此系列文章为本人对《Effective Java》一书的学习笔记,主要是记录对书中重点内容的理解。
既然有缘看到此文,那么希望能对你有所帮助。
本文对应原书第6条 避免创建不必要的对象
一般来说,最好能重用单个对象,毕竟它快速又简洁,而不是每次要用的时候,都new一个功能相同的对象。
另一方面,如果对象是不可变的(immutable
),它就始终可以被重用。
来看几个例子:
例1 - - 无意义的创建新对象
String s = new String("hello world");
这是一个反例,这样的语句每次执行都会新建一个String
的实例,而这种实例毫无意义。
首先,作为参数被传进去的字符串"hello world"
本来就已经是一个String的实例,它已经存在与字符串常量池中,这个语句执行的时候,还会再开辟一个空间给String
实例,然后这个实例还会指向那个常量池中的"hello world"
,画蛇添足,妥妥的了。
例2 - - 未使用现成的对象
String s = "xxx";
Boolean flag = new Boolean(s);
这个反例在IDE敲出来之后,会温馨的给报一个警告,并且温馨地提供simplify
的办法,主动帮你替换为
String s = "xxx";
Boolean flag = Boolean.valueOf(s);
翻看其源码,其实都调用了parseBoolean
方法,只不过前者多new了一个新对象,后者则是使用了可重用的 static final
对象。
但是不用担心,前者以后应该不会再出现了,因为Java 9
开始,它已被废弃。
例3 - - 隐蔽的对象创建
public static boolean matches(String s) {
return s.matches("^规则$");
}
这代码乍一看好像没啥毛病,但被前辈发现一定会骂你一通,打开源码:
public static boolean matches(String regex, CharSequence input) {
// 会new出一个Pattern
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}
原来如此,这个反例表面上只是用了一个固定的字符串,一脸无辜,但背地里每次调用都会多new
一次Pattern
,真是不可貌相。
所以该怎么写呢,很简单,把Pattern
准备好,不就OK了么:
private static final Pattern PATTERN = Pattern.compile("^规则$");
public static boolean matches(String s) {
return PATTERN.matcher(s).matches();
}
例4 - - 自动拆装箱
public static long sum() {
Long sum = 0L;
for(long i = 0; i < Integer.MAX_VALUE; i++){
sum += i;
}
return sum;
}
同样,乍一看没啥毛病,但实质上这段代码制造了约231个多余的Long
实例,仅仅是因为sum被声明时使用了Long
而不是long
,效率不必多言,肯定弱爆了,真是作孽啊。
所以这一条的结论很明显:
要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
例5 - - 数据库连接池问题
我们以上讨论的都是在自己系统内部搞来搞去,数据库连接池就不一样了,由于涉及网络连接,并且受限于数据库的种种限制(连接数量),建立数据库的连接代价是非常昂贵的,相比之下你偷偷new一个对象根本不算什么。
所以,如果你胆敢写出以下代码,小心饭碗不保:
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName("xxx.Driver");
conn = DriverManager.getConnection("url", "user", "password");
} catch (SQLException e) { ... }
return conn;
}
好了,每次都搞一个新的Connection
,收获了这么多的Connection
,也应该知足的告老还乡了。
赶紧改一下代码或许还能有一线生机:
private static Connection conn;
static {
try {
Class.forName("xxx.Driver");
conn = DriverManager.getConnection("url", "user", "password");
} catch (SQLException e) { ... }
}
public static Connection getConnection() {
return conn;
}
总结
多注意可重用对象,可以用旧对象的情况下,就别随意找新欢了。
水平有限,若文章中存在错误,恳请不吝赐教,这对我以及后面的读者都有重要意义;
若文章能够帮助到你,还望一键三连,感谢支持。