优化代码,提升代码性能

2023-09-22 09:39:54

一、 方法

1. 尽量指定类、方法的final修饰符

如果指定了一个类为final,则该类所有的方法都是final的。Java编译器会寻找机会内联所有的final方法,内联对于提升Java运行效率作用重大,具体参见Java运行期优化。此举能够使性能平均提高50%。

二、 变量

1. 循环内不要不断创建对象引用

例如:

for (int i = 1; i <= count; i++){
	Object  obj = new Object;
}

这种做法会导致内存中有count份Object对象引用存在,count很大的话,就耗费内存了,建议为改为:

Object obj = null;
for (int i = 0; i <= count; i++) {
	obj = new Object; 
}

这样的话,内存中只有一份Object对象引用,每次new Object的时候,Object对象引用指向不同的Object罢了,但是内存中只有一份,这样就大大节省了内存空间了。

2. 基本类型转换成字符串

把一个基本数据类型转为字符串,基本数据类型.toString是最快的方式、String.valueOf次之、数据+””最慢

3. 如果变量的初值会被覆盖,就没有必要给变量赋初值

反例:

List<UserDO> userList = new ArrayList<>();
if (isAll) {
    userList = userDAO.queryAll();
} else {
    userList = userDAO.queryActive();
}

正例:

List<UserDO> userList;
if (isAll) {
    userList = userDAO.queryAll();
} else {
    userList = userDAO.queryActive();
}

4. 尽量使用基本数据类型,避免不必要的装箱、拆箱和空指针判断

反例:

public static double sum(Double value1, Double value2) {
    double double1 = Objects.isNull(value1) ? 0.0D : value1;
    double double2 = Objects.isNull(value2) ? 0.0D : value2;
    return double1 + double2;
}
double result = sum(1.0D, 2.0D);

正例:

public static double sum(double value1, double value2) {
    return value1 + value2;
}
double result = sum(1.0D, 2.0D);

三、常量

1. 将常量声明为static final,并以大写命名

这样在编译期间就可以把这些内容放入常量池中,避免运行期间计算生成常量的值。另外,将常量的名字以大写命名也可以方便区分出常量与变量

2. 禁止使用JSON转化对象

虽然在功能上没有问题,但是在性能上却存在问题。

四、对象

1. 尽量重用对象

特别是String对象的使用,出现字符串连接时应该使用StringBuilder/StringBuffer代替。由于Java虚拟机不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响。

五、循环

1. 不要在循环中使用try…catch…,应该把其放在最外层

除非不得已。如果毫无理由地这么写了,那是不合理的。

2. for、增强for、iterator的选择

参考文章:List遍历:for,foreach Iterator 速度比较
总结:iterator 性能更优

// 遍历Set
Set<String> set = new HashSet<>();
set.add("a");
set.add("a");
set.add("b");
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}

// 遍历List
List<String> list = new ArrayList<>();
list.add("a");
list.add("a");
list.add("b");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}

// 遍历Map
Map<String, String> nameMap = new HashMap<>();
nameMap.put("student1", "lihua");
Set<Map.Entry<String, String>> entries = nameMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while(iterator.hasNext()){
	Map.Entry<String, String> entry = iterator.next();
	System.out.println(entry.getKey());
	System.out.println(entry.getValue());
}

六、集合

1. ArrayList和LinkedList

顺序插入和随机访问比较多的场景使用ArrayList,元素删除和中间插入比较多的场景使用LinkedList

2. 如果能估计到待添加的内容长度,尽量为指定初始长度

比如ArrayList、LinkedLlist、StringBuilder、StringBuffer、HashMap、HashSet等等,以StringBuilder为例:

(1)StringBuilder// 默认分配16个字符的空间

(2)StringBuilder(int size) // 默认分配size个字符的空间

(3)StringBuilder(String str) // 默认分配16个字符+str.length个字符空间

(4)List 默认长度是10

(5) Map 默认长度是16

只要达到它的最大容量,它就不得不创建一个新的字符数组然后将旧的字符数组内容拷贝到新字符数组中—-这是十分耗费性能的一个操作

七、字符串

1. 尽量避免使用split

除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。

2. 基本类型转换成字符串

把一个基本数据类型转为字符串,基本数据类型.toString是最快的方式、String.valueOf次之、数据+””最慢

3. 在字符串相加的时候,使用 ‘ ‘ 代替 " ",如果该字符串只有一个字符的话

例子:

public class STR {
	public void method(String s) {
		String string = s + "d" // violation.
		string = "abc" + "d" // violation.
	}
}

