40岁开始学Java:避免创建不必要的对象
在Java中避免创建不必要的对象可以通过以下几种方法实现,从而提升性能和减少内存消耗:
1. 重用不可变对象
- 字符串常量池:使用字面量而非
new String
,例如String s = "hello"
,复用常量池中的对象。 - 静态工厂方法:如
Integer.valueOf()
会缓存-128到127的实例,优先于new Integer()
。 - 预编译高开销对象:如正则表达式
Pattern
,避免在循环中重复编译:public class RegexExample { private static final Pattern PATTERN = Pattern.compile("regex"); public static boolean validate(String input) { return PATTERN.matcher(input).matches(); } }
2. 避免自动装箱
- 使用基本类型(
int
而非Integer
),尤其在循环中:long sum = 0L; // 使用基本类型long,避免Long自动装箱 for (long i = 0; i < 10000; i++) { sum += i; }
3. 缓存频繁使用的对象
- 静态初始化:将高成本对象在类加载时初始化并缓存:
public class Person { private static final Date BOOM_START; static { Calendar cal = Calendar.getInstance(); cal.set(1946, Calendar.JANUARY, 1); BOOM_START = cal.getTime(); } // 复用BOOM_START }
4. 对象池与享元模式
- 对重量级对象(如数据库连接)使用池化技术(如Apache Commons Pool)。
- 享元模式共享无状态对象,如适配器或常量对象。
5. 避免在循环内创建对象
- 将对象创建移至循环外,并重置状态(注意线程安全):
Calendar cal = Calendar.getInstance(); for (int i = 0; i < 100000; i++) { cal.setTime(date); // 复用Calendar实例 // 处理逻辑 }
6. 处理线程安全问题
- 使用
ThreadLocal
保存线程专有对象,避免重复创建:public class DateUtil { private static final ThreadLocal<SimpleDateFormat> formatCache = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd")); public static String format(Date date) { return formatCache.get().format(date); } }
7. 优化集合与工具类
- 使用不可变视图(如
Collections.unmodifiableList
)避免拷贝。 - 复用缓冲区数组,例如在I/O操作中重复使用字节数组。
总结
- 关键点:识别可复用的对象,尤其是初始化成本高或频繁使用的不可变对象。
- 权衡:避免过度优化轻量级对象,对象池适用于高成本资源。
- 注意事项:确保线程安全,合理使用缓存和静态工厂方法。
通过这些策略,可以有效减少不必要的对象创建,优化程序性能。