上一篇里对几种书写方式进行了简单的测试,得出了一些初步的结论。这次简单了解Lambda原理后,对测试做了一些调整,发现得到不一样的结果,而这个调整,明显更契合实际开发的场景。

暂时还没有亲自去验证,主要是从博客中了解的Lambda原理,引起一些启发,对测试代码进行了一些改善。

在此感谢这篇博客的作者:https://www.cnblogs.com/UncleWang001/p/10020611.html - lambda表达式底层处理机制

调整后的代码:

  1 package com.supalle.test;
2
3 import lombok.AllArgsConstructor;
4 import lombok.Builder;
5 import lombok.Data;
6 import lombok.NoArgsConstructor;
7
8 import java.lang.reflect.Constructor;
9 import java.lang.reflect.InvocationTargetException;
10 import java.util.function.Supplier;
11
12 /**
13 * @描述:语法PK
14 * @作者:Supalle
15 * @时间:2019/7/26
16 */
17 public class SyntaxPKTest {
18
19
20 /* 循环次数 */
21 private final static int SIZE = 100000000;
22
23 /* 有类如下 */
24 @Data
25 @Builder
26 @NoArgsConstructor
27 @AllArgsConstructor
28 private static class Man {
29 private String name;
30 private int age;
31 }
32
33
34 /**
35 * 使用 new Man();
36 *
37 * @return 运行耗时
38 */
39 public static long runWithNewConstructor() {
40 long start = System.currentTimeMillis();
41
42 for (int i = 0; i < SIZE; i++) {
43 new SyntaxPKTest.Man();
44 }
45
46 return System.currentTimeMillis() - start;
47 }
48
49 /**
50 * 使用反射
51 *
52 * @return 运行耗时
53 */
54 public static long runWithReflex() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
55 Constructor<SyntaxPKTest.Man> constructor = SyntaxPKTest.Man.class.getConstructor();
56 long start = System.currentTimeMillis();
57
58 for (int i = 0; i < SIZE; i++) {
59 constructor.newInstance();
60 }
61
62 return System.currentTimeMillis() - start;
63 }
64
65 /**
66 * 使用内部类调用 new Man();
67 *
68 * @return 运行耗时
69 */
70 public static long runWithSubClass() {
71 long start = System.currentTimeMillis();
72
73 Supplier<Man> supplier = new Supplier<Man>() {
74 @Override
75 public Man get() {
76 return new Man();
77 }
78 };
79 for (int i = 0; i < SIZE; i++) {
80 supplier.get();
81
82 }
83
84 return System.currentTimeMillis() - start;
85 }
86
87 /**
88 * 使用Lambda调用 new Man();
89 *
90 * @return 运行耗时
91 */
92 public static long runWithLambda() {
93 long start = System.currentTimeMillis();
94
95 Supplier<Man> supplier = () -> new Man();
96
97 for (int i = 0; i < SIZE; i++) {
98 supplier.get();
99 }
100
101 return System.currentTimeMillis() - start;
102 }
103
104
105 /**
106 * 使用 MethodReference
107 *
108 * @return 运行耗时
109 */
110 public static long runWithMethodReference() {
111 long start = System.currentTimeMillis();
112
113 Supplier<Man> supplier = Man::new;
114
115 for (int i = 0; i < SIZE; i++) {
116 supplier.get();
117 }
118
119 return System.currentTimeMillis() - start;
120 }
121
122 public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
123
124 // 测试前调用一下,加载Man字节码,尽量公平
125 SyntaxPKTest.Man man1 = new SyntaxPKTest.Man();
126 SyntaxPKTest.Man man2 = new SyntaxPKTest.Man("张三", 20);
127
128 System.out.println("测试环境:CPU核心数 - " + Runtime.getRuntime().availableProcessors());
129
130 System.out.println();
131
132 // 这里的话对比再次调用的时间
133 System.out.println("首次使用 new Man() 耗时:" + runWithNewConstructor());
134 System.err.println("再次使用 new Man() 耗时:" + runWithNewConstructor());
135 System.out.println("首次使用反射 耗时:" + runWithReflex());
136 System.err.println("再次使用反射 耗时:" + runWithReflex());
137 System.out.println("首次使用内部类调用 new Man() 耗时:" + runWithSubClass());
138 System.err.println("再次使用内部类调用 new Man() 耗时:" + runWithSubClass());
139 System.out.println("首次使用Lambda调用 new Man() 耗时:" + runWithLambda());
140 System.err.println("再次使用Lambda调用 new Man() 耗时:" + runWithLambda());
141 System.out.println("首次使用 MethodReference 耗时:" + runWithMethodReference());
142 System.err.println("再次使用 MethodReference 耗时:" + runWithMethodReference());
143
144
145 }
146
147 }

这次调整,仅仅只是把内部类、Lambda、Method Reference 放到循环外边,更符合我们常用的情形。

测试结果较之上一篇真的有很大的变化。

 1 首次使用 new Man()            耗时:4
2 再次使用 new Man() 耗时:1
3 首次使用反射 耗时:237
4 再次使用反射 耗时:251
5 首次使用内部类调用 new Man() 耗时:5
6 再次使用内部类调用 new Man() 耗时:2
7 首次使用Lambda调用 new Man() 耗时:41
8 再次使用Lambda调用 new Man() 耗时:3
9 首次使用 MethodReference 耗时:4
10 再次使用 MethodReference 耗时:1
 1 首次使用 new Man()            耗时:3
