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()方法将其拆分。下面通过一段代码举例

 List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
list.add(8);
list.add(9);
list.add(10);
Spliterator<Integer> sp = list.spliterator();
Spliterator<Integer> sp1 = sp.trySplit();
Spliterator<Integer> sp2 = sp.trySplit();
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]]

这里就对这几个方法的用途很明确了。

上一篇:react input 获取/失去焦点


下一篇:input实时监听控制输入框的输入内容和长度,并进行提示和反馈