java常用重构优化总结--自己亲身体验
代码重构
6大原则:
单一职责原则(一个类最好最好只有一种行为动机,太多承担职责会导致耦合度太高)、
开放封闭原则(功能可以扩展,但是不可以内部修改)、
依赖倒转原则(应该依赖抽象而不应该依赖具体对象)、
里氏代换原则(父类都替换成它的子类程序的行为没有变化。 正是有了里氏代换原则,才使得”开-闭“原则成为了可能)、
接口隔离原则(为同一个角色提供宽、窄不同的接口,以对付不同的客户端)、
迪米特法则(最少知道原则;如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用)
设计模式应用:
<1. 适配器模式(由原来sphinx适配为solr应用)
<2. 抽象工厂方法模式+反射+配置文件实现可配置的动态化(csv、bean、json等)
<3. 建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
主要用于解析客户端传过来的查询条件进行构造和封装,生成对应的solrQuery。以及最后查询完毕之后构建分装成对应返回的json格式
<4. 过滤器模式:允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来
过滤筛选传入查询时间、过滤目前已经有的集群定位查询范围(hot/recent/warm/all)
<5. 观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己(模拟ZK)
实时预处理触发更新底层依赖数据库更新。
多个更新类注册到统一监听器上 + 缓存mamcache + 出发更新模块(监控数据库数据变化+指标) + 数据库
代码调优
<1. 可以指定final修饰的类和方法那就一定要指定,java编译器会内联所有的final方法,提升java运行效率。Java编译器会寻找机会内联所有的final方法,内联对于提升Java运行效率作用重大,具体参见Java运行期优化。此举能够使性能平均提高50%。
<2. 字符串拼接不能使用+来拼接,底层会创建一个新对象,这两个对象相拼接,应该使用StringBuilder/StringBuffer
<3. 尽量使用局部变量。因为这是在栈中创建,随着方法的运行结束这些内容就消失了,不需要额外的垃圾回收
<4. 在一些大的循环时,尽量减少重复计算;例如for循环中的length
对方法的调用,即使方法中只有一句语句,也是有消耗的,包括创建栈帧、调用方法时保护现场、调用方法完毕时恢复现场等。所以例如下面的操作:
for (int i = 0; i < list.size(); i++) {...}
建议替换为:
for (int i = 0, int length = list.size(); i < length; i++) {...}
这样,在list.size()很大的时候,就减少了很多的消耗
<5. 尽量使用懒加载方式即在需要的时候才去创建
<6. 不要在循环中使用try...catch...
<7. 在可以评估出待添加内容的长度,那么在初始化容器的时候就直接指定开辟那么大的空间,HashMap除外,大概开辟2的次幂大小就可以了,因为它底层是列表形式存储
比如ArrayList、LinkedLlist、StringBuilder、StringBuffer、HashMap、HashSet等等,以StringBuilder为例:
(1)StringBuilder() // 默认分配16个字符的空间
(2)StringBuilder(int size) // 默认分配size个字符的空间
(3)StringBuilder(String str) // 默认分配16个字符+str.length()个字符空间
可以通过类的初始化函数来设定它的初始化容量,这样可以明显地提升性能。比如StringBuilder吧,length表示当前的StringBuilder能保持的字符数量。因为当StringBuilder达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,无论何时只要StringBuilder达到它的最大容量,它就不得不创建一个新的字符数组然后将旧的字符数组内容拷贝到新字符数组中—-这是十分耗费性能的一个操作。试想,如果能预估到字符数组中大概要存放5000个字符而不指定长度,最接近5000的2次幂是4096,每次扩容加的2不管,那么:
(1)在4096的基础上,再申请8194个大小的字符数组,加起来相当于一次申请了12290个大小的字符数组,如果一开始能指定5000个大小的字符数组,就节省了一倍以上的空间
(2)把原来的4096个字符拷贝到新的的字符数组中去
这样,既浪费内存空间又降低代码运行效率。所以,给底层以数组实现的集合、工具类设置一个合理的初始化容量是错不了的,这会带来立竿见影的效果。但是,注意,像HashMap这种是以数组+链表实现的集合,别把初始大小和你估计的大小设置得一样,因为一个table上只连接一个对象的可能性几乎为0。初始大小建议设置为2的N次幂,如果能估计到有2000个元素,设置成new HashMap(128)、new HashMap(256)都可以。
<8. 当复制大量数据时最好使用System.arrayCopy()方法 [当内容长度大于10000左右,使用此方法,否则太小的话使用for循环比较快]
<9. 乘法、除法尽量使用位运算
<10. 循环内不要创建对象
<11. 不要创建不使用的对象、不要引入不用到的引用。
<12. 使用数据库就使用数据库连接池
<13. 使用带缓冲的输入输出流进行IO操作:BufferedReader、BufferedInputStream / BufferedWriter、BufferedOutputStream
BufferedReader会一次性从物理流中读取8k(默认数值,可以设置)字节内容到内存,如果外界有请求,就会到这里存取,如果内存里没有才到物理流里再去读。即使读,也是再8k。 如果不使用BufferedReader而直接读物理流,是按字节来读,对物理流的每次读取,都有IO操作。IO操作是最耗费时间的。BufferedReader就是减少了大量IO操作,而为你节省了时间。
<14. 基本类型转换为字符串,最快的使用.toString()方法
所以以后遇到把一个基本数据类型转为String的时候,优先考虑使用toString()方法。至于为什么,很简单:
1、String.valueOf()方法底层调用了Integer.toString()方法,但是会在调用前做空判断
2、Integer.toString()方法就不说了,直接调用了
3、i + “”底层使用了StringBuilder实现,先用append方法拼接,再用toString()方法获取字符串
三者对比下来,明显是2最快、1次之、3最慢
<15. 遍历map对应的key-value,最好使用iterator的EntrySet方式;如果只是使用key值,则使用 hm.keySet();更加合理
<16. 多使用一些apache下提供的包:StringUtils、Collections判空、Arrays转换list,或者使用Guava:Joiner、Splitter、Strings、Maps判空
java常用重构优化总结--自己亲身体验的更多相关文章
- Java的性能优化
http://www.toutiao.com/i6368345864624144897/?tt_from=mobile_qq&utm_campaign=client_share&app ...
- java常用英语单词
abstract (关键字) 抽象 ['.bstr.kt] access vt.访问,存取 ['.kses]'(n.入口,使用权) algorithm n.算法 ['.lg.riem] annotat ...
- 从虚拟机视角谈 Java 应用性能优化
从虚拟机视角谈 Java 应用性能优化 周 祥, 软件工程师, IBM 简介:Java 的普及和广泛应用,以及其基于虚拟机运行的机制,使得性能问题越来越重要.本文从 Java 虚拟机的角度,特别是垃圾 ...
- Java常用英语汇总(面试必备)
Java常用英语汇总(面试必备) abstract (关键字) 抽象 ['.bstr.kt] access vt.访问,存 ...
- Java程序性能优化技巧
Java程序性能优化技巧 多线程.集合.网络编程.内存优化.缓冲..spring.设计模式.软件工程.编程思想 1.生成对象时,合理分配空间和大小new ArrayList(100); 2.优化for ...
- 发布大幅重构优化的 TouchVG 1.0.2
发布大幅重构优化的 TouchVG 1.0.2,支持SVG.多模块扩展结构,欢迎评阅改进.提交pull request. https://github.com/rhcad/touchvg 关于 Tou ...
- [JAVA] java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
- 百万并发中间件系统的内核设计看Java并发性能优化
“ 这篇文章,给大家聊聊一个百万级并发的中间件系统的内核代码里的锁性能优化. 很多同学都对Java并发编程很感兴趣,学习了很多相关的技术和知识.比如volatile.Atomic.synchroniz ...
- 【转载】图解Java常用数据结构(一)
图解Java常用数据结构(一) 作者:大道方圆 原文:https://www.cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Jav ...
随机推荐
- 九度OJ 1370 数组中出现次数超过一半的数字
题目地址:http://ac.jobdu.com/problem.php?pid=1370 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2 ...
- 转(sphinx 多索引使用 方法 )
1 http://blog.csdn.net/adparking/article/details/7080278 文章不错 总结 1.索引合并问题,前面已经解释过,两个索引合并时,都要读入,然后还要 ...
- nodejs -formidable模块实现图片上传。
var form = new formidable.IncomingForm(); form.uploadDir="/localnonobank/test/images/"; ...
- 点击listview 的列头对其item进行自动排序
若要自定义排序顺序,必须编写一个实现 IComparer 接口的类,并将 ListViewItemSorter 属性设置为该类的一个对象.当设置 ListViewItemSorter 属性值时,将自动 ...
- Google Map 自定义 infowindow
最近做的东西用到了infowindow,不过google提供的样式太难看了,于是想改变一下样式.看了一下好像infowindow的样式不太好改. 查了半天资料,看到一个infobox,感觉真的挺好用. ...
- rownum
rownum是一个伪列,oracle数据库会对查找到的数据 从1 开始递增指定每行的rownum值, 当查询条件里有 rownum时(比如 where rownum>2),数据库会依次从数据集里 ...
- facebook快速登录常见错误:后台设置、域名权限、开发模式、公开、沙盒
开发人员登录地址 : https://developers.facebook.com/?ref=pf 官方登录API文档地址 : https://developers.facebook.com/do ...
- HDU1004 (数组元素出现最多)
HDU1004 思路:求数组中出现次数最多的那个元素: 遍历数组元素,找出每个元素出现的次数 Input Input contains multiple test cases. Each test c ...
- CUDA获取显卡数据
一个简单的获取Nvidia显卡信息的程序 #include<iostream> int main() { cudaDeviceProp prop; int count; cudaGetDe ...
- swift swizzle
SWIZZLE 由 王巍 (@ONEVCAT) 发布于 2015/09/30 Swizzle 是 Objective-C 运行时的黑魔法之一.我们可以通过 Swizzle 的手段,在运行时对某些方法的 ...