JAVA性能优化_重要要点_二

String对象的3个基本特点: 

1、不变性 : 不变模式的主要作用在于当 一个对象需要被多线程共享,并且访问频繁时,可以省略同步和锁等待的时间,从而大幅提高系统性能。

2、针对常量池的优化 : intern()方法会不开辟新的空间,而使用现有的开辟的地址

3、类的final定义:  作为 final类的String对象在系统中不能有任何子类,这是对系统安全性的 保护。

字符串分割效率对比结论: split()方法功能强大,但是效率最差;StringTokenizer性能优于split()方法,因此在能够使用 StringTokenizer的模块中,就没有必要使用split();而完全由自己 实现的分割算法性能最好,但相对来说,代码的可读性和系统的可维护性最差,只有当系统性能问题成为主要矛盾时,才推荐使用该方法。

**对于静态字符串的连接操作,Java在编译时会进行彻底的 优化,将多个连接操作的字符串在编译时合成一个单独的长字符串。

**Java在编译时,会对字符串处理进行一定的优化。因此, 一些看起来很慢的代码,可能实际上并不会太慢。

**String的加法操作虽然会被优化,但编译器显然 不够“聪明”,因此对于String操作,类似于“+”和“+=”的运算符 应该尽量少用;其次,String的concat()方法的效率远远高于“+”和 “+=”运算符,但是又远远低于StringBuilder类

**在无须考虑线程安全的情况下可以使用性能相对较好的 StringBuilder,但若系统有线程安全要求,则只能选择StringBuffer。

**对于大对象的扩容会涉及大量的内存复制操作。如果能 够预先评估StringBuilder的大小,则能够有效地减少这些操作,从而 提高系统的性能。

**CompactStrings优化字符串存储

核心数据结构

List

ArrayList与LinkedList的不同之处

1、增加元素到列表尾端:  只要ArrayList的当前容量足够大,add()操作的效率 就非常高。

只有当ArrayList对容量的需求超过当前数组的大小时,才需要进行扩容。扩容过程中会进行大量的数组复制操作,而数组复制时,最终将会调用System.arraycopy()方法,因此add()操作的效率还是相当高的。

LinkedList由于使用了链表的结构,因此不需要维护容量的大小。从这一点上说,它比ArrayList有一定的性能优势。然而每次 的元素增加都需要新建一个Entry对象并进行更多的赋值操作,在频繁的系统调用中,对性能会产生一定的影响。

2、增加元素到列表的任意位置

ArrayList 每次插入操作都会进行一次数组复制,而这个操作在 增加元素到List尾端的时候是不存在的。大量的数组重组操作会导致 系统性能低下,并且插入的元素在List中的位置越靠前,数组重组的开销也越大,因此,尽可能地将元素插入到List的尾端附近,有助于 提高该方法的性能。

对于LinkedList来说,在List尾端插入数据与在任意位置 插入数据是一样的,并不会因为插入的位置靠前而导致插入方法性能降低。

3、删除任意位置的元素

对于ArrayList,从尾部删除元素时效率很高,从头部删除元素时相当费时,而LinkedList从头、尾删除元素时效率相差无几级,但是从List中间删除元素时性能非常糟糕。

4、容量参数: 容量参数是ArrayList和Vector等基于数组的List的特有性能参 数,它表示初始化的数组大小

数组的扩容会导致整个数组进行一次内存复制,因此合理的数组大小有助于减少 数组扩容的次数,从而提高系统性能。 ** 默认情况下,ArrayList数组的初始大小为10,每次扩容将新的数组大小设置为原大小的1.5倍。

在能有效地评估ArrayList数组大小初始值的情况下,指定容量大小对其性能有较大的提升

5、遍历列表

对于ArrayList这些基于数组的实现来说,随机访问的速度是很快的。在遍历这些List对象时,可以优先考虑随机访问。但对于 LinkedList等基于链表的实现,随机访问性能是非常差的,应避免使用。

Map

Hashtable的大部分方法做了同步,而HashMap则没有,因此HashMap不是线程安全的;其次,Hashtable不允许key或者value使用null值,而HashMap可以;最后,在内部算法上,它们对key的Hash 算法和Hash值到内存索引的映射算法不同

HashMap原理: HashMap就是将key做Hash算法,然后将Hash值映射到内存地址上,直接取得key所对应的数据

native方法通常比一般的方法快,因为它直接调用操作系 统本地链接库的API。由于hashCode()方法是可以重载的,因此为了保证HashMap的性能,需要确保相关的hashCode()是高效的。而位运算也 比算术运算和逻辑运算快。

Hash冲突:

HashMap的内部维护着一个Entry数组,每一个Entry表项包括key、value、next和hash几项。这里需要特别注意其中的next 部分,它指向了另外一个Entry。进一步阅读HashMap的put()方法源码 可以看到,当put()操作有冲突时,新的Entry依然会被安放在对应的 索引下标中,以并替换原有的值。同时,为了保证旧值不丢失,会将 新的Entry的next指向旧值,这便实现了在一个数组索引空间内存放多 个值项的目的。因此,HashMap实际上是一个链表的数组

只要hashCode()和hash()方法实现得足够好,能够尽可能地减少冲突的产生,那么对HashMap的操作几乎 等价于对数组的随机访问操作,具有很好的性能。但是,如果 hashCode()或者hash()方法实现较差,在大量冲突产生的情况下, HashMap事实上就退化为几个链表,对HashMap的操作等价于遍历链表,此时性能很差。

容量参数

HashMap的扩容操作会遍历整个HashMap,因此应该尽量 避免该操作发生。设置合理的初始大小和负载因子,可以有效减少 HashMap扩容的次数。

HashMap的性能在一定程度上取决于hashCode()的实现。 一个好的hashCode()算法,可以尽可能减少冲突,从而提高HashMap的 访问速度。

LinkedHashMap: LinkedHashMap可以简单地理解为一个维护了元素次序表的HashMap。

** 不要在迭代器模式中修改被迭代的集合。如果这么做, 就会抛出Concurrent-ModificationException异常。这个特性适用于所有的集合类,包括HashMap、Vector和ArrayList等

TreeMap有着比HashMap更为强大的功能,它实现了SortedMap接口,这意味着它可以对元素进行排序,然而TreeMap的性能却略微低于HashMap。

TreeMap的排序方式和LinkedHashMap是不同的。 LinkedHashMap是基于元素进入集合的顺序或者被访问的先后顺序排序,而TreeMap则是基于元素的固有顺序(由Comparator或者 Comparable确定)排序。

Set间的区别:

HashSet的输出结果毫无规律可言,LinkedHashMap的输 出顺序和输入顺序完全一致,而TreeSet的输出顺序则是将所有输入从小到大排序。

如果可以,尽量直接访问内部元素,而不要调用对应的接口。因为函数调用是需要消耗系统资源的,而直接访问元素会更高效。

通过RandomAccess可以知道List是否支持快速随机访问。同时需要记住,如果应用程序需要通过索引下标对List做随机访问,尽量不要使用LinkedList,而使用ArrayList和Vector,都是不错的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值