最近面试总会被问到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]]

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

JDK8源码阅读之Collection及相关方法的更多相关文章

  1. JDK源码阅读之Collection

    源码版本:JDK 1.7. 集合 Collection,根据已知的内容可以知道有List.Set.Map(严格说,Map不属于Collection)等大类. 先查看 Collection, publi ...

  2. JDK源码阅读(三) Collection<T>接口,Iterable<T>接口

    package java.util; public interface Collection<E> extends Iterable<E> { //返回该集合中元素的数量 in ...

  3. 源码阅读之HashMap(JDK8)

    概述 HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap最多只允许一条记录的键为null,允许多条记录 ...

  4. 源码阅读之LinkedList(JDK8)

    inkedList概述 LinkedList是List和Deque接口的双向链表的实现.实现了所有可选列表操作,并允许包括null值. LinkedList既然是通过双向链表去实现的,那么它可以被当作 ...

  5. 源码阅读之ArrayList(JDK8)

    ArrayList概述 ArrayList是一个的可变数组的实现,实现了所有可选列表操作,并允许包括 null 在内的所有元素.每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组 ...

  6. java8 ArrayList源码阅读

    转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...

  7. JDK 1.8源码阅读 HashMap

    一,前言 HashMap实现了Map的接口,而Map的类型是成对出现的.每个元素由键与值两部分组成,通过键可以找对所对应的值.Map中的集合不能包含重复的键,值可以重复:每个键只能对应一个值. 存储数 ...

  8. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

  9. EventBus源码解析 源码阅读记录

    EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...

随机推荐

  1. 《JAVA程序设计》_第六周学习总结

    一.本周学习内容 1.内部类--7.1知识 在一个类的内部定义的类成为内部类,包含内部类的类叫做外嵌类 内部类和外嵌类的关系 外嵌类的成员变量在内部类中仍然有效,内部类也可调用外嵌类中的方法 内部类的 ...

  2. day20 hashlib、hmac、subprocess、configparser模块

    hashlib模块:加密 import hashlib# 基本使用cipher = hashlib.md5('需要加密的数据的二进制形式'.encode('utf-8'))print(cipher.h ...

  3. (n)e(m)

    经常会看到类似于 1e30 9e5 类似的表达式 (我一个蒟蒻不懂啊) 于是 给自己解释解释 那么 nem就是 n乘以10的m次方 (哈哈哈哈,我简直是太弱了)

  4. Core官方DI解析(2)-ServiceProvider

    ServiceProvider ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServ ...

  5. [转帖]Shell脚本中的break continue exit return

    Shell脚本中的break continue exit return 转自:http://www.cnblogs.com/guosj/p/4571239.html break结束并退出循环 cont ...

  6. Flutter获取屏幕宽高和Widget大小

    我们平时在开发中的过程中通常都会获取屏幕或者 widget 的宽高用来做一些事情,在 Flutter 中,我们可以使用如下方法来获取屏幕或者 widget 的宽高. MediaQuery 一般情况下, ...

  7. jmeter压测数据库,抓包工具,python基础

    jmeter压力测试 前提场景的设置:单场景(单个接口进行压力测试一个请求)或混合场景(有业务流程的场景进行压力测试多个请求),压测时间一般在5--1515分组具体看需求. 数据准备:数据量少和数据量 ...

  8. 使用ffmpeg将Mp4转gif

    视频转动图,是个强需求,家大业大的微博相册只可上传图片,进而基于微博相册的生态也是如此.目前,网络上有许多转换.压缩的网站,多数执行速度慢或者收费,体验较差. ffmpeg是一个开源的音频处理软件,支 ...

  9. magento 2 method config

    1. 模板渲染静态文件: <?php echo $this->getViewFileUrl('requirejs::require.js'); ?> 2.

  10. 快速傅里叶变换FFT& 数论变换NTT

    相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...