遍历集合的方法总结
1.List
- 普通for循环
List<String> list = new ArrayList<>();
//...
for (int i = 0; i < list.size(); ++i) {
String s = list.get(i);
}
- 增强for循环
List<String> list = new ArrayList<>();
//...
for (String s : list) {
System.out.println(s);
}
- Iterator迭代器 + for循环
List<String> list = new ArrayList<>();
//...
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
}
- Iterator迭代器 + while循环
List<String> list = new ArrayList<>();
//...
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
}
2.Set
- 增强for循环
Set<String> set = new HashSet<>();
//...
for (String s : set) {
System.out.println(s);
}
- Iterator迭代器
Set<String> set = new HashSet<>();
//...
for (Iterator<String> it = set.iterator(); it.hasNext(); ) {
String s = it.next();
}
3.Map
- 根据key获取value
Map<String, Integer> map = new HashMap<>();
//...
Set<String> set = map.keySet();
for (String s : set) {
Integer i = map.get(s);
}
- 使用entrySet
Map<String, Integer> map = new HashMap<>();
//...
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String s = entry.getKey();
Integer i = entry.getValue();
}
IO流
四大IO抽象类
InputStream/OutputStream和Reader/writer类是所有IO流类的抽象父类。
- InputStream
此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。 数据的读取需要由它的子类来实现。继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit)。
常用方法:
int read():读取一个字节的数据,并将字节的值作为int类型返回(0-255之间的一个值)。如果未读出字节则返回-1(返回值为-1表示读取结束)。
void close():关闭输入流对象,释放相关系统资源。
- OutputStream
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
常用方法:
void write(int n):向目的地中写入一个字节。
void close():关闭输出流对象,释放相关系统资源。
- Reader
Reader用于读取的字符流抽象类,数据单位为字符。
int read(): 读取一个字符的数据,并将字符的值作为int类型返回(0-65535之间的一个值,即Unicode值)。如果未读出字符则返回-1(返回值为-1表示读取结束)。
void close() : 关闭流对象,释放相关系统资源。
- Writer
Writer用于写入的字符流抽象类,数据单位为字符。
void write(int n): 向输出流中写入一个字符。
void close() : 关闭输出流对象,释放相关系统资源。
文件字节流
- FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。
- FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。
- Java也提供了FileReader专门读取文本文件。
- Java也提供了FileWriter专门写入文本文件。
利用文件流实现文件的复制
public class Test {
public static void main(String[] args) {
String in = "C:\\Users\\whatsoooever\\Desktop\\a.txt";
String out = "C:\\Users\\whatsoooever\\Desktop\\b.txt";
copy(in,out);
}
static void copy(String in,String out) {
FileInputStream fis = null;
FileOutputStream fos = null;
//为了提高效率,设置缓存数组!(读取的字节数据会暂存放到该字节数组中)
byte[] buffer = new byte[1024];
int temp = 0;
try {
fis = new FileInputStream(in);
fos = new FileOutputStream(out);
//边读边写
//temp指的是本次读取的真实长度,temp等于-1时表示读取结束
while ((temp = fis.read(buffer)) != -1) {
/*将缓存数组中的数据写入文件中,注意:写入的是读取的真实长度;
*如果使用fos.write(buffer)方法,那么写入的长度将会是1024,即缓存
*数组的长度*/
fos.write(buffer,0,temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件字符流
文件字节流可以处理所有的文件,但是字节流不能很好的处理Unicode字符,经常会出现“乱码”现象。所以,我们处理文本文件,一般可以使用文件字符流,它以字符为单位进行操作。
利用文件流实现文件的复制
public class Test {
public static void main(String[] args) {
String in = "C:\\Users\\whatsoooever\\Desktop\\a.txt";
String out = "C:\\Users\\whatsoooever\\Desktop\\b.txt";
copy(in,out);
}
static void copy(String in,String out) {
FileReader fr = null;
FileWriter fw = null;
//注意这里是char数组
char[] buffer = new char[1024];
int len = 0;
try {
fr = new FileReader(in);
fw = new FileWriter(out);
while ((len = fr.read(buffer)) != -1) {
fw.write(buffer,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fr != null) {
fr.close();
}
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲字节流
Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。
当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。
因此,缓冲流还是很重要的,我们在IO操作时记得加上缓冲流来提升性能。
BufferedInputStream和BufferedOutputStream这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。
使用缓冲流实现文件的高效率复制
public class Test {
public static void main(String[] args) {
String in = "C:\\Users\\whatsoooever\\Desktop\\a.txt";
String out = "C:\\Users\\whatsoooever\\Desktop\\b.txt";
copy(in, out);
}
static void copy(String in, String out) {
FileInputStream fis = null;
BufferedInputStream bis = null;
//使用缓冲字节流包装文件字节流,增加缓冲功能,提高效率
//缓存区的大小(缓存数组的长度)默认是8192,也可以自己指定大小
FileOutputStream fos = null;
BufferedOutputStream bos = null;
int len = 0;
try {
fis = new FileInputStream(in);
fos = new FileOutputStream(out);
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
while ((len = bis.read()) != -1) {
bos.write(len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//注意:增加处理流后,注意流的关闭顺序!“后开的先关闭!”
try {
if (bos != null) {
bos.close();
}
if (bis != null) {
bis.close();
}
if (fos != null) {
fos.close();
}
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意:
- 在关闭流时,应该先关闭最外层的包装流,即“后开的先关闭”。
- 缓存区的大小默认是8192字节,也可以使用其它的构造方法自己指定大小。
缓冲字符流
BufferedReader/BufferedWriter增加了缓存机制,大大提高了读写文本文件的效率,同时,提供了更方便的按行读取的方法:readLine(); 处理文本时,我们一般可以使用缓冲字符流。
使用BufferedReader与BufferedWriter实现文本文件的复制
public class Test {
public static void main(String[] args) {
String in = "C:\\Users\\whatsoooever\\Desktop\\a.txt";
String out = "C:\\Users\\whatsoooever\\Desktop\\b.txt";
copy(in, out);
}
static void copy(String in, String out) {
// 注:处理文本文件时,实际开发中可以用如下写法,简单高效!!
FileReader fr = null;
FileWriter fw = null;
BufferedReader br = null;
BufferedWriter bw = null;
String temp = "";
try {
fr = new FileReader(in);
fw = new FileWriter(out);
br = new BufferedReader(fr);
bw = new BufferedWriter(fw);
//br.readLine()方法的返回值是一个字符串对象,即文本中的一行内容
while ((temp = br.readLine()) != null) {
//将读取的一行字符串写入文件中
bw.write(temp);
//下次写入之前先换行,否则会在上一行后边继续追加,而不是另起一行
bw.newLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
if (br != null) {
br.close();
}
if (fw != null) {
fw.close();
}
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意:
- readLine()方法是BufferedReader特有的方法,可以对文本文件进行更加方便的读取操作。
- 写入一行后要记得使用newLine()方法换行。
对象流
当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过http协议发送字符串信息;我们也可以在网络上直接发送Java对象。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常读取。
把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。
对象序列化的作用有如下两种:
- 持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中,比如:休眠的实现。以后服务器session管理,hibernate将对象持久化实现。
- 网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。
注意点:
- ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
- ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
- 只有实现了Serializable接口的类的对象才能被序列化。 Serializable接口是一个空接口,只起到标记作用。
- static属性不参与序列化。
- 对象中的某些属性如果不想被序列化,不能使用static,而是使用transient修饰。
- 为了防止读和写的序列化ID不一致,一般指定一个固定的序列化ID。
将Person类的实例进行序列化和反序列化
//Person类实现Serializable接口后,Person对象才能被序列化
class Person implements Serializable {
// 添加序列化ID,它决定着是否能够成功反序列化!
private static final long serialVersionUID = 1L;
String name;
int age;
boolean isMen;
Person(String name, int age, boolean isMen) {
this.name = name;
this.age = age;
this.isMen = isMen;
}
@Override
public String toString() {
return "name:" + this.name + ",age:" + this.age + ",isMen:" + this.isMen;
}
}
public class Test {
public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
Person person = new Person("whatsoooever", 24, false);
// 通过ObjectOutputStream将Person对象的数据写入到文件中,即序列化。
try {
fos = new FileOutputStream("C:\\Users\\whatsoooever\\Desktop\\a.txt");
oos = new ObjectOutputStream(fos);
oos.writeObject(person);
oos.flush();
//反序列化
fis = new FileInputStream("C:\\Users\\whatsoooever\\Desktop\\a.txt");
ois = new ObjectInputStream(fis);
Person p = (Person) ois.readObject();
System.out.println(p);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
if (ois != null) {
ois.close();
}
if (fos != null) {
fos.close();
}
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
装饰器模式
IO流体系中大量使用了装饰器模式,让流具有更强的功能、更强的灵活性。比如:
FileInputStream fis = new FileInputStream(src);
BufferedInputStream bis = new BufferedInputStream(fis);
显然BufferedInputStream装饰了原有的FileInputStream,让普通的FileInputStream也具备了缓存功能,提高了效率。