第一第二回讲的主要是集合类的一些最常用的工具. 其实com.google.common.collect里还有很多非常有用的工具, 比如 Ordering, ComparisonChain, Iterables, Multiset, Multimap等等. 这里有些我们后面还会涉及.
小兄弟正在做socket客户服务器通信相关的课程设计, 所以我有点迫不及待先讲讲common.io这个包了. 这里面最有用的, 在我看来, 就是 CharStreams和 ByteStreams这两个工具.
大家知道, Java里读外设主要是跟InputStream和Reader打交道. 其中InputStream用来读取原始的字节流, 而Reader是在你已经知道了输入是用什么字符集编码的情况下读取字符串.
但是这两个类还是相对底层了一些. 在做一些很灵活复杂的事情的时候是必要的, 甚至我们还需要抬出nio这个大杀器. 可它们对日常工作中一些简单的事情, 就有炮弹打蚊子的感觉.
比如, 我需要从一个Reader里一行一行读出所有文本. 直接用Reader的话, 你需要弄一个BufferedReader, 然后循环调用readLine(), 直到全部读完. 类似这样:
BufferedReader buffered = new BufferedReader(reader); Listlines = new ArrayList (); for (;;) { String line = buffered.readLine(); if (line == null) { break; } lines.add(line); }
用CharStreams的话, 一句话就搞定了:
Listlines = CharStreams.readLines(reader);
如果你还是需要类似于流一样的操作-比如, 输入的行数太多, 不能一下子都读进来, 那么, 还有一个 LineReader可以用. 用起来类似于:
LineReader lineReader = new LineReader(reader); for (String line = lineReader.readLine(); line != null; line = lineReader.readLine()) { System.out.println(line); }
其它的one-liner, 包括:
从一个Readable读取所有东西写到一个Appendable里去:
CharStreams.copy(reader, writer);
从Readable读取所有内容到一个字符串:
String content = CharStreams.toString(reader);
另外, 写io程序一个最常见的bug, 就是打开东西忘记关了. 或者关的不彻底. 一般来说, 你要开一个InputStream, 肯定要接下来用一个try-finally, 在用完之后调用close()把它关上. OutputStream, Reader, Writer同理.
但是这很麻烦, 而且容易忘. 在java7的 自动资源管理出来之前, 可以用common.io包定义的InputSupplier, OutputSupplier接口.
原理是, 你实现一个InputSupplier对象, 把"怎样打开这个InputStream/Reader"的逻辑封装在getInput()它的函数里, 然后, 把它传递给CharStreams, ByteStreams相关的API, 比如readLines(), copy()等, 这些API调用你的supplier, 然后做事, 做完之后它把自己屁股擦干净, 把它打开的InputSteam/Reader再关上.
ByteStreams很类似, 不过它是工作在字节流上, 而不关心字符编码问题.
对应于CharStreams.toString(), 是
byte[] content = ByteStreams.toByteArray(inputStream)
用来把整个InputStream的内容全部一次性读到一个byte[]里面.
对应于CharStreams.copy(), 是
ByteStreams.copy(inputStream, outputStream);
用来把所有内容从一个InputStream拷贝到另一个OutputStream.
嗯. 以上.