Effective Java -- 避免创建不必要的对象

此系列文章为本人对《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;
}

总结

多注意可重用对象,可以用旧对象的情况下,就别随意找新欢了。

水平有限,若文章中存在错误,恳请不吝赐教,这对我以及后面的读者都有重要意义;
若文章能够帮助到你,还望一键三连,感谢支持。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值