集合

79 阅读9分钟

SFXUSA86FM-eyJsaWNlbnNlSWQiOiJTRlhVU0E4NkZNIiwibGljZW5zZWVOYW1lIjoi5pyd6Zm956eR5oqA5aSn5a24IiwibGljZW5zZWVUeXBlIjoiQ0xBU1NST09NIiwiYXNzaWduZWVOYW1lIjoiVGFvYmFv77ya5p6B5a6i5LiT5LqrICAtLS0g6LCo6Ziy55uX5Y2W77yBIiwiYXNzaWduZWVFbWFpbCI6IktyaXN0YW5fQmxvd2VAb3V0bG9vay5jb20iLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiJGb3IgZWR1Y2F0aW9uYWwgdXNlIG9ubHkiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IkdPIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSUzAiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRNIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJDTCIsInBhaWRVcFRvIjoiMjAyNS0wMi0xOSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNVIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU0MiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUEMiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRTIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSRCIsInBhaWRVcFRvIjoiMjAyNS0wMi0xOSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJTRiIsInBhaWRVcFRvIjoiMjAyNS0wMi0xOSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJSTSIsInBhaWRVcFRvIjoiMjAyNS0wMi0xOSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiSUkiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRQTiIsInBhaWRVcFRvIjoiMjAyNS0wMi0xOSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiREIiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRDIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQUyIsInBhaWRVcFRvIjoiMjAyNS0wMi0xOSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNWIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IldTIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQU0kiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUENXTVAiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUlMiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiRFAiLCJwYWlkVXBUbyI6IjIwMjUtMDItMTkiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUERCIiwicGFpZFVwVG8iOiIyMDI1LTAyLTE5IiwiZXh0ZW5kZWQiOnRydWV9XSwibWV0YWRhdGEiOiIwMTIwMjQwMjI2TFBBQTAwMzAwOCIsImhhc2giOiI1NDY4ODAyOS8yNTk5OTU2NTotMTQ5MzMwODg5NSIsImdyYWNlUGVyaW9kRGF5cyI6NywiYXV0b1Byb2xvbmdhdGVkIjpmYWxzZSwiaXNBdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJ0cmlhbCI6ZmFsc2UsImFpQWxsb3dlZCI6dHJ1ZX0=-JDVXZeZnNxn5sMQEXZ2TOZlrMOVI37CPE25JugHcDUdJPc75u4D+IEwoFl1GRB8GKrIhSwJa6OhgHpyXyMqLXtroe/p+qWo6kLi86iTuXpK+E4UQPQP9X9cZTxgupD4py7/Pps4qeuwiWIsbESoDDxRsuivhh1xka8lfJHoPDMwdV7DNjRFUUFpJrDr7KYp5zGRFU9hIUfh8YzZ0lQTAzboQyUwMoTRRiUOM5hs/2/RG6VA1gPaeqRaE6v0nphHTZ6By3Zvs5tj9qh6iW07jtXTxXk0MDzNrQpMh2MUvPB0dikKjDMxgUKFGEiDKvFilZJ+y0ErfdFekBn+mfInr0Q==-MIIETDCCAjSgAwIBAgIBDzANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTIyMTAxMDE2MDU0NFoXDTI0MTAxMTE2MDU0NFowHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyMjEwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/W3uCpU5M2y48rUR/3fFR6y4xj1nOm3rIuGp2brELVGzdgK2BezjnDXpAxVDw5657hBkAUMoyByiDs2MgmVi9IcqdAwpk988/Daaajq9xuU1of59jH9eQ9c3BmsEtdA4boN3VpenYKATwmpKYkJKVc07ZKoXL6kSyZuF7Jq7HoQZcclChbF75QJPGbri3cw9vDk/e46kuzfwpGftvl6+vKibpInO6Dv0ocwImDbOutyZC7E+BwpEm1TJZW4XovMBegHhWC04cJvpH1u98xoR94ichw0jKhdppywARe43rGU96163RckIuFmFDQKZV9SMUrwpQFu4Z2D5yTNqnlLRfAgMBAAGjgZkwgZYwCQYDVR0TBAIwADAdBgNVHQ4EFgQU5FZqQ4gnVc+inIeZF+o3ID+VhcEwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBANLG1anEKid4W87vQkqWaQTkRtFKJ2GFtBeMhvLhIyM6Cg3FdQnMZr0qr9mlV0w289pf/+M14J7S7SgsfwxMJvFbw9gZlwHvhBl24N349GuthshGO9P9eKmNPgyTJzTtw6FedXrrHV99nC7spaY84e+DqfHGYOzMJDrg8xHDYLLHk5Q2z5TlrztXMbtLhjPKrc2+ZajFFshgE5eowfkutSYxeX8uA5czFNT1ZxmDwX1KIelbqhh6XkMQFJui8v8Eo396/sN3RAQSfvBd7Syhch2vlaMP4FAB11AlMKO2x/1hoKiHBU3oU3OKRTfoUTfy1uH3T+t03k1Qkr0dqgHLxiv6QU5WrarR9tx/dapqbsSmrYapmJ7S5+ghc4FTWxXJB1cjJRh3X+gwJIHjOVW+5ZVqXTG2s2Jwi2daDt6XYeigxgL2SlQpeL5kvXNCcuSJurJVcRZFYUkzVv85XfDauqGxYqaehPcK2TzmcXOUWPfxQxLJd2TrqSiO+mseqqkNTb3ZDiYS/ZqdQoGYIUwJqXo+EDgqlmuWUhkWwCkyo4rtTZeAj+nP00v3n8JmXtO30Fip+lxpfsVR3tO1hk4Vi2kmVjXyRkW2G7D7WAVt+91ahFoSeRWlKyb4KcvGvwUaa43fWLem2hyI4di2pZdr3fcYJ3xvL5ejL3m14bKsfoOv

