Java的几种创建实例方法的性能对比(二)
上一篇里对几种书写方式进行了简单的测试,得出了一些初步的结论。这次简单了解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的几种创建实例方法的性能对比(二)的更多相关文章
- Java的几种创建实例方法的性能对比
近来打算自己封装一个比较方便读写的Office Excel 工具类,前面已经写了一些,比较粗糙本就计划重构一下,刚好公司的电商APP后台原有的导出Excel实现出现了可怕的性能问题,600行的数据生成 ...
- java讲讲几种常见的排序算法(二)
java讲讲几种常见的排序算法(二) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 堆排序 思路:构建一个小顶堆,小顶堆就是棵二叉树,他的左右孩子均大于他的根节点( ...
- Java中两种实现多线程方式的对比分析
本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cf ...
- Go_18: Golang 中三种读取文件发放性能对比
Golang 中读取文件大概有三种方法,分别为: 1. 通过原生态 io 包中的 read 方法进行读取 2. 通过 io/ioutil 包提供的 read 方法进行读取 3. 通过 bufio 包提 ...
- Golang 中三种读取文件发放性能对比
Golang 中读取文件大概有三种方法,分别为: 1. 通过原生态 io 包中的 read 方法进行读取 2. 通过 io/ioutil 包提供的 read 方法进行读取 3. 通过 bufio 包提 ...
- 求斐波那契数列第n位的几种实现方式及性能对比(c#语言)
在每一种编程语言里,斐波那契数列的计算方式都是一个经典的话题.它可能有很多种计算方式,例如:递归.迭代.数学公式.哪种算法最容易理解,哪种算法是性能最好的呢? 这里给大家分享一下我对它的研究和总结:下 ...
- java线程——三种创建线程的方式
前言 线程,英文Thread.在java中,创建线程的方式有三种: 1.Thread 2.Runnable 3.Callable 在详细介绍下这几种方式之前,我们先来看下Thread类和Runnabl ...
- Java数组3种创建方式
public static void main(String[] args){ /** * 1. 固定大小的空数组, 动态创建 */ String[] strArr1 = new String[3]; ...
- Delegate、Thread、Task、ThreadPool几种方式创建异步任务性能对比
开始预测的结果是 Task>Delegate>ThreadPool>>Thread. (一)测试代码 static async Task<int> AsyncTas ...
随机推荐
- 第八章 - JUC
J.U.C AQS 原理 全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架 特点: 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需 ...
- SpringBoot:SpringBoot项目中 HttpServletRequest ServletInputStream 读取不到文件数据流
在Springboot程序启动后,会默认添加OrderedCharacterEncodingFilter和HiddenHttpMethodFilter过滤器.在HiddenHttpMethodFilt ...
- python opencv处理图片
1.图像读入:cv2.imread() 使用函数cv2.imread(filepath,flags) 读入图像.第二个参数是要告诉函数应该如何读取这幅图片. cv2.IMREAD_COLOR:默认参数 ...
- mybatis 配置的log4j文件无效,不能正常显示日志信息
正在学习mybatis,配置好后log4j.properties文件后,日志信息不能正常显示,没有效果. 查看了一下mybatis的相关文档,在日志一栏找到问题愿意 原因是我们的mybatis选了其他 ...
- 关于vector.size()的一些常见错误总结
1. 问题引入 通过查看[https://www.cplusplus.com/reference/vector/vector/] 的vector.size()说明,即 member type defi ...
- git rebase 和 git merger
& git merge 在上图中,每一个绿框均代表一个commit.除了c1,每一个commit都有一条有向边指向它在当前branch当中的上一个commit. 图中的项目,在c2之后就开了另 ...
- asp.net c#从SQL2008读取图片显示到网页
//图像数据表:tx//字段id (nvarchar(50) ,image(image)//tgav为图片ID,实质为上传前的主名 (省略了.jpg) using System; using Syst ...
- java集合(1)-概述
Java集合类是一种特别有用的工具类,可用于存储数量不等的对象,并可以实现常用的数据结构,如栈,队列等,此外Java集合还可以用于保存具有映射关系的关联数组.java集合大致可分为Set,List,Q ...
- spring boot(二)整合mybatis plus+ 分页插件 + 代码生成
先创建spring boot项目,不知道怎么创建项目的 可以看我上一篇文章 用到的环境 JDK8 .maven.lombok.mysql 5.7 swagger 是为了方便接口测试 一.Spring ...
- Easyui设置easyui-textbox不可编辑
转载自:https://blog.csdn.net/qq_23113521/article/details/78801689 在easyui里由于easyui-textbox被封装,通过一般的jque ...