《Effective Java》第5条:避免创建不必要的对象
原文地址: itweknow.cn/detail?id=6… ,欢迎大家访问。
当一个对象能够被重用的时候,就不要去创建新对象。我们先来考虑一个比较简单的例子
String s = new String("stringette");
复制代码
这个语句在每次被调用的时候都会创建一个全新的String
实例,而且参数stringette
自身也是一个String实例。所以一般建议使用下面的方式来申明一个String
String s = "stringette";
复制代码
下面通过几个例子来说明一下为啥需要避免创建不必要的对象。
例一
我们有一个Person
类,并且类里面有一个isBabyBoomer
方法,用来校验这个人是否在生育高峰期出生(生育高峰期为1946年至1964年),可能我们通常的写法是
public class Person {private final Date birthDate;public Person(Date birthDate) {this.birthDate = birthDate;}public boolean isBabyBoomer() {Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));// 高峰期开始时间。calendar.set(1946, Calendar.JANUARY, 1,0, 0, 0);Date start = calendar.getTime();// 高峰期结束时间。calendar.set(1965, Calendar.JANUARY, 1,0, 0, 0);Date end = calendar.getTime();// 比较。return birthDate.compareTo(start) >=0 &&birthDate.compareTo(end) < 0;}
}
复制代码
我们来试一下调用一千万次这个方法所消耗的时间。
public class Test01 {public static void main(String[] args) {long start = System.currentTimeMillis();Person person = new Person(new Date());for (int i=0; i<10000000; i++) {person.isBabyBoomer();}long end = System.currentTimeMillis();System.out.println("消耗时间:" + (end - start) + "ms");}
}
复制代码
在我的电脑上耗时在3200ms
左右,下面我们做一下修改,将生育高峰期的开始和结束时间抽出来作为Person
类的属性,并且在静态代码块中进行赋值。
public class Person {private final Date birthDate;private static final Date startDate;private static final Date endDate;static {Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));// 高峰期开始时间。calendar.set(1946, Calendar.JANUARY, 1,0, 0, 0);startDate = calendar.getTime();// 高峰期结束时间。calendar.set(1965, Calendar.JANUARY, 1,0, 0, 0);endDate = calendar.getTime();}public Person(Date birthDate) {this.birthDate = birthDate;}public boolean isBabyBoomer2() {// 比较。return birthDate.compareTo(startDate) >=0 &&birthDate.compareTo(endDate) < 0; }
}
复制代码
再次测试发现消耗时间大概在20ms
左右,效率提高了差不多150倍。
例二
我们知道在Java
中字符串如果使用+
进行拼接的时候会创建新的String实例,而使用StringBuilder.append()
方法则不会创建新的实例。下面我们分别用两种方式进行十万次的字符串拼接。
public class Test02 {public static void main(String[] args) {method01();method02();}public static void method01() {long start = System.currentTimeMillis();String a = "";for (int i=0; i<100000; i++) {a += "a";}long end = System.currentTimeMillis();System.out.println("method01 used time:" + (end - start) + "ms");}public static void method02() {long start = System.currentTimeMillis();StringBuilder a = new StringBuilder("");for (int i=0; i<100000; i++) {a.append("a");}long end = System.currentTimeMillis();System.out.println("method01 used time:" + (end - start) + "ms");}
}
复制代码
结果如下:
method01 used time:3591ms
method01 used time:2ms
复制代码
例三
这个例子我们直接上代码,区别很微小,就是在定义sum
的时候method01
使用了包装类型,method02
则使用了基本类型。例子实现的是求所有int
正值的和。
public class Test03 {public static void main(String[] args) {method01();method02();}public static void method01() {long start = System.currentTimeMillis();Long sum = 0L;for (long i=0; i< Integer.MAX_VALUE; i++) {sum += i;}System.out.println(sum);long end = System.currentTimeMillis();System.out.println("method1 time used:" + (end - start) + "ms");}public static void method02() {long start = System.currentTimeMillis();long sum = 0L;for (long i=0; i< Integer.MAX_VALUE; i++) {sum += i;}System.out.println(sum);long end = System.currentTimeMillis();System.out.println("method2 time used:" + (end - start) + "ms");}
}
复制代码
得到的结果是:
2305843005992468481
method1 time used:6170ms
2305843005992468481
method2 time used:633ms
复制代码
可以看到细微的区别结果的差距还是蛮大的,所以我们要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
最终我们得到的结论是当你应该重用现有对象时,请不要创建新的对象
。
《Effective Java》第5条:避免创建不必要的对象相关推荐
- Effective Java学习笔记之第5条 避免创建不必要的对象
第5条 避免创建不必要的对象 一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的对象. 反面例子: String s = new String("stringette&quo ...
- 反射创建对象_如何应用Java反射技术灵活地创建程序类的对象实例
软件项目实训及课程设计指导--如何应用Java反射技术灵活地创建程序类的对象实例 1.如何应用属性配置文件实现对系统中的配置信息进行读写操作 Java中的属性配置文件主要可以作为软件应用系统及项目的配 ...
- Effective Java读书笔记三:创建和销毁对象
第1条:考虑用静态工厂方法代替构造器 对于类而言,为了让客服端获得它的一个实例最常用的的一个方法就是提供一个公有的构造器.还有一种方法,类可以提供一个公有的静态工厂方法(static factory ...
- 《Effective Java》 第一讲:创建和销毁对象
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 一.用静态工厂方法代替构造器 用静态工厂的优点 : 1. 方法有名字,更好理解. 2.不必每次调用的 ...
- Effective Java读书笔记---二、创建和销毁对象
二.创建和销毁对象 何时以及如何创建对象, 何时以及如何避免创建对象, 如何确保它们能够适时地销毁, 如何管理对象销毁之前必须进行的各种清理动作 1.用静态工厂方法代替构造器 优势: 它们有名称 不必 ...
- Effective.Java第23-33条(泛型相关)
23. 类结构层次优于标签类 有时你会碰到一个类,它的实例有一个或多个风格,并且包含一个tag属性表示实例的风格.例如,如下面的类表示一个圆或者矩形: public class Figure {/* ...
- Effective Java第七条:避免使用终结方法
第七条:避免使用终结方法 1, 终结方法(finalizer)会让程序不稳定,性能降低,出现可移植性的问题. 2, Finalizer在c++中师析构器(destructors)的一部分,用作回收 ...
- effective java 第2条:遇到多个构造器参数时要考虑用构造器
如果构建一个对象需要很多参数时,那么有三种方式可以实现. 第一种就是多重构造器 public class Person {private final int id; //requiredprivate ...
- effective java第45条:将局部变量的作用域最小化
我以前写for循环的例子: public class Client {public static void main(String[] args) {Client client = new Clien ...
- 创建时间指定日期 java,Java避坑之如何创建指定时间Date对象
在翻看自己以前写的惨不忍睹的代码时,发现了自己曾经写的一个跟Date有关的坑.Date date = new Date(2020, 1, 1); System.out.println(date); 我 ...
最新文章
- Part2_4 Sqlite基础操作
- PMCAFF | 产品经理挑战赛,等你来战
- 使用python实现人脸检测转载
- java爬虫怎么确定url连接_Java爬虫之抓取一个网站上的全部链接
- P1136 迎接仪式
- 嵌入式根文件系统制作
- Threading in C#
- 手把手教你D2C,走向前端智能化
- rocketmq 几种队列_关于RocketMQ的知识
- LQR轨迹跟踪算法Python/Matlab算法实现2
- 10亿个数中求最大的10个数字
- CIO关注:数字化转型带来的IT版图巨变正在成为新的挑战
- java 什么是精度_Java中BigDecimal精度和相等比较的坑
- 婚恋职场人格-张晓文-武汉理工大学-中国MOOC-亲密关系测试题参考答案
- Linux 下载安装maven
- arma模型 java_ARMA模型与ARIMA模型java实现例程
- 单片机74LS164C语言例子,51单片机控制74LS164芯片输出64位的数组
- 金蝶k3服务器重装账套怎么恢复,金蝶KIS旗舰版、金蝶K3账套备份、恢复操作教程...
- 陌陌也出了网页版,醉翁之意不在酒在直播
- ArcGIS Runtime API for Android100.13.0加载TPK包、Runtime包、WMS地图服务、三维模式
热门文章
- Django中ORM模型总结(二)[抽象模型类,模型类的对应关系,模型类的属性,字段类型]...
- C# IEnumerator与 IEnumerable(2) 托管使用
- Date类的getYear(),getMonth过时,现在的获取方法
- Python云端系统开发入门 pycharm代码
- BZOJ1396: 识别子串(后缀自动机,线段树)
- PAT——1054. 求平均值
- 集成CCFlow工作流与GPM的办公系统驰骋CCOA介绍(一)
- 数据库之“on”“where”区别
- Updatepanel jquery 失效解决方案
- 转 - 受益终生的十大经典管理学定律