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 ...
随机推荐
- SpringBoot入门系列(四)整合模板引擎Thymeleaf
前面介绍了Spring Boot的优点,然后介绍了如何快速创建Spring Boot 项目.不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/ ...
- Idea - 常用基础配置
前言 IntelliJ IDEA是我们开发常用的一大神器,深得众程序猿青睐,但是在使用过程中,有一些默认设置我们使用起来并不是很友好...这里就记录一些我使用的配置. 1.多行显示同时打开的多个文件 ...
- C语言程序设计(三) 简单的算术运算和表达式
第三章 简单的算术运算和表达式 算数运算符:一元.二元.三元(条件运算符) 1/2是整型除法,1.0/2是浮点数除法 求余运算(%)限定参与运算的两个操作数必须为整数,不能对两个实型数据进行求余运算 ...
- 【SpringBoot基础系列-实战】如何指定 bean 最先加载(应用篇)
[基础系列-实战]如何指定 bean 最先加载(应用篇) 在日常的业务开发中,绝大多数我们都是不关注 bean 的加载顺序,然而如果在某些场景下,当我们希望某个 bean 优于其他的 bean 被实例 ...
- 建议11:增强数组排序的sort功能
sort方法不仅按字母顺序进行排序,还可以根据其他顺序执行操作.这时就必须为方法提供一个比较函数的参数,该函数要比较两个值,然后返回一个用于说明这两个值得相对顺序的数字.比较函数应该具有两个参数a和b ...
- HTTP请求中Get和Post请求的区别?
分类 Get的请求方式 1.直接在浏览器地址栏输入某个地址. 2.点击链接地址. 3.表单的默认提交方式或者设置为method="get". Post的请求方式 1.设置表单的me ...
- LeetCode43,一题让你学会高精度算法
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode系列第22篇文章,今天讲的内容是高精度算法. 今天和大家讨论的算法是高精度,对应的LeetCode是第43题.题面其实 ...
- 【简说Python WEB】数据库
目录 [简说Python WEB]数据库 数据库表 docker安装MySQL Flask-SQLAlchemy操纵MySQL数据库 初始化 定义模型 定义关系 数据库的CRUD操作 创建表 inse ...
- 微信小程序校历组件
微信小程序校历组件 校历组件,可以作为校园小程序的插件,如果觉得不错,点个star吧
- python对齐输出
这个问题烦恼了挺久,一般情况下我都是用\t解决,但其实这样的办法并不是很nice,然后今天在写一个demo的时候实在看不下去,就百度科普了一波,确实是有比较nice的解决方案. 像这样: 令人十分难受 ...