一、引子
一般来说,最好能重用对象而不是每次需要的时候就创建一个相同功能的新对象,特别是当对象不可变时,它始终可以被重用的。重用对象对程序性能起到重要作用。
二、重用不可变对象
对于同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。
Boolean b1 = Boolean.valueOf("test"); // 使用静态工厂方法(good)
Boolean b2 = new Boolean("test"); // 使用构造器(bad)
三、重用不会被修改的可变对象
下面的例子业务为:检验某个人是否出生于1946年 ~ 1964年期间。
/*
* 改进前
*/
public class Person {
private Date birthDate = new Date();
public boolean isBabyBoomer() {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
calendar.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = calendar.getTime();
calendar.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = calendar.getTime();
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
}
/*
* 改进后
*/
public class Person2 {
private Date birthDate = new Date();
private static Date BOOM_START;
private static Date BOOM_END;
static {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
calendar.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = calendar.getTime();
calendar.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = calendar.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
}
}
改进前每调用一次isBabyBoomer都会创建一个Calendar,TimeZone,Date对象,改进后的程序只会在初始化的时候创建这些对象一次。如果isBabyBoomer方法被频繁的调用,那么将会显著地提高性能。
四、自动装箱和拆箱
看一下下面这个小程序,不知道你能不能发现什么问题?
public class Client {
public static void main(String[] args) {
long start = System.currentTimeMillis();
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println(">>>>>>>>>>Total spent time: " + (end - start) / 1000 + "s");
}
}
因为sum定义为Long类型,导致这个程序创建了很多不必要的对象,每次往Long sum中增加long i 时都会构建一个实例。
结论:要优先使用基本数据类型而不是装箱基本类型,要当心无意识的自动装箱。
分享到:
相关推荐
这可以减少实例化的次数,避免创建不必要的重复对象。 - 静态工厂方法可以返回任何子类型的对象,提供更大的灵活性。API可以返回对象而无需公开实现类,从而保持接口的简洁性。 - 在Java 8之前,接口不能有静态方法...
6. **避免创建不必要的对象**:对象创建是有代价的,重复创建相同的对象可能导致性能问题,应尽量复用或使用不可变对象。 7. **避免使用终结方法(finalizers)和清理器(cleaners)**:这些机制不可靠且执行时间不...
java7 hashmap源码 Effective Java 3th 索引 创建和销毁对象 考虑使用静态工厂方法代替构造方法 优点: 有名字 每次调用的时候,不一定要创建新的...避免创建不必要的对象 用 String str = "abcd";而不是String str= n
**避免创建不必要的对象**: 1. **不可变对象**:对于不可变对象,可以通过缓存已创建的对象来避免重复创建。 2. **使用静态工厂方法**:如果一个类既提供了静态工厂方法也提供了构造器,则通常推荐使用静态工厂...
- 避免不必要的对象创建,尤其是String对象,注意字符串连接的效率问题。 - 使用StringBuilder代替String的+操作进行字符串拼接。 - 利用局部变量缓存常量,避免频繁的属性访问。 8. 错误处理 - 不要忽视异常,...
- **避免在循环体中创建对象**:循环内的对象创建可能会导致不必要的性能开销。 - **了解JVM内存模型**:理解堆、栈、方法区等概念,有助于进行性能调优。 - **使用StringBuilder(或StringBuffer)**:在构建...
- **避免对对象的不必要的复制**:了解如何最小化对象复制,例如通过使用`System.arraycopy()`或`Arrays.copyOf()`。 - **正确使用equals()和hashCode()**:理解这两者的性能影响,特别是在集合类中。 9. **最后...
11. **优先使用Arrays.asList()而不是new ArrayList()**:前者将数组转换为列表,而后者创建了一个新的列表,前者更高效且避免了创建不必要的对象。 12. **使用迭代器而非for-each循环遍历集合**:两者都能遍历集合...
避免不必要的对象创建 德玛 项目7 释放使用的对象参考 莉娜 项目8 避免使用终结剂和清洁剂 莉娜 项目9 使用try-with-resources而不是try-finally 林 第三章所有对象的通用方法 项目编号 标题 副标题 经理 项目...
11. **使用`String`构造函数创建字符串,而不是`new String()`(Item 11)**:直接使用`String`构造函数更高效,因为字符串是不可变的,避免了不必要的内存分配。 12. **避免在循环中使用`System.arraycopy()`...
- 保持代码简洁,避免不必要的复杂度。 - 编写可测试的代码。 #### 四、代码示例 **Example.java** ```java package com.example; public class Example { private String message; public Example(String ...
4. **优先考虑静态工厂方法而非构造器**: 静态工厂方法有多个优势,例如可以有选择性地返回子类实例、不需暴露构造器、在无参数情况下避免创建不必要的对象等。 5. **使用不可变对象**: 不可变对象一旦创建完成,其...
了解`Long`和`Integer`的缓存机制可以帮助避免不必要的对象创建,提高性能。 #### 五、总结 在Java开发中,正确地比较`Long`和`Integer`对象是非常重要的。直接使用`==`可能会导致意料之外的结果。通过使用`equals...
- **项02:避免创建不必要的对象**:过度创建对象会增加内存负担,应该尽可能重用现有对象或采用更高效的替代方案。 - **项03:覆盖equals时请遵守通用约定**:正确的equals方法实现对于确保对象一致性至关重要。 #...
21. 避免创建不必要的对象。 22. 使用System.arraycopy()方法复制数组。 23. 对于可序列化类,明确指定serialVersionUID。 以上就是基于“Java学习总结(2023/03/19)”的主题,结合《Effective Java》一书,对Java...
##### Item4:避免创建重复的对象 - **目的**:减少内存占用,提高性能。 - **实现方式**: - 使用缓存机制存储已创建的对象实例。 - 当请求新对象时,首先检查缓存中是否已经存在相同属性的对象。 ##### Item5:...
饿汉式在类加载时就完成了实例化,确保了线程安全,但可能会造成不必要的内存浪费。`SingleInstance2.java`可能就使用了这种模式。代码中单例对象在类加载时即被创建。 ```java public class SingleInstance2 { ...