java代码优化重构 java 优化

北大青鸟java培训:代码重构过程中会产生哪些常见问题?相信大家在开发软件和进行软件维护的时候也会发现,有时候我们会针对一些软件的功能进行代码重构来让系统运行更加的稳定 。
今天天津java培训就一起来了解一下,在代码重构的过程中都会遇到哪些问题 。
1、离线任务和模型的管理问题 。
我们做在线服务的都有体会,我们经常容易对线上业务逻辑代码更关注一些 , 而往往忽视离线代码任务的管理和维护 。
但离线代码任务和模型在推荐场景中又至关重要 。
因此如何有效维护离线代码和任务,是我们面临的一个问题 。
2、特征日志问题 。
在推荐系统中,我们常常会遇到特征拼接和特征的『时间穿越』的问题 。
所谓特征时间穿越,指的是模型训练时用到了预测时无法获取的『未来信息』 , 这主要是训练label和特征拼接时时间上不够严谨导致 。
如何构建便捷通用的特征日志,减少特征拼接错误和特征穿越,是我们面临的二个问题 。
3、服务监控问题 。
一个通用的推荐系统应该在基础监控上做到尽可能通用可复用,减少具体业务对于监控的开发量,并方便业务定位问题 。
4、离线任务和模型的管理问题 。
在包括推荐系统的算法方向中 , 需要构建大量离线任务支持各种数据计算业务,和模型的定时训练工作 。
但实际工作中 , 我们往往忽略离线任务代码管理的重要性,当时间一长,各种数据和特征的质量往往无法保证 。
为了尽可能解决这样的问题 , 我们从三方面来做,一,将通用推荐系统依赖的离线任务的代码统一到一处管理;二,结合公司离线任务管理平台,将所有任务以通用包的形式进行管理,这样保证所有任务的都是依赖新包;三,建设任务结果的监控体系,将离线任务的产出完整监控起来 。
5、特征日志问题 。
AndrewNg之前说过:『挖掘特征是困难、费时且需要专业知识的事 , 应用机器学习其实基本上是在做特征工程 。
』我们理想中的推荐系统模型应该是有干净的RawData , 方便处理成可学习的Dataset , 通过某种算法学习model , 来达到预测效果不断优化的目的 。
但现实中,我们需要处理各种各样的数据源,有数据库的 , 有日志的 , 有离线的,有在线的 。
这么多来源的RawData,不可避免的会遇到各种各样的问题,比如特征拼接错误,特征『时间穿越』等等 。
这里边反应的一个本质问题是特征处理流程的规范性问题 。
那么我们是如何来解决这一点呢,先,我们用在线代替了离线,通过在线落特征日志 , 而不是RawData , 并统一了特征日志Proto,如此就可以统一特征解析脚本 。
Java中重构是什么意思?java重构:指程序员对已有程序在尽量不改变接口的前提下 , 进行重新编写代码的工作,一般有以下几方面:
1、去除已知bug 。
2、提高程序运行效率 。
3、增加新的功能 。
重构举例:(简化代码、提升效率)
重构前:
if(list != nulllist.size()0){
for(int i = 0; ilist.size(); i){
//skip...}}
重构后
if(list != null){
for(int i = 0, len = list.size(); ilen; i){
//skip...}}
Java代码如何优化?从哪些方面入手?分析?1)尽量指定类、方法的final修饰符 。带有final修饰符的类是不可派生的java代码优化重构,Java编译器会寻找机会内联所有的final方法,内联对于提升Java运行效率作用重大 , 此举能够使性能平均提高50% 。
2)尽量重用对象 。由于Java虚拟机不仅要花时间生成对象 , 以后可能还需要花时间对这些对象进行垃圾回收和处理,因此生成过多的对象将会给程序的性能带来很大的影响 。
3)尽可能使用局部变量 。调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中速度较快,其java代码优化重构他变量,如静态变量、实例变量等,都在堆中创建速度较慢 。
4)慎用异常 。异常对性能不利,只要有异常被抛出,Java虚拟机就必须调整调用堆栈,因为在处理过程中创建java代码优化重构了一个新的对象 。异常只能用于错误处理,不应该用来控制程序流程 。
5)乘法和除法使用移位操作 。用移位操作可以极大地提高性能,因为在计算机底层,对位的操作是最方便、最快的,但是移位操作虽然快,可能会使代码不太好理解 , 因此最好加上相应的注释 。
6)尽量使用HashMap、ArrayList、StringBuilder,除非线程安全需要 , 否则不推荐使用 Hashtable、Vector、StringBuffer,后三者由于使用同步机制而导致java代码优化重构了性能开销 。
尽量在合适的场合使用单例 。使用单例可以减轻加载的负担、缩短加载的时间、提高加载的效率,但并不是所有地方都适用于单例 。
Java代码如何优化1. 尽量在合适的场合使用单例
使用单例可以减轻加载的负担 , 缩短加载的时间 , 提高加载的效率 , 但并不是所有地方都适用于单例 , 简单来说 , 单例主要适用于以下三个方面:
第一 , 控制资源的使用,通过线程同步来控制资源的并发访问;
第二,控制实例的产生,以达到节约资源的目的;
第三 , 控制数据共享 , 在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信 。
2. 尽量避免随意使用静态变量
要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存
3. 尽量避免过多过常的创建Java对象
尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象 。
4. 尽量使用final修饰符
带有final修饰符的类是不可派生的 。在Java核心API中,有许多应用final的例子,例如java.lang.String.为String类指定final防止了使用者覆盖length()方法 。另外,如果一个类是final的,则该类所有方法都是final的 。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关) 。此举能够使性能平均提高50%.
5. 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快 。其他变量 , 如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢 。
6. 尽量处理好包装类型和基本类型两者的使用场所
虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生和处理都在栈中处理,包装类型是对象,是在堆中产生实例 。
在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型 。
7. 慎用synchronized,尽量减小synchronize的方法
都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制 。synchronize方法被调用时,直接会把当前对象锁 了,在方法执行完之前其他线程无法调用当前对象的其他方法 。所以synchronize的方法尽量?。?并且应尽量使用方法同步代替代码块同步 。
8. 尽量使用StringBuilder和StringBuffer进行字符串连接
这个就不多讲了 。
9. 尽量不要使用finalize方法
实际上,将资源清理放在finalize方法中完成是非常不好的选择,由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大 , 程序运行效率更差 。
10. 尽量使用基本数据类型代替对象
String str = "hello";
上面这种方式会创建一个"hello"字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o
11. 单线程应尽量使用HashMap、ArrayList
HashTable、Vector等使用了同步机制,降低了性能 。
12. 尽量合理的创建HashMap
当你要创建一个比较大的hashMap时,充分利用另一个构造函数
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大?。?同样的Hashtable,Vectors也是一样的道理 。
13. 尽量减少对变量的重复计算
并且在循环中应该避免使用复杂的表达式 , 在循环中,循环条件会被反复计算,如果不使用复杂表达式 , 而使循环条件值不变的话,程序将会运行的更快 。
14. 尽量避免不必要的创建
15. 尽量在finally块中释放资源
程序中使用到的资源应当被释放,以避免资源泄漏 。这最好在finally块中去做 。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭 。
16. 尽量使用移位来代替'a/b'的操作
"/"是一个代价很高的操作,使用移位的操作将会更快和更有效
17.尽量使用移位来代替'a*b'的操作
同样的,对于'*'操作,使用移位的操作将会更快和更有效
18. 尽量确定StringBuffer的容量
StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组 。在使用中,如果超出这个大小,就会重新分配内存 , 创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组 。在大多数情况下,你可以在创建 StringBuffer的时候指定大?。?这样就避免了在容量不够的时候自动增长,以提高性能 。
19. 尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部 , 引用变量显式设为null.
20. 尽量避免使用二维数组
二维数据占用的内存空间比一维数组多得多,大概10倍以上 。
21. 尽量避免使用split
除非是必须的,否则应该避免使用split,split由于支持正则表达式 , 所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果 。
22. ArrayListLinkedList
一 个是线性表,一个是链表 , 一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此 , 重要的是理解好2 者得数据结构,对症下药 。
23. 尽量使用System.arraycopy ()代替通过来循环复制数组
System.arraycopy() 要比通过循环来复制数组快的多
24. 尽量缓存经常使用的对象
尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存 , 他们基本都实现了FIFO/FLU等缓存算法 。
25. 尽量避免非常大的内存分配
有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的 。分配的内存块都必须是连续的,而随着堆越来越满 , 找到较大的连续块越来越困难 。
26. 慎用异常
当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的 。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大 。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照 , 所以暂时停止入栈和出栈操作 。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素 。
如 果您创建一个 Exception ,就得付出代价 。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来 。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价 。招致性能损失的并不是 throw 操作--尽管在没有预先创建异常的情况下就抛出异常是有点不寻常 。真正要花代价的是创建异常 。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常 。异常是为异常的情况而设计的,使用时也应该牢记这一原则 。
(1) 。用Boolean.valueOf(boolean b)代替new Boolean()
包装类的内存占用是很恐怖的,它是基本类型内存占用的N倍(N2),同时new一个对象也是性能的消耗 。
(2) 。用Integer.valueOf(int i)代替new Integer()
和Boolean类似,java开发中使用Integer封装int的场合也非常多,并且通常用int表示的数值都非常小 。SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用 Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例 。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用 。
(3) 。用StringBuffer的append方法代替" "进行字符串相加 。
这个已经被N多人说过N次了,这个就不多说了 。
(4) 。避免过深的类层次结构和过深的方法调用 。
因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户) 。
(5) 。变量只有在用到它的时候才定义和实例化 。
这是初学者最容易犯的错 , 合理的使用变量 , 并且只有在用到它的时候才定义和实例化,能有效的避免内存空间和执行性能上的浪费,从而提高了代码的效率 。
(6) 。避免在循环体中声明创建对象,即使该对象占用内存空间不大 。
这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误
采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷 。因此在循环体中声明创建对象的编写方式应该尽量避免 。
(7) 。如果if判断中多个条件用'||'或者''连接,请将出现频率最高的条件放在表达式最前面 。
这个小技巧往往能有效的提高程序的性能,尤其是当if判断放在循环体里面时,效果更明显 。
1.JVM管理两种类型的内存:堆内存(heap) , 栈内存(stack),堆内在主要用来存储程序在运行时创建或实例化的对象与变量 。而栈内存则是用来存储程序代码中声明为静态(static)(或非静态)的方法 。
2.JVM中对象的生命周期 , 创建阶段,应用阶段,不可视阶段 , 不可到达阶段,可收集阶段,终结阶段,释放阶段
3.避免在循环体中创建对象,即使该对象点用内存空间不大 。
4.软引用的主要特点是具有较强的引用功能 。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收 。它可以用于实现一些常用资源的缓存,实现Cache的功能
5.弱引用对象与Soft引用对象最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象,GC总是进行回收 。
6.共享静态变量存储空间
7.有时候我们为了提高系统性能,避免重复耗时的操作,希望能够重用一些创建完成的对象 , 利用对象池实现 。类似JDBC连接池 。
8.瞬间值,序列化对象大变量时,如果此大变量又没有用途,则使用transient声明,不序列化此变量 。同时网络传输中也不传输 。
9.不要提前创建对象
10 .(1)最基本的建议就是尽早释放无用对象的引用
A a = new A();
a = null; //当使用对象a之后主动将其设置为空
(2)尽量少用finalize函数 。
(3) 如果需要使用经常用到的图片展,可以使用软引用 。
(4) 注意集合数据类型,包括数组,树等数据,这些数据结构对GC来说,回收更为复杂,
(5) 尽量避免在类的默认构造器中创建 , 初始化大量的对象,防止在调用其自类的构造器时造成不必要的内存资源浪费 。
(6) 尽量避免强制系统做垃圾内存回收 。
(7) 尽量避免显式申请数组空间 。
(8) 尽量在合适的场景下使用对象池技术以提高系统性能,缩减系统内存开销 。
11.当做数组拷贝操作时 , 采用System.arraycopy()方法完成拷贝操作要比采用循环的办法完成数组拷贝操作效率高
12. 尽量避免在循环体中调用方法,因为方法调用是比较昂贵的 。
13. 尽量避免在循环体中使用try-catch 块,最好在循环体外使用try--catch块以提高系统性能 。
14. 在多重循环中,如果有可能,尽量将最长的循环放在最内层,最短的循环放在最外层,以减少循环层间的变换次数 。
15. 在需要线程安全的情况下,使用List list = Collections.synchronizedList(new ArrayList());
16. 如果预知长度 , 就设置ArrayList的长度 。
17. ArrayList 与 LinkedList 选择,熟悉底层的实现原理,选择适当的容器 。
18. 字符串累加采用StringBuffer.
19. 系统I/O优化 , 采用缓冲和压缩技术 。优化性能 。
20. 避免在类在构造器的初始化其他类
21 尽量避免在构造中对静态变量做赋值操作
22. 不要在类的构造器中创建类的实例
23. 组合优化继承
24. 最好通过Class.forname() 动态的装载类
25. JSP优化,采用out 对象中的print方法代替println()方法
26 .采用ServletOutputStream 对象代替JSPWriter对象
27. 采用适当的值初始化out 对象缓冲区的大小
28. 尽量采用forward()方法重定向新的JSP
29. 利用线程池技术处理客户请求
30.Servlet优化
(1) 通过init()方法来缓存一些静态数据以提高应用性能 。
(2) 用print() 方法取代println()方法 。
(3) 用ServletOutputStream 取代 PrintWriter.
(4) 尽量缩小同步代码数量
31. 改善Servlet应用性能的方法
(1)不要使用SingleThreadModel
(2)使用线程池ThreadPool
32. EJB优化
实体EJB:
(1)实体EJB中常用数据缓存与释放
(2)采用延迟加载的方式装载关联数据
(3)尽可能地应用CMP类型实体EJB
(4)直接采用JDBC技术处理大型数据
33. 优化JDBC连接
(1)设置合适的预取行值
(2)采用连接池技术
(3)全合理应用事务
(4)选择合适的事务隔离层与及时关闭连接对象
34. PreparedStatemetn只编译解析一次,而Statement每次都编译解析 。
35. 尽可能地做批处理更新
36. 通过采用合适的getXXX方法提高系统性能
37. 采用设计模式 。
Java代码的优化方法有哪些说到代码优化 , 每个人或多或少都掌握一到两种方法 , 但是这样的方法对提升代码运行效率效果不大,最重要是对代码的重视和了解,这样才能提升代码的运行效率 。在进行代码优化的过程中,方法是非常重要的,多掌握几种方法,根据代码的不同情况选择适合的方法进行优化 。下面电脑培训为大家介绍Java代码优化的几种方法 。
1、使用指定类、方法的final修饰符
具有final修饰符的类不可派生 。在Java核心API中,有许多最终应用程序的例子,例如java.lang.String,整个类都是final 。为类指定final修饰符允许继承类,并且为方法指定final修饰符允许覆盖该方法 。如果将类指定为final,IT培训认为该类的所有方法都是final 。Java编译器将寻找内联所有最终方法的机会 。内联对于提高Java操作的效率非常重要 。这可以将性能平均提高50% 。
2、重用对象
String对象的使用是非常重要的,StringBuilder/StringBuffer并不是字符串连接 。由于Java虚拟机需要时间来生成对象 , 所以将来垃圾收集和处理这些对象可能需要一些时间 。因此,生成太多对象将对程序的性能产生很大影响 。
3、使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在堆栈中 , 速度更快 。其他变量(如静态变量和实例变量)在堆中创建并且速度较慢 。此外,昆明北大青鸟发现在堆栈中创建的变量,当方法完成运行时,内容消失,不需要进行额外的垃圾收集 。
4、及时关闭流
在Java编程过程中,在执行数据库连接和I/O流操作时要小心 。使用后 , 北大青鸟云南嘉荟校区官网建议应及时关闭以释放资源 。因为这些大型物体的操作会导致系统的大量开销,稍微粗心会导致严重的后果 。
【java代码优化重构 java 优化】java代码优化重构的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java 优化、java代码优化重构的信息别忘了在本站进行查找喔 。

    推荐阅读