集合类:Java7和Java8中集合类差异


Java8在Java7的基础上对集合类进行了改进和优化,但是使用过程与Java7并没有什么不同,这一点是值的学习借鉴的。

1. 通用区别

Map、Set和List在Java8中均添加了forEach方法,该方法的入参是Consumer,一个函数式接口,可以简单理解为允许一个入参,但没有返回值的函数式接口。函数式接口会在以后的lambda表达式时候讲解。

@override
public void forEach(Consumer<? super E> action) {
	// 判断非空
	Objects.requireNonNull(action);
	// modCount的原始值被拷贝,用于判断在方法执行过程中数组是否被修改
	final int expectedModCount = modCount;
	final E[] elementData = (E[]) this.elementData;
	final int size = this.size;
	// 每次循环都会判断数组有没有被修改,一旦被修改,停止循环
	for (int i=0; modCount == expectedModCount && i < size; i++) {
		// 执行循环内容,action 代表要干的事情
		action.accept(elementData[i]);
	}
	// 数组如果被修改了,抛异常
	if (modCount != expectedModCount) {
		throw new ConcurrentModificationException();
	}
}
  1. action.accept的含义
    action.accept就是在for循环中要做的事情,可以是任何事情,如
public void testForEach(){
	List<Integer> list = new ArrayList<Integer>(){{
		add(1);
		add(3);
		add(2);
		add(4);
	}};
	// value 是每次循环的入参,就是 list 中的每个元素
	list.forEach( value->log.info("当前值为:{}",value));
}

此时,action.accept就是括号中要打印的语句,执行结果为,

当前值为:1
当前值为:3
当前值为:2
当前值为:4

log.info(“当前值为:{}”,value)就是action。

  1. forEach方法上有@override标记,说明该方法是对父类方法的复写,该方法被定义在Iterable接口上。Java7和8中ArrayList都实现了该接口,但是在Java7中并没有实现该方法。源码中,该方法使用default关键字进行修饰,这个关键字值会出现在接口类中,被该关键字修饰的方法不会强制子类对其进行实现。
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

2.List区别

Java7在初始化List时,直接创建容量为10的数组。而Java8中,初始化时是空数组,在第一次调用add方法后才会对数组进行初始化。
image
其余地方没有修改。

3.Map区别

HashMap的区别

  1. 与List一样,在初始化时先不对底层数组进行初始化
  2. Java8的hash算法更加简单
  3. Java8在HashMap中引入了红黑树。如果使用Java的API,如String、Integer等作为key时,这些API的hashCode实现十分完美,很少出现链表转为红黑树的情况。只有当key是自定义的类且复写的hashCode方法十分糟糕时,大量的hash冲突会迫使链表转为红黑树,用于提升效率。
    所以Java8的相当于重写了Java7的HashMap。
  4. 新增getOrDefault、putIfAbsent、compute和computeIfPresent方法。
public void compute(){
	HashMap<Integer,Integer> map = Maps.newHashMap();
	map.put(10,10);
	log.info("compute 之前值为:{}",map.get(10));
	map.compute(10,(key,value) -> key * value);
	log.info("compute 之后值为:{}",map.get(10));
	// 还原测试值
	map.put(10,10);
	
	// 如果为 11 的 key 不存在的话,需要注意 value 为空的情况,下面这行代码就会报空指针
	map.compute(11,(key,value) -> key * value);
	
	// 为了防止 key 不存在时导致的未知异常,我们一般有两种办法
	// 1:自己判断空指针
	map.compute(11,(key,value) -> null == value ? null : key * value);
	// 2:computeIfPresent 方法里面判断
	map.computeIfPresent(11,(key,value) -> key * value);
	log.info("computeIfPresent 之后值为:{}",map.get(11));
}

这些新增的方法能够很好的解决空指针的问题。

LinkedHashMap

由于HashMap被重写,导致LinkedHashMap调用HashMap方法时的代码也进行了修改。

总结

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值