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 ...
随机推荐
- salesforce零基础学习(一百零四)Salesforce Optimizer
本篇参考: https://admin.salesforce.com/blog/2017/analyzing-org-salesforce-optimizer-webinar-recap 假设你在做一 ...
- keycloak~OIDC&OAuth2&自定义皮肤
1 OpenID & OAuth2 & SAML 1.1 相关资料 https://github.com/keycloak/keycloak https://www.keycloak. ...
- Basic remains java入门题
Basic remains input: b p m 读入p进制的p,m, 求p%m ,以b进制输出 1 import java.util.*; 2 import java.math ...
- 使用Retrofit上传图片
Retrofit使用协程发送请求参考文章 :https://www.cnblogs.com/sw-code/p/14451921.html 导入依赖 app的build文件中加入: implement ...
- 明明是企业管理软件,CRM系统为何被抵触?
小编在昨天的文章<CRM系统为什么没有达到预期效果?>中曾说过,CRM客户管理系统没有达到预期效果的其中一个原因是CRM系统的使用率太低,而根本的原因是员工的抵触.明明是企业管理大师,CR ...
- JDBC:MySQL5.x 与 MySQL8.x
jar包下载地址: https://dev.mysql.com/downloads/connector/j/ 或者 :http://central.maven.org/maven2/mysql/mys ...
- Redis的内存回收原理,及内存过期淘汰策略详解
Redis 内存回收机制Redis 的内存回收主要围绕以下两个方面: 1.Redis 过期策略:删除过期时间的 key 值 2.Redis 淘汰策略:内存使用到达 maxmemory 上限时触发内存淘 ...
- RabbitMQ 安装与界面管理
RabbitMQ 安装与界面管理 RabbitMQ概述 官网:https://www.rabbitmq.com/ RabbitMQ是部署最广泛的开源消息代理. RabbitMQ拥有成千上万的用户,是最 ...
- 4.Java基础
为了项目方便管理,创建空项目 一.注释 平时编写代码,在代码量比较少的时候,还可以看懂自己写的,但是当项目结构一复杂起来,我们就需要用到注释了 注释并不会被执行,是给写代码的人看的 书写注释是一个非常 ...
- python 12篇 mock接口之flask模块
一.使用pip install flask按照flask模块. import flask,json # 轻量级web开发框架 server = flask.Flask(__name__) @serve ...