集合类再探:不可变类的好处,Collector接口详解,使用内部迭代

本文探讨了Java集合类中可变与不可变的区别,强调了不可变集合在编程中的好处,例如简化编程思维、减少副作用。文章详细介绍了Collector接口及其在Java 8中的应用,如何通过Collector进行数据处理和转换,并指出标准库的局限性。此外,还讨论了外部迭代与内部迭代的转换,并提出在实际应用中,推荐使用Immutable类型以降低出错概率。
摘要由CSDN通过智能技术生成

集合类再探

注:本文使用的pom依赖见文末。

💡 集合类的基础 — Iterable、Iterator

java语言层面支持对实现了Iterable接口的对象使用for-each语句。Iterator可以实现有限流和无限流。

Collection类定义了基本的增删改查操作,转向基本数组类型(toArray),1.8引入了stream操作。

可变与不可变

不可变集合看似是限制,但是其会极大简化了编程的心理负担。

心理负担举例:

我们使用一个List对象,对其修改的操作必须小心翼翼,因为宽接口的问题,add之类的操作很可能不支持。

stream 操作在其他类库上不一定有效,因为default方法不一定适用于所有子类。

一个集合对象作为方法的入参,有可能被方法修改,而这种修改我们很难轻易地理解,需要阅读代码或者注释。一个方法不能复用常常是因为添加了过多的副作用,而这种副作用暗含其中,为我们的项目添加了一颗颗隐形炸弹。注释的产生只能说明代码设计存在一定的缺陷,优秀的代码应该减少不必要的注释,显然对于副作用,我们必须要显著说明,比如可能抛出的异常。

ImmutableList<String> list = ...
foo(list)
boo(list)
zoo(list)
doSomethingWith(list)
// 如上的几个方法互不影响,可以继续放心地使用 list
// 如果list的类型是List,这几个方法的入参很可能都不一样

💡 集合类型的创建经历了可变 → 不可变,当其不可变时,应当在代码中体现

guava 和很多其他工具类都是按照这种思想设计的:

// Guava
// builder 模式
ImmutableList<Integer> list = ImmutableList.<Integer>builder()
                .add(1)
                .add(2)
                .addAll(otherList)
                .build();
// 静态工厂
ImmutableList<Integer> list = ImmutableList.of(1, 2, 3);
// shallow copy
ImmutableList<Integer> list = ImmutableList.copyOf(new Integer[]{1, 2, 3});

💡 从类型系统上讲,不可变类型支持协变

协变的意思是对象的继承会在集合的维度上传递,不可变类型由于不支持修改,对于协变的支持理所当然。

Java不支持类定义时定义协变,只支持使用集合对象时使用通配符,所以我们能在许多方法上看到泛型通配符。

/ # Guava.ImmutableList
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
    if (elements instanceof ImmutableCollection) {
      @SuppressWarnings("unchecked") // all supported methods are covariant
      ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
      return list.isPartialView() ? ImmutableList.<E>asImmutableList(list.toArray()) : list;
    }
    return construct(elements.toArray());
  }
// elements 入参后,如果不进行修改,可以@SuppressWarnings("unchecked"),直接转换类型为不变,方便后续使用。

💡 副作用容易引起程序错误

// code1
// 请思考这段代码的运行结果
Random random = new Random();
List<Integer> list = random.ints(6L).boxed().collect(Collectors.toList());
System.out.println("list = " + list);
List<Integer> subList = list.subList(0, 3);
System.out.println("subList = " + subList);

Collections.sort(list);

System.out.println("list = " + list);
System.out.println("subList = " + subList);

// 以上代码的运行结果
/**
list = [40, 60, 28, 4, 83, 90]
subList = [40, 60, 28]
list = [4, 28, 40, 60, 83, 90]
Exception in thread "main" java.util.ConcurrentModificationException
**/
// 我们发现:subList这个变量在sort操作之后,不能使用了

// code2
Random random = new Random();
List<Integer> _list = random.ints(6L, 0, 100).boxed().collect(Collectors.toList());
ImmutableList<Integer> list = ImmutableList.copyOf(_list);
System.out.println("list = " + list);
List<Integer> subList = list.subList(0, 3);
System.out.println("subList = " + subList);

Collections.sort(list);

System.out.println("list = " + list);
System.out.println("subList = " + subList);

// 以上代码的运行结果
/**
list = [22, 34, 50, 49, 93, 49]
subList = [22, 34, 50]
Exception in thread "main" java.lang.UnsupportedOperationException
	at com.google.common.collect.ImmutableList.sort(ImmutableList.java:581)
	at java.util.Collections.sort(Collections.java:141)
**/
// 虽然编译通过了,但是 list 禁止了修改,同时由于没有直接调用list.sort()方法,在运行前我们无法获取编译的提示。
// 使用 list.~~sort~~(null); 会得到 IDEA inspection 提示,因为Immutable类的sort标注为了@Deprecate

// code3
Random random = new Random();
List<Integer> _list = random.ints(6L, 0, 100).boxed().collect(Collectors.toList());
ImmutableList<Integer> list = ImmutableList.copyOf(_list);
System.out.println("list = " + list);
List<Integer> subList = list.subList(0, 3);
System.out.println("subList = " + subList);

ImmutableList<Integer> sortedList = list.stream().sorted().collect(ImmutableList.toImmutableList());

System.out.println("list = " + l
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值