1 ArrayList在循环过程中删除,会不会出现问题。

方式一

List<String> list = new ArrayList<>(Arrays.asList("aa", "bb", "bb", "cc"));
for(int i = 0; i < list.size(); i++){
	if("bb".equals(list.get(i))){
		list.remove(i);
	}
}

问题:结果不正确,数据索引变了导致第2个“bb”没有移除

方式二

List<String> list = new ArrayList<>(Arrays.asList("aa", "bb", "bb", "cc"));	
for(String str : list){
	if("bb".equals(str)){
		list.remove(str);
	}
}

问题:报错java.util.ConcurrentModificationException 分析:增强for循环是Java给我们提供的一个语法糖,如果将以上代码进行反编译(使用jad工具)的话,可以得到以下代码:

Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
	String str = iterator.next();
	if("bb".equals(str)){
		list.remove(str);
	}		
}

Iterator.next 调用了 Iterator.checkForComodification方法 ,而异常就是checkForComodification方法中抛出的。

final void checkForComodification() {
    if (modCount != expectedModCount){
        throw new ConcurrentModificationException();
	}
}

根本原因:通过分析arrayList的源码,调用remove方法时,只修改了modCount,导致modCount和expectedModCount不相等抛出异常,即集合遍历是通过iterator进行的,但是元素的add/remove却是直接使用的集合类自己的方法,这就导致iterator在遍历的时候,会发现有一个元素在自己不知不觉的情况下就被删除/添加了,就会抛出一个异常,用来提示用户,可能发生了并发修改。

方式三

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
	if ("bb".equals(iterator.next())) {
   	iterator.remove();
	}
}

正常删除,推荐使用。通过iterator.remove()方式,会同时修改modCount和expectedModCount,不会抛异常。

方式四

List<String> list = new ArrayList<String>(Arrays.asList("a", "a", "b", "c"));
list = list.stream().filter(str -> !str.equals("a")).collect(Collectors.toList());

Arrays.asList使用遇到的问题。

List<String> list = Arrays.asList("aa", "bb", "bb", "cc");
list.add("hh");
list.remove("aa");
list.clear();

问题:运行代码,抛出java.lang.UnsupportedOperationException 原因:Arrays.asList使用的ArrayList是Arrays的内部类,并不是我们平时用的ArrayList。查看AbstractList方法,可以看到抛出异常的地方。

@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
	return new ArrayList<>(a);
}

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
{
	...
}

