我曾经接手过一个工程, 里面有一段让我头晕目眩的代码, 展示如下:
- String str1 = "";
- for (int i = 0; i < list.size(); i++) {
- str1 += list.get(i);
- if (i < list.size() - 1) {
- str1 += ",";
- }
- }
这段代码大概就是想要拼成一个很长很长的 String 罢了, 看起来逻辑也很简单, 还用上了 foreach, 但是我还是要说让我头晕目眩, 原因就在于 String 是一个不可变类.
我们来看看 String 的源码就知道了什么叫做不可变类:
String
这种类有一个典型的特点就是不可继承, 对于 String 的任何拼接操作, 实际上都是在新建对象, 上面这段代码实际上就创建了 list.size()+1 个 String 对象.
那么这就是一段很不优雅的代码了, 至少一个资深的程序员永远不会在循环中做 String 的拼接的. 这其实也就是《Effective Java》这本书的第六条提到的所谓 "避免创建不必要的对象" 了.
这一条里举了一个类似的例子:
- //String 是不可变类, XXX 实际上已经创建好了一个对象, 此时 new 只会再次创建一个对象
- // 不可变类可以被复用
- String str = new String("XXX");
这个时候可以用 StringBuilder 了, 如下代码片段:
- StringBuilder stringBuilder = new StringBuilder();
- for (int i = 0; i < list.size(); i++) {
- stringBuilder.append(list.get(i));
- if (i < list.size()-1) {
- stringBuilder.append(",");
- }
- }
- // 这是最讨厌的一步, 需要把 StringBuilder 转成 String 才能继续使用
- String s = stringBuilder.toString();
上面这段代码还是不美好, 因为额外生成了一个 StringBuilder 对象, 这不是我想要的, 这也算是额外的对象了.
这时要是有个静态工厂方法就好了. 还好这世界还有 Google, 提供的 Guava 里面就有很多很好的工具:
String str = Joiner.on(",").join(list);
这就好了, 不会生成额外的对象.
这只是一个小例子, 也许读到这里的人会说, 现在的计算机硬件已经很强大了, 多核 CPU, 大内存, SSD 硬盘, 根本不在于这点细枝末节的提升. 那么这个时候就应该好好看看数据库连接池的设计了.
我们知道, 数据库建链的过程实际上是一次 TCP 建链的过程, 包括了经典的三次握手协议, 在《码农翻身》这本书里作者也风趣讲了这个协议是多么的让人崩溃, 但是为了数据库连接的稳定可靠, 必须这么做. 这也就意味着数据库建链的过程是一个昂贵的操作, 因此, 避免每次连接的时候都去新建一个链接是必要的, 也就是说我们需要把建立好的连接对象放在一个容器里保存起来, 这就是避免创建不必要的对象的思想了.
注意, 绝对不是说尽量不要创建对象, 不管到什么时候, 一定要强调所谓不必要的这个概念.
我记得我上学的时候面向对象这门课的老师讲 Java 的时候说过, Java 程序员掌握越多的类库, 那么他的编程能力越强大. 这句话部分对, 因为有的时候, 你看着 Guava 用起来爽, 但是没有思考为什么爽, 为什么 Google 要做这么一件事情, 那你也不过是掌握了这个类库怎么用而已.
正所谓学而不思则罔.
来源: http://www.jianshu.com/p/4207dbfa84b0