JDK8源码阅读之Collection及相关方法
最近面试总会被问到JDK8中的一些新特性,所以闲下来抽时间看了一下8的源码,目前主要看的是数据结构部分,特此记录一下。
新增函数式接口,实现该接口的可以直接用lambda表达式。
default和static关键字修饰接口中的方法,可以在方法中写实现。下方是Collection接口中实现的一个方法。
default Spliterator<E> spliterator() { return Spliterators.spliterator(this, 0); }
Collection接口新增了spliterator(),stream(),parallelStream(),removeIf()方法。
spliterator()方法返回一个Spliterator对象。看到英文应该可以想到是split+iterator的意思,顾名思义,就是用来做拆分遍历。
该对象有2个比较重要的属性值,index是起始值(包含),fence为结束值(不包含)
可以通过trySplit()方法将其拆分。下面通过一段代码举例
1 List<Integer> list = new ArrayList<Integer>(); 2 list.add(1); 3 list.add(1); 4 list.add(2); 5 list.add(3); 6 list.add(4); 7 list.add(5); 8 list.add(6); 9 list.add(7); 10 list.add(8); 11 list.add(9); 12 list.add(10); 13 Spliterator<Integer> sp = list.spliterator(); 14 Spliterator<Integer> sp1 = sp.trySplit(); 15 Spliterator<Integer> sp2 = sp.trySplit(); 16 Spliterator<Integer> sp3 = sp.trySplit();
可以通过debug查看各个对象中index和fence的值。trySplit()之后会从中间拆分,返回前半段,而把后半段保留在原对象中。
该接口的tryAdvance(Consumer action)方法,从index开始对元素进行某种操作,当还有元素未操作时,返回true,否则返回false。通常遍历时使用forEachRemaining(Consumer action);
estimateSize()方法返回还剩多少元素未处理
stream()方法返回一个Stream对象,该对象与我们之前用到的I/O流不同,是JDK8新增的一个接口。可以认为是一个更高级的iterator。该接口与IntStream,DoubleStream,IntStream都继承于BaseStream接口。最大的好处应该就是可以过滤筛选元素,不需要像之前要遍历每个元素去做筛选。
该接口有多个方法,下面介绍下各个方法的作用。
Stream<T> filter(Predicate<? super T> predicate); 根据表达式将符合表达式的元素返回。 XXXStream mapToXXX(ToXXFunction mapper):将元素按照ToXXFunction的复写方法去转换。 <R> Stream<R> map(Function<? super T, ? extends R> mapper):将元素按照Function的方法去转换 Stream flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);将集合中不同的元素结合到一起生成一个新的Stream distinct(); 去重,根据元素的equals()方法去重 sorted();排序,按照默认排序规则排序 sorted(Comparator );按照给与规则排序 peek(Consumer action);重新生成原有Stream的所有元素的Stream,并给每个元素添加一个Consumer的消费函数,每个元素执行该函数。一般用于debug时 limit(int maxSize);将Stream进行截断操作,获取前maxSize个元素。 skip(int n);返回第n个元素以后的元素,如果Stream的大小不超过n,则返回空Stream。 forEach(Consumer action);对所有元素执行action操作。 toArray();返回包含所有元素的数组 reduce(BinaryOperator<T> accumulator);根据表达式做相应的运算直到最后。 collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);将元素放入结果容器中。 min(comparator);根据给定的比较方式,返回最小的 max(comparator);同上返回最大的 count();返回元素个数 anyMatch(Predicate);判断是否有符合表达式的元素,如果为空,则返回false allMatch(Predicate);判断是否全部符合表达式,如果为空,则返回true; noneMatch(Predicate);判断是否全部不符合 findFirst();找到第一个元素,如果为空,则返回空 findAny();返回任意一个。
Stream的创建:
可以通过builder()创建Builder然后创建
Empty();返回一个空Stream
Of(T… t);返回含有传入参数的Stream。
Iterate(final T seed, UnaryOperator);以seed为基础,根据后面的响应操作表达式来添加元素,无限长度
Generate(Supplier);根据给定的方法来生成元素,无限长度
无限长度一般配合limit();使用
Concat(Stream a,Stream b);将两个Stream合并为一个,如果两个是有序的,则合并后有序,如果任意一个是并行的,则合并后并行,关闭合并的Stream则原有两个也关闭
parallelStream()方法,顾名思义,就是获取平行的Stream。
removeIf(Predicate filter)方法可以用于批量删除集合中的符合filter的元素。下面介绍一下Predicate接口。
Predicate接口我们先看一下源码中的注译:
Represents a predicate (boolean-valued function) of one argument.
这可以认为是一个判别条件,用途是用来判断所给的元素是否符合某种不表达式;
该接口有5个方法:
新建对象时需要重写该方法,在其中写相应的判断
boolean test(T t);
与操作,获取两个Predicate的与 default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); }
非操作,获取两个Predicate的非 default Predicate<T> negate() { return (t) -> !test(t); }
或操作,获取两个Predicate的或
default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); }
静态方法,返回一个Predicate,用于判断是否与传入的对象相同
static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); }
下面用一个例子来说明这几个方法:
List<Student> ls = new ArrayList<Student>(); Student s = new Student("zhangsan",25); Student s2 = new Student("lisi",30); Student s3 = new Student("wangwu",10); ls.add(s); ls.add(s2);
ls.add(s3);
//这里可以写lambda表达式 Predicate<Student> p1 = new Predicate<Student>() { @Override public boolean test(Student t) { // TODO Auto-generated method stub if(t.age>25) return true; return false; } }; Predicate<Student> p2 = p1.negate(); Predicate<Student> p3 = Predicate.isEqual(s); ls.removeIf(p1);
System.out.println(ls.toString());
上述代码的输出结果为:[Student [name=zhangsan, age=25], Student [name=wangwu, age=10]]
p1的表达式为 age>25的元素,所以只有一个元素被删除。
上面代码不动 将p1换为p2输出结果为:[Student [name=lisi, age=30]]
将p2换为p3输出结果为:[Student [name=lisi, age=30], Student [name=wangwu, age=10]]
我们将p1替换为p1.and(p3)结果为:[Student [name=zhangsan, age=25], Student [name=lisi, age=30], Student [name=wangwu, age=10]]
p1替换为p1.or(p3)结果为:[Student [name=wangwu, age=10]]
这里就对这几个方法的用途很明确了。