2 再次使用 new Man() 耗时:2
3 首次使用反射 耗时:240
4 再次使用反射 耗时:256
5 首次使用内部类调用 new Man() 耗时:5
6 再次使用内部类调用 new Man() 耗时:3
7 首次使用Lambda调用 new Man() 耗时:43
8 再次使用Lambda调用 new Man() 耗时:4
9 首次使用 MethodReference 耗时:4
10 再次使用 MethodReference 耗时:1
首次使用 new Man()            耗时:3
再次使用 new Man() 耗时:2
首次使用反射 耗时:238
再次使用反射 耗时:251
首次使用内部类调用 new Man() 耗时:5
再次使用内部类调用 new Man() 耗时:1
首次使用Lambda调用 new Man() 耗时:39
再次使用Lambda调用 new Man() 耗时:5
首次使用 MethodReference 耗时:3
再次使用 MethodReference 耗时:2

可以看到Lambda和Method Reference同样耗时非常小,主要是在使用其创建了Supplier<Man>接口的实现实例后,本质上就和内部类创建出来的对象没有差别,因此在性能表现上相差不大。

结论:

  如果既要保持灵活简洁又追求极致的性能时,那么使用在Lambda或者Method Reference时,尽量不要写在循环内部。

Java的几种创建实例方法的性能对比(二)的更多相关文章

  1. Java的几种创建实例方法的性能对比

    近来打算自己封装一个比较方便读写的Office Excel 工具类,前面已经写了一些,比较粗糙本就计划重构一下,刚好公司的电商APP后台原有的导出Excel实现出现了可怕的性能问题,600行的数据生成 ...

  2. java讲讲几种常见的排序算法(二)

    java讲讲几种常见的排序算法(二) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 堆排序 思路:构建一个小顶堆,小顶堆就是棵二叉树,他的左右孩子均大于他的根节点( ...

  3. Java中两种实现多线程方式的对比分析

    本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cf ...

  4. Go_18: Golang 中三种读取文件发放性能对比

    Golang 中读取文件大概有三种方法,分别为: 1. 通过原生态 io 包中的 read 方法进行读取 2. 通过 io/ioutil 包提供的 read 方法进行读取 3. 通过 bufio 包提 ...

  5. Golang 中三种读取文件发放性能对比

    Golang 中读取文件大概有三种方法,分别为: 1. 通过原生态 io 包中的 read 方法进行读取 2. 通过 io/ioutil 包提供的 read 方法进行读取 3. 通过 bufio 包提 ...

  6. 求斐波那契数列第n位的几种实现方式及性能对比(c#语言)

    在每一种编程语言里,斐波那契数列的计算方式都是一个经典的话题.它可能有很多种计算方式,例如:递归.迭代.数学公式.哪种算法最容易理解,哪种算法是性能最好的呢? 这里给大家分享一下我对它的研究和总结:下 ...

  7. java线程——三种创建线程的方式

    前言 线程,英文Thread.在java中,创建线程的方式有三种: 1.Thread 2.Runnable 3.Callable 在详细介绍下这几种方式之前,我们先来看下Thread类和Runnabl ...

  8. Java数组3种创建方式

    public static void main(String[] args){ /** * 1. 固定大小的空数组, 动态创建 */ String[] strArr1 = new String[3]; ...

  9. Delegate、Thread、Task、ThreadPool几种方式创建异步任务性能对比

    开始预测的结果是 Task>Delegate>ThreadPool>>Thread. (一)测试代码 static async Task<int> AsyncTas ...

随机推荐

  1. js 正则表达式 验证数字或字母

    let reg= /^(^[0-9]*$)|(^[A-Za-z]+$)/ /*reg= /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]$/*/ if(!reg.test( ...

  2. 解决List遍历删除元素提示ConcurrentModificationException

    JDK1.8提供新的API  ===>  removeIf public static void main(String[] args) { List<String> list = ...

  3. MySQL忘记密码怎么办-MySQL修改密码(亲测可用)

    前言: 最近要用到本地的MySQL,结果把密码忘记了. ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using pas ...

  4. 物理机连接虚拟机中的数据库及Windows添加防火墙允许端口详细操作步骤

    公司项目中因为会使用到SQL server数据库,但是自己电脑无论安装2008R2或者2014版本都不成功,我想可能是和之前安装的一些Windows的软件存在冲突. 于是便单独创建了一台虚拟机,在虚拟 ...

  5. 「CF559E」 Gerald and Path

    「CF559E」 Gerald and Path 为啥我现在做啥题都在想网络流啊 考虑 \(\texttt{DP}\). 容易想到状态应该包含当前枚举了前 \(i\) 条线段,且第 \(i\) 条线段 ...

  6. WIN7 WIN10修改path不用重启即可生效

    近来安装python scrapy经常忘了添加到path,需要时增加了但需要重启才能起作用,用下面的方法马上能生效: 1修改path:右击"计算机"--高级--环境变量--path ...

  7. python 遍历字典中的键和值

    #遍历字典中的所有键和值 zd1={"姓名":"张三","年龄":20,"性别":"女"} zd2= ...

  8. 成功解决1406, “Data too long for column ‘txt‘ at row 1“

    这是因为数据库里该字段的数据类型所给的数据空间太小.MySQL将截断超过指定列宽度的任何插入值.为了让这个不报错,可以尝试切换MySQL模式不使用严格模式. SET @@global.sql_mode ...

  9. Java基础00-继承17

    1. 继承 1.1 继承概述 但是我们将相同的类提取出来就会变成这个样子 让他们之间产生一个继承的关系 1.2 继承的好处和弊端 IS-A.HAS-A和USE-A关系 苹果是水果的一种可以使用继承猫是 ...

  10. 使用python对工作簿每个sheet表进行数据可视化展示(本案例是从第2个sheet开始循环读取也就是索引为1的表)

    # 导入相关模块from pyecharts.charts import Barfrom pyecharts import options as optsfrom pyecharts.charts i ...