// 更正: 将一个字符的字符串替换成' '
public class STR {
	public void method(String s) {
		String string = s + "d // violation.
		string = "abc" + 'd' // violation.
	}
}

八、方法

1. 把跟类成员变量无关的方法声明成静态方法

静态方法的好处就是不用生成类的实例就可以直接调用。静态方法不再属于某个对象,而是属于它所在的类。只需要通过其类名就可以访问,不需要再消耗资源去反复创建对象。即便在类内部的私有方法,如果没有使用到类成员变量,也应该声明为静态方法。

反例:

public int getMonth(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    return calendar.get(Calendar.MONTH) + 1;
}

正例:

public static int getMonth(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    return calendar.get(Calendar.MONTH) + 1;
}
更多推荐

前端VUE---JS实现数据的模糊搜索

实现背景因为后端实现人员列表返回,每次返回的数据量在100以内,要求前端自己进行模糊搜索页面实现因为是实时更新数据的,就不需要搜索和重置按钮了代码HTML<el-dialogtitle="团队人员详情":visible.sync="centerDialogVisible"width="30%"center:close-

【从0学习Solidity】7. 映射类型 mapping

【从0学习Solidity】7.映射类型mapping博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!本文收录于不写代码没饭吃的学习汇报系列

穿越两大空间的调用栈

人是有经历的,软件也如此。简历记录着一个人的经历,而调用栈(callstack)则记录着软件的经历。看一个人的简历可以快速了解一个人。观察调用栈,则可以快速理解软件。因为此,我非常喜欢看软件的调用栈。每当看到一个漂亮的调用栈,我常常如获至宝,端详许久。因为对调试技术的热爱,这些年,我花了很多时间在调试器上。特别是开发了

基于movie lens-100k数据集的协同过滤算法实现

基于movielens-100k数据集的协同过滤算法实现数据集处理基于用户的协同过滤算法的实现基于物品的协同过滤算法的实现数据集处理importpandasaspdu_data=pd.read_csv('D:/PyCharmWorkSpace/ml-100k/ml-100k/u.data')u_genre=pd.rea

使用qt完善对话框功能

1、完善登录框点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容“账号密码不匹配,是否重新登录”,给定两个按钮ok和cancel,点击ok后,会清除密码框中的内容,继续进行登录;如果点击cancel按钮,则关闭界面。如果账号和密码匹配,则弹出信息对话框,给出提

zookeeper + kafka

Zookeeper概述Zookeeper是一个开源的分布式服务管理框架。存储业务服务节点元数据及状态信息,并负责通知再ZooKeeper上注册的服务几点状态给客户端Zookeeper工作机制Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观

Spring 框架的 MethodInterceptor 简介

org.springframework.cglib.proxy.MethodInterceptor是CGLIB库(CodeGenerationLibrary)中的一个接口,用于拦截方法的调用。CGLIB是一个用于生成Java字节码的代码生成库,它通常与SpringAOP一起使用,用于创建动态代理。MethodInter

IaaS,PaaS,SaaS 的区别

越来越多的软件,开始采用云服务。云服务只是一个统称,可以分成三大类。IaaS:基础设施服务,Infrastructure-as-a-servicePaaS:平台服务,Platform-as-a-serviceSaaS:软件服务,Software-as-a-serviceSaaS是软件的开发、管理、部署都交给第三方,不需

Java反序列化和PHP反序列化的区别

文章目录PHP反序列化漏洞什么是反序列化漏洞?修改序列化后的数据,目的是什么?Java反序列化漏洞那么漏洞点在哪里?漏洞成因什么是反序列化漏洞?反序列化存在的意义是为了数据传输,类是无法直接进行传输的。通过序列化后转换为字符串格式或者JSON格式进行传输。序列化与反序列化seriallization序列化:将对象转化为

Java多线程篇(4)——wait/notify和park/unPark

文章目录Object-wait/notifyobject.wait()object.notify()LockSupport-park/unparkLockSupport.park()LockSupport.unPark()Object-wait/notifyobject.wait()ObjectSynchronizer

宏任务,微任务,事件循环event loop与promise、setTimeout、async、nextTick【超详细示例讲解】

目录js单线程宏任务:在主线程上排队执行的任务,顺序执行宏任务macrotask:setTimeout,setInterval定时事件,Ajax,DOM事件,script脚本的执行、I/O操作、UI渲染等。微任务:不进入主线程、而进入"微任务列表"的任务微任务microtask(异步):Promise、async/aw

热文推荐