引出
程序人生——Java数组和集合使用建议(2)文章来源地址https://www.toymoban.com/news/detail-841500.html
数组和集合
建议71:推荐使用subList处理局部列表
- 需求:要删除一个ArrayList中的20-30范围内的元素;将原列表转换为一个可变列表,然后使用subList获取到原列表20到30范围内的一个视图(View),然后清空该视图内的元素,即可在原列表中删除20到30范围内的元素
建议72:生成子列表后不要再操作原列表
- subList生成子列表后,使用Collections.unmodifiableList(list);保持原列表的只读状态)(利用subList生成子列表后,更改原列表,会造成子列表抛出java.util.ConcurrentModificationException异常。原因:subList取出的列表是原列表的一个视图,原数据集(代码中的list变量)修改了,但是subList取出的子列表不会重新生成一个新列表(这点与数据库视图是不相同的),后面再对子列表操作时,就会检测到修改计数器与预期的不相同,于是就抛出了并发修改异常
建议73:使用Comparator进行排序
- Comparable接口可以作为实现类的默认排序法,Comparator接口则是一个类的扩展排序工具)(两种数据排序实现方式:1、实现Comparable接口,必须要实现compareTo方法,一般由类直接实现,表明自身是可比较的,有了比较才能进行排序;2、实现Comparator接口,必须实现compare方法,Comparator接口是一个工具类接口:用作比较,它与原有类的逻辑没有关系,只是实现两个类的比较逻辑
建议74:不推荐使用binarySearch对列表进行检索
- indexOf与binarySearch方法功能类似,只是使用了二分法搜索。使用二分查找的首要条件是必须要先排序,不然二分查找的值是不准确的。indexOf方法直接就是遍历搜寻。从性能方面考虑,binarySearch是最好的选择
建议75:集合中的元素必须做到compareTo和equals同步
- 实现了compareTo方法,就应该覆写equals方法,确保两者同步)(在集合中indexOf方法是通过equals方法的返回值判断的,而binarySearch查找的依据是compareTo方法的返回值;equals是判断元素是否相等,compareTo是判断元素在排序中的位置是否相同
建议76:集合运算时使用更优雅的方式
- 1、并集:list1.addAll(list2);
- 2、交集:list1.retainAll(list2);
- 3、差集:list1.removeAll(list2);
- 4、无重复的并集:list2.removeAll(list1);list1.addAll(list2);
建议77:使用shuffle打乱列表
- 使用Collections.shuffle(tagClouds)打乱列表
建议78:减少HashMap中元素的数量
- 尽量让HashMap中的元素少量并简单)(**现象:**使用HashMap存储数据时,还有空闲内存,却抛出了内存溢出异常;**原因:**HashMap底层的数组变量名叫table,它是Entry类型的数组,保存的是一个一个的键值对。与ArrayList集合相比,HashMap比ArrayList多了一次封装,把String类型的键值对转换成Entry对象后再放入数组,这就多了40万个对象,这是问题产生的第一个原因;HashMap在插入键值对时,会做长度校验,如果大于或等于阈值(threshold变量),则数组长度增大一倍。默认阈值是当前长度与加载因子的乘积,默认的加载因子(loadFactor变量)是0.75,也就是说只要HashMap的size大于数组长度的0.75倍时,就开始扩容。导致到最后,空闲的内存空间不足以增加一次扩容时就会抛出OutOfMemoryError异常
建议79:集合中的哈希码不要重复
- 列表查找不管是遍历查找、链表查找或者是二分查找都不够快。最快的是Hash开头的集合(如HashMap、HashSet等类)查找,原理:根据hashCode定位元素在数组中的位置。HashMap的table数组存储元素特点:1、table数组的长度永远是2的N次幂;2、table数组中的元素是Entry类型;3、table数组中的元素位置是不连续的;每个Entry都有一个next变量,它会指向下一个键值对,用来链表的方式来处理Hash冲突的问题。如果Hash码相同,则添加的元素都使用链表处理,在查找的时候这部分的性能与ArrayList性能差不多
建议80:多线程使用Vector或HashTable
- Vector与ArrayList原理类似,只是是线程安全的,HashTable是HashMap的多线程版本。线程安全:基本所有的集合类都有一个叫快速失败(Fail-Fast)的校验机制,当一个集合在被多个线程修改并访问时,就可能出现ConcurrentModificationException异常,这是为了确保集合方法一致而设置的保护措施;实现原理是modCount修改计数器:如果在读列表时,modCount发生变化(也就是有其他线程修改)则会抛出ConcurrentModificationException异常。**线程同步:**是为了保护集合中的数据不被脏读、脏写而设置的
建议81:非稳定排序推荐使用List
- 非稳定的意思是:经常需要改动;TreeSet集合中元素不可重复,且默认按照升序排序,是根据Comparable接口的compareTo方法的返回值确定排序位置的。SortedSet接口(TreeSet实现了该接口)只是定义了在该集合加入元素时将其进行排序,并不能保证元素修改后的排序结果。因此TreeSet适用于不变量的集合数据排序,但不适合可变量的排序。对于可变量的集合,需要自己手动进行再排序)(SortedSet中的元素被修改后可能会影响其排序位置
建议82:由点及面,一页知秋—集合大家族
- List:实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack,其中ArrayList是一个动态数组,LinkedList是一个双向链表,Vector是一个线程安全的动态数组,Stack是一个对象栈,遵循先进后出的原则;
- Set:Set是不包含重复元素的集合,其主要的实现类有:EnumSet、HashSet、TreeSet,其中EnumSet是枚举类型的专用Set,HashSet是以哈希码决定其元素位置的Set,原理与HashMap相似,提供快速插入与查找方法,TreeSet是一个自动排序的Set,它实现了SortedSet接口;
- Map:可以分为排序Map和非排序Map;排序Map为TreeMap,根据Key值进行自动排序;非排序Map主要包括:HashMap、HashTable、Properties、EnumMap等,其中Properties是HashTable的子类,EnumMap则要求其Key必须是某一个枚举类型;
- Queue:分为两类,一类是阻塞式队列,队列满了以后再插入元素会抛异常,主要包括:ArrayBlockingQueue、PriorityBlockingQueue、LinkedBlockingQueue,其中ArrayBlockingQueue是以数组方式实现的有界阻塞队列;PriorityBlockingQueue是依照优先级组件的队列;LinkedBlockingQueue是通过链表实现的阻塞队列;另一类是非阻塞队列,无边界的,只要内存允许,都可以追加元素,经常使用的是PriorityQueue类。还有一种是双端队列,支持在头、尾两端插入和移除元素,主要实现类是:ArrayDeque、LinkedBlockingDeque、LinkedList;
- 数组:数组能存储基本类型,而集合不行;所有的集合底层存储的都是数组;
- 工具类:数组的工具类是:java.util.Arrays和java.lang.reflect.array;集合的工具类是java.util.Collections;
- 扩展类:可以使用Apache的commons-collections扩展包,也可以使用Google的google-collections扩展包
深入认识JVM
JVM内存分配,类加载
Java进阶(1)——JVM的内存分配 & 反射Class类的类对象 & 创建对象的几种方式 & 类加载(何时进入内存JVM)& 注解 & 反射+注解的案例
创建对象的4种方法总结
Java进阶(4)——结合类加载JVM的过程理解创建对象的几种方式:new,反射Class,克隆clone(拷贝),序列化反序列化
垃圾回收GC
Java进阶(垃圾回收GC)——理论篇:JVM内存模型 & 垃圾回收定位清除算法 & JVM中的垃圾回收器
简介:本篇博客介绍JVM的内存模型,对比了1.7和1.8的内存模型的变化;介绍了垃圾回收的语言发展;阐述了定位垃圾的方法,引用计数法和可达性分析发以及垃圾清除算法;然后介绍了Java中的垃圾回收器,由串行、到并行再到并发,最后到G1的演变;最后给出了垃圾回收器的对比和使用指引。
JVM调优,Arthas使用
- Java进阶(JVM调优)——阿里云的Arthas的使用 & 安装和使用 & 死锁查找案例,重新加载案例,慢调用分析
- Java进阶(JVM调优)——JVM调优参数 & JDK自带工具使用 & 内存溢出和死锁问题案例 & GC垃圾回收
认识多线程
创建多线程方法+了解线程池
Java进阶(5)——创建多线程的方法extends Thread和implements Runnable的对比 & 线程池及常用的线程池
多线程下-1非原子性问题即解决
Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件
再论线程,创建、生命周期
Java进阶(再论线程)——线程的4种创建方式 & 线程的生命周期 & 线程的3大特性 & 集合中的线程安全问题
主要内容:
1.线程创建的方式,继承Thread类,实现Runable接口,实现Callable接口,采用线程池;
2.线程生命周期: join():运行结束再下一个, yield():暂时让出cpu的使用权,deamon():守护线程,最后结束,sleep():如果有锁,不会让出;
3.线程3大特性,原子性,可见性,有序性;
4.list集合中线程安全问题,hash算法问题;文章来源:https://www.toymoban.com/news/detail-841500.html
总结
程序人生——Java数组和集合使用建议(2)
到了这里,关于程序人生——Java数组和集合使用建议(2)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!