Java 程序该怎么优化?(技巧篇)
搬砖者:为什么程序总是那么慢?它现在到底在干什么?时间都花到哪里去了?
面试官:简单谈谈 Java 程序性能优化?
1.
字符串处理优化,乃优化之源。
研发过程中,String 的 API 用的应该是最多,创建 String 对象,以及字符串分割处理那是常有的事儿。
1.1. 字符串分割,谁更胜一筹?
字符串分割,常用的方式有哪些?哪种方式好一些?
方式一,经常用 String 提供的 split() 方法来满足业务需求。
代码模拟了一些数据,然后程序跑起来,花费大约 3000 多毫秒。
方式二,采用字符串分割的工具类 StringTokenizer。
采用 StringTokenizer 完成 split() 同样的数据分割,花费大约 500 毫秒。
从运行效果, StringTokenizer 其效率高于 split() 方法。所以,在能够使用 StringTokenizer 进行处理的地方,就尽量使用 StringTokenizer 进行字符串分割处理。
另外,平时研发中,需要注意一点,在使用索引访问用 String 的 split() 方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛异常的风险。
1.2. 字符串拼接,哪种方式更优?
方式一,使用 + 号拼接字符串。
程序跑起来,大约花费 27687 毫秒。
方式二,使用 StringBuilder 进行拼接字符串。
程序跑起来,大约花费 24 毫秒。
很显然,使用 + 号拼接字符串,其效率明显较低,采用 StringBuilder 来完成字符串连接性能相对较好,同理,如果需要考虑线程安全的情况下,可以选择 StringBuffer。
另外,在阿里开发手册中也强烈推荐,在循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。如果采取 + 号拼接,会造成内存资源浪费。
2.
善用 arraycopy(),让数组复制不再难。
数组复制是研发过程中,使用较多的功能,JDK 中提供了 API 来实现。但是,哪种方式较好呢?
方式一,作为开发人员,没事就喜欢造轮子,代码会这么写。
方式二,采取 System.arraycopy() 来完成数组复制。
红色圈住部分,在本机跑起来验证,方式一、方式二,差距不是特别大,在数据量大的时候,System.arraycopy() 还是稍微好一点。
方式三,采取 Arrays.copyOf() 来完成数组的复制。
鉴于 Arrays.copyOf() 底层还是调用 System.arraycopy() 来实现,性能肯定稍逊色于直接调用 System.arraycopy() 来完成数组复制。
所以,对数组的操作,如果能用 System.arraycopy() 这个方法实现,建议尽量去使用。
3.
关注循环体,别做重复劳动。
尽可能让程序少做重复的计算,尤其要重点关注循环体内的代码。
举个简单的栗子,上面代码段中,Math.PI * Math.sin(k) 的执行在循环体中重复执行,而且执行结果是唯一的,可以考虑提到循环体外。
本机进行验证时,前者大约花费 30 毫秒,而调整后,大约花费 2 毫秒,性能提升还是有的。
所以,从循环体内提取重复的代码,可以有效的提升系统性能。
另外,在阿里开发手册中强烈推荐,循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。
4.
集合用的多,使用场景要注意。
业务研发中,集合家族的 API 使用频率相当之高。那么,充分的选择好数据结构进行数据存储,便是最好的程序优化。
为了更清晰的说清各自的使用场景,也为了更好的助你掌握,梳理成思维导图。
4.1. List 家族,谁能得宠?
4.2. Map 家族,谁占鳌头?
另外,在集合初始化时,要指定集合初始值大小。
说明:HashMap 使用 HashMap(int initialCapacity) 初始化。
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。
注意负载因子(即 loader factor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。
反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容 量 7 次被迫扩大,resize 需要重建 hash 表,严重影响性能。
—— 阿里开发手册
4.2. Set 家族,谁最适配?
图中已经把常用的数据结构列举了出来,就不再一一去写代码验证啦。还是那句话,选择好数据结构进行数据存储,便是最好的程序优化。
5.
缓冲,让子弹飞一会儿。
缓冲,最常用的场景就是提高 I/O 的速度,解决 I/O 性能瓶颈。在
Java 中对不少 I/O 组件都提供了缓冲功能。
例如,采用 FileWriter 向文件中写入数据。
程序跑起来,花费大约 8212 毫秒。那么,再来看看加入缓冲之后会有什么效果?
程序跑起来,花费大约 4143 毫秒,性能提升了一倍。
所以,文件读写操作时尽量都使用缓冲流进行操作,有助于提升性能。
6.
缓存,让坐飞机的和坐驴车的打交道。
在实际项目研发中,缓存也是经常使用到,缓存是为了提升系统性能而开辟的内存空间。
最为简单的缓存可以直接使用 HashMap 实现,例如应用的配置信息,在启动的时候都加载进去。
针对银行编码等一些使用频率较高的业务数据,或者来之不易的计算结果,都可以保存到缓存中,当再次使用时,直接从缓存中获取,而不需要再占用宝贵的系统资源。
目前有很多基于 Java 的缓存框架,而我用的最多的是 EhCache。
7.
日志记的好,线上没烦恼。
推荐:谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。
说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。
记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
—— 阿里开发手册
8.
杂七杂八,啰嗦一句不嫌多。
一个优化原则。先实现业务功能,再考虑优化性能,如果功能都没实现,谈其它的都白扯。
一个调优思路。
首先从系统设计层面,去看看是否有改进的可能,是不是可以引入一些设计模式、是不是可以引入缓存机制等方法,来屏蔽潜在的性能问题。
然后从代码层面,看看代码是否有优化的可能。
接着去看看 Java 程序运行的环境,也就是通过调整 JVM 的参数来提升一下性能。
接着到数据库层面,看看是否有调优的可能。
最后到操作系统层面,看看是否可以进行调优。
好了,本次的分享,就到这里,希望你们喜欢。
Java 程序该怎么优化?(技巧篇)的更多相关文章
- Java 程序该怎么优化?(工具篇)
程序员:为什么程序总是那么慢?时间都花到哪里去了? 面试官:若你写的 Java 程序,出现了性能问题,该怎么去排查呢? 工欲善其事必先利其器,为你呈上一箩筐性能优化工具,必有一款满足你,废话不多说,直 ...
- Java 程序该怎么优化?(实战篇)
面试官:出现了性能问题,该怎么去排查呢? 程序猿:接口响应那么慢,时间都花到哪里去了? 运维喵:为什么你的应用跑着跑着,CPU 就接近 100%? 分享一些真实生产问题排查故事,看看能否涨姿势,能否 ...
- Java 程序该怎么优化?(命令篇)
灵魂拷问,JDK 提供的命令,除了 java.javac,你还用过哪些命令呢? 灵魂再拷问,若你写的 Java 程序,出现了性能问题,该怎么去排查呢? Java 作为编程语言中的战斗机,JDK 默认已 ...
- eclipse调试java程序的九个技巧
转:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions ...
- 使用 Eclipse 调试 Java 程序的 10 个技巧
你应该看过一些如<关于调试的N件事>这类很流行的帖子 .假设我每天花费1小时在调试我的应用程序上的话,那累积起来的话也是很大量的时间.由于这个原因,用这些时间来重视并了解所有使我们调试更方 ...
- 【转】使用 Eclipse 调试 Java 程序的 10 个技巧
你应该看过一些如<关于调试的N件事>这类很流行的帖子 .假设我每天花费1小时在调试我的应用程序上的话,那累积起来的话也是很大量的时间.由于这个原因,用这些时间来重视并了解所有使我们调试更方 ...
- 【Eclipse】调试java程序的九个技巧
本文转自[半夜乱弹琴],原文地址:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspe ...
- eclipse debug调试java程序的九个技巧
九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions display 远程debug 最早开始用eclipse的debug的时候,只会F5 F6 F ...
- (转)eclipse调试java程序的九个技巧
转自:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions ...
随机推荐
- python入门到放弃-基本数据类型之dcit字典
1.概述 字典是python中唯一的一个映射类型,以{}大括号括起来的键值对组成 字典中的key是唯一的,必须是可hash,不可变的数据类型 语法:{key1:value,key2:value} #扩 ...
- Jira使用说明文档
1 建立项目 1.1 权限归属 Jira系统管理员 1.2 执行内容 建立项目.工作流分配调整.制定项目负责人及默认经办人 1.3 建立项目过程 登录使用Jira系统管理员 ...
- selenium 操作 获取动态页面数据
# selenium from selenium import webdriver import time driver_path = r"G:\Crawler and Data\chrom ...
- js 数组 方法
instanceof 检测一个对象是否是数组;(用来对付复杂数据类型;)// 简单数据类型 typeof ;A instanceof B // A是不是B造出来的;例: var arr = [1,2, ...
- 原来rollup这么简单之 rollup.generate + rollup.write篇
大家好,我是小雨小雨,致力于分享有趣的.实用的技术文章. 内容分为翻译和原创,如果有问题,欢迎随时评论或私信,希望和大家一起进步. 分享不易,希望能够得到大家的支持和关注. 计划 rollup系列打算 ...
- JVM 参数(转)
Herry灬凌夜 转自:https://www.cnblogs.com/wuyx/p/9627542.html 常用的JVM配置参数 一.Trace 跟踪参数 在Eclipse中,如何打开GC的监控 ...
- 关于emgucv控制多摄像头问题
看到这篇文章你或许已经查阅很多资料,也可能你刚准备深入研究,但是关于调用多摄像头问题我要说明一点,关于多摄像头调用 取决于你电脑本身USB控制器数量,不是说你电脑上5个usb就可以同时控制5台摄像头, ...
- MyBatis框架——快速入门
主流的ORM框架(帮助开发者实现数据持久化工作的框架): 1.MyBatis: 半自动化ORM框架,半自动:指框架只完成一部分功能,剩下的工作仍需开发者手动完成. MyBatis 框架没有实现 POJ ...
- java web 获取 网页访问次数
ServletContext context = request.getServletContext(); /** * 从ServletContext中获取计数器对象 */Integer count ...
- 全国职业技能大赛信息安全管理与评估-MySQL弱口令利用
MySQL读文件 #coding=utf-8 import MySQLdb host = '172.16.1.' for i in range(129,131): tag = host+str(i) ...