例如:
java代码
以上是不必要的,随着test()方法执行完毕,程序中obj引用变量的作用域结束。 但是如果改成下面这样:
java代码
这时候就需要将obj赋值为nulljava栈和堆分别存放什么,以便尽快释放对Object对象的引用。
20.尽量避免使用二维数组
二维数据占用的内存空间比一维数组大得多,大约多10倍。
21.尽量避免使用split
除非必要,否则应避免使用 split。 由于split支持正则表达式,所以效率比较低。 如果是频繁的几十、上百万的调用,会消耗很多资源。 如果确实需要频繁调用split,可以考虑使用apache的StringUtils.split(string,char),可以缓存频繁split的结果。
22. 数组列表和链表
一个是线性列表,另一个是链表。 一句话,尽量使用ArrayList进行随机查询。 ArrayList 优于 LinkedList。 LinkedList 也需要移动指针。 LinkedList 在增删改操作上优于 ArrayList。 ArrayList也需要移动数据,但这是理论上的分析。 ,事实未必如此,重要的是了解两者的数据结构,对症下药。
23.尝试使用System.arraycopy()代替循环复制数组
System.arraycopy() 比通过循环复制数组要快得多。
24.尽量缓存经常使用的对象
尽可能缓存经常使用的对象。 可以使用数组或者HashMap容器进行缓存,但是这种方式可能会导致系统占用过多的缓存,降低性能。 推荐使用一些第三方的开源工具,比如EhCache,Oscache做缓存,他们基本实现了FIFO/FLU等缓存算法。
25.尽量避免非常大的内存分配
有时问题不是由当时堆的状态引起的,而是分配失败引起的。 所有分配的内存块必须是连续的,随着堆越来越满,找到更大的连续块变得越来越困难。
26. 谨慎使用异常
当一个异常被创建时,需要收集一个堆栈轨迹(stack track),它用来描述异常是在哪里创建的。 构建这些堆栈跟踪需要拍摄运行时堆栈的快照,而这部分成本很高。 当需要创建Exception时,JVM不得不说:别动,我要保存你现在的快照,所以暂时停止push和pop操作。 堆栈跟踪不仅包括运行时堆栈中的一个或两个元素,还包括该堆栈中的每个元素。
如果你创建了一个 Exception,你就必须付出代价。 好在捕获异常的开销不大,可以用try-catch来包裹核心内容。 从技术上讲,您甚至可以随意抛出异常而无需付出太多代价。 引发性能损失的不是 throw 操作——尽管在没有预先创建异常的情况下抛出异常有点不寻常。 真正的成本是创建异常,幸运的是,良好的编程习惯告诉我们无论如何都不应该抛出异常。 异常是为异常情况而设计的,使用时应牢记这一原则。
27. 尝试重用对象
尤其是在String对象的使用上,当出现字符串拼接的时候应该使用StringBuffer来代替,因为系统不仅需要时间来生成对象,以后还可能需要花时间对这些对象进行垃圾回收和处理。 因此,生成过多的对象会对程序的性能产生很大的影响。
28. 不要双重初始化变量
默认情况下,在调用类的构造函数时,java会将变量初始化为一定的值,所有对象都设置为null,整型变量设置为0,float和double变量设置为0.0,逻辑值设置为错误的。 当一个类派生自另一个类时尤其如此,因为当使用 new 关键字创建对象时,会自动调用构造函数链中的所有构造函数。
这里有一个注释。 当为成员变量设置初始值但又需要调用其他方法时,最好放在一个方法中。 比如在initXXX()中,因为直接调用了一个方法赋值,可能会因为类没有初始化而抛出空指针异常,如:public int state = this.getState()。
29、在java+Oracle应用系统开发中,java内嵌的SQL语言尽量大写,以减轻Oracle解析器的解析负担。
30、java编程过程中,进行数据库连接和I/O流操作,使用后及时关闭,释放资源。 因为对这些大对象的操作会造成很大的系统开销。
31、保证过期对象的及时回收意义重大
过多地创建对象会消耗系统大量的内存,严重时会造成内存泄漏。 因此,保证过期对象的及时回收具有重要意义。 JVM的GC不是很智能,所以建议在对象使用完后手动设置为null。
32、在使用同步机制时,尽量使用方法同步,而不是代码块同步。
33.不要在循环中使用Try/Catch语句,将Try/Catch放在循环的最外层
error是获取系统错误的类,或者说是虚拟机错误的类。 并不是所有的错误Exception都可以获得。 如果虚拟机报错Exception,则无法获取。 必须使用错误来获取它。
34.通过StringBuffer的构造函数设置其初始化容量可以显着提高性能
StringBuffer的默认容量是16,当StringBuffer的容量达到最大容量时,它会将自己的容量增加到当前的2倍+2,即2*n+2。 每当 StringBuffer 达到其最大容量时,它必须创建一个新的对象数组,然后复制旧的对象数组,这会浪费很多时间。 所以有必要给StringBuffer设置一个合理的初始容量值!
35.java.util.Vector的合理使用
Vector 类似于 StringBuffer。 每次扩容时,都必须将现有的所有元素分配到新的存储空间中。 Vector默认存储容量为10个元素,扩展容量翻倍。
vector.add(index, obj) 该方法可以将元素obj插入到index位置,但是index和后面的元素必须依次向下移动一位(其index加1)。 除非必要,否则对性能不利。 相同的规则适用于 remove(int index) 方法,该方法删除此向量中指定位置的元素。 将所有后续元素向左移动(将其索引减 1)。 返回此向量中删除的元素。 所以删除向量的最后一个元素比删除第一个元素便宜得多。 最好使用 removeAllElements() 方法移除所有元素。
如果你想删除vector中的一个元素,你可以使用vector.remove(obj); 而不是自己检索元素的位置,然后删除它java栈和堆分别存放什么,例如:
int index = indexOf(obj);
向量。 删除(索引)。
38.创建一个对象的实例,不用new关键字
当使用 new 关键字创建类的实例时,将自动调用构造函数链中的所有构造函数。 但是如果一个对象实现了 Cloneable 接口,我们可以调用它的 clone() 方法。 clone() 方法不调用任何类构造函数。
下面是工厂模式的典型实现:
改进后的代码使用了 clone() 方法:
39. 不要将数组声明为:public static final
40.HaspMap的遍历
使用hash值取出对应的Entry进行比较得到结果,得到entry的值后直接取key和value。
41.数组(array)和ArrayList的使用
array 是最高效的,但是它的容量是固定的,不能动态改变。 ArrayList 的容量可以动态增加,但是是以牺牲效率为代价的。
42、单线程应该尽量使用HashMap、ArrayList
除非必要,否则不推荐使用 HashTable 和 Vector,它们使用同步机制,会降低性能。
43.StringBuffer和StringBuilder的区别是
java.lang.StringBuffer 线程安全的可变字符序列。 类似于 String 的字符串缓冲区,但不能修改。 StringBuilder StringBuilder 类通常应优先于此类使用,因为它支持所有相同的操作,但速度更快,因为它不执行同步。
为了获得更好的性能,你应该在构造StringBuffer或StringBuilder时尽量指定她的容量。 当然,如果不超过16个字符,就没有必要了。 同等情况下,使用StringBuilder只能比使用StringBuffer获得10%~15%的性能提升,但又要承担多线程不安全的风险。 综合考虑还是推荐使用StringBuffer。
44.尽量使用基本数据类型而不是对象。
45. 使用具体的类比比使用接口更高效,但结构灵活性降低,但现代 IDE 可以解决这个问题。
46. 考虑使用静态方法
如果您不必访问对象的外部,则将您的方法设为静态方法。 它会被调用得更快,因为它不需要虚函数指针表。 这也是一个很好的做法,因为它告诉你如何区分方法的性质,调用这个方法不会改变对象的状态。
47. 应尽可能避免内在的 GET 和 SET 方法。
48.避免枚举和使用浮点数。
以下是一些实际优化的示例:
49.避免在循环条件中使用复杂的表达式
在没有进行编译优化的情况下,循环中会反复计算循环条件。 如果不使用复杂的表达式,保持循环条件值不变,程序会运行得更快。 例子:
正确的:
50. 定义“Vectors”和“Hashtables”的初始大小
当JVM扩展Vector的大小时,需要重新创建一个更大的数组,复制原数组的内容,最后回收原数组。 可见,Vector容量的扩展是一个耗时的工作。
通常,10 个元素的默认大小是不够的。 您最好能够准确估计您需要的最佳尺寸。 例子:
正确的:
自己设置初始大小。
51. 在finally块中关闭Stream
应释放程序中使用的资源,以避免资源泄漏。 这最好在 finally 块中完成。 不管程序执行的结果如何,finally块总是会被执行,以确保资源被正确关闭。
52. 使用'System.arraycopy()' 代替遍历数组
例子:
正确的:
53. 使实例中访问变量的getter/setter 方法成为“final”
简单的getter/setter方法应该设置为final,告诉编译器这个方法不会被重载,所以可以“内联”,例如:
正确的:
54. 对于常量字符串,使用'String'而不是'StringBuffer'
常量字符串不需要动态改变长度。
例子:
更正:用String替换StringBuffer,如果确定String不会再变化,这样会减少运行开销,提高性能。
55. 添加字符串时,如果字符串只有一个字符,用''代替""
例子:
正确的:
将一个字符的字符串替换为 ' '
以上只是Java编程的性能优化。 大多数性能优化是在时间、效率和代码结构层次上的权衡。 每个都有自己的优点和缺点。 不要把以上内容当成教条。 不适用,宜根据实际工作场景进行选择,灵活学习应用,灵活运用。
【结尾】
如果你看到这个,说明你喜欢这篇文章,请转发点赞。 微信搜索“web_resource”,关注并回复“进群”或扫描下方二维码进入无广告交流群。
↓扫描二维码进群↓