2 为什么编码规范要求谨慎使用ArrayList中的subList方法

List<String> sourceList = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> sublist = sourceList.subList(0, 3);
sourceList.remove("a");

问题:运行代码,抛出java.util.ConcurrentModificationException 原因:SubList为ArrayList的内部类,返回的是SubList,是原List的视图,而不是ArrayList,

public List<E> subList(int fromIndex, int toIndex) {
	subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

private class SubList extends AbstractList<E> implements RandomAccess {
	...
}

视图和原List的修改会相互影响,需要注意几点: 1、对父(sourceList)子(subList)List做的非结构性修改(如set),都会影响到彼此。 2、对子List做结构性修改(如add/remove),操作同样会反映到父List上。 3、对父List做结构性修改(如add/remove),会抛出异常ConcurrentModificationException。

3 快速失败和安全失败

快速失败:集合迭代时,next()等方法调用时会检查集合被修改次数modCount是否等于expectedmodCount, 如果迭代过程中集合被修改(并发情况下),比如remove操作,只修改了modCount,导致这两个值不相等,会抛出ConcurrentModificationException异常 java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改。

安全失败:先复制集合内容,对拷贝的集合进行遍历。 java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

Set:元素唯一 HashSet:哈希结构,添加删除效率高,时间复杂度O(1) TreeSet:红黑树结构,有序,添加删除时间复杂度O(logn)

java集合类框架的最佳实践 如果容量固定,选择Array而不是ArrayList 使用泛型 d接口入参出参,定义为接口要优于具体的实现类 返回集合为空,返回长度为0的集合,不要返回null

4 HashMap的源码、实现原理。

  • 数据结构:数组+链表,Entry<K,V>[]
  • 优点:查询快
  • put(k,V):根据key计算hashcode,根据 hashcode 定位出所在桶。 如果桶是一个链表,则需要遍历判断key是否和传入 key 相等,如果相等则进行覆盖,不相等则在链表头部插入(JDK8是尾部?)。
  • get(k):根据key计算hashcode,根据 hashcode 定位出所在桶。 如果桶是一个链表,则需要遍历判断key是否和传入 key 相等,如果相等则返回。

5 JDK8对HashMap做了怎样的优化。

  • JDK7存在的问题:当 Hash 冲突严重时,在桶上形成的链表会变的越来越长,这样在查询时的效率就会越来越低;时间复杂度为 O(N)。
  • 优化:引入红黑树,当链表的大小大于设定的阈值时,就转换为红黑树,查询效率提高到 O(logn)。

6 HashMap在并发使用时可能会出现死循环?死循环是如何产生的

往HashMap中做put操作时,扩容时会调用transfer(),并发操作容易在一个桶上形成环形链表。 当获取一个不存在的 key 时,计算出的 index 正好是环形链表的下标就会出现死循环。 juejin.im/post/5a66a0…

7 HaspMap扩容是怎样扩容的,为什么都是2的N次幂的大小。

HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,当容量是2的n次幂时,可以使得添加的元素均匀分布在HashMap的数组上,减少hash碰撞,避免形成链表的结构。 元素的存放位置index=hash(key)& (table.length()-1),以容量为16和15为例。 容量为16: 1111&1001=1001 1111&1000=1000 容量为15:更容易产生哈希碰撞 1110&1001=1000 1110&1000=1000 当数组长度为15的时候,hash(key)与14(1110)进行“与”,那么最后一位永远是0,而0001,0011,0101,1001,1011,0111,1101这几个位置永远都不能存放元素了,空间浪费相当大,而且这种情况下数组可以使用的位置比数组长度小了很多,增加了碰撞的几率,减慢了查询的效率。 blog.csdn.net/belalds/art…

8 ConcurrentHashMap 是如何实现的? 1.7、1.8 实现有何不同?为什么这么做?

9 当key或value为null时,HashMap、HashTable如何处理的?

HashMap 支持key为null,put的时候放在table[0]的位置 支持key为null,不需要特别处理 HashTable key为null,代码key.hashCode()会报空指针 value为null,put的时候有如下判空,直接抛出空指针 if (value == null) { throw new NullPointerException(); }