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]]
这里就对这几个方法的用途很明确了。
JDK8源码阅读之Collection及相关方法的更多相关文章
- JDK源码阅读之Collection
源码版本:JDK 1.7. 集合 Collection,根据已知的内容可以知道有List.Set.Map(严格说,Map不属于Collection)等大类. 先查看 Collection, publi ...
- JDK源码阅读(三) Collection<T>接口,Iterable<T>接口
package java.util; public interface Collection<E> extends Iterable<E> { //返回该集合中元素的数量 in ...
- 源码阅读之HashMap(JDK8)
概述 HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap最多只允许一条记录的键为null,允许多条记录 ...
- 源码阅读之LinkedList(JDK8)
inkedList概述 LinkedList是List和Deque接口的双向链表的实现.实现了所有可选列表操作,并允许包括null值. LinkedList既然是通过双向链表去实现的,那么它可以被当作 ...
- 源码阅读之ArrayList(JDK8)
ArrayList概述 ArrayList是一个的可变数组的实现,实现了所有可选列表操作,并允许包括 null 在内的所有元素.每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组 ...
- java8 ArrayList源码阅读
转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...
- JDK 1.8源码阅读 HashMap
一,前言 HashMap实现了Map的接口,而Map的类型是成对出现的.每个元素由键与值两部分组成,通过键可以找对所对应的值.Map中的集合不能包含重复的键,值可以重复:每个键只能对应一个值. 存储数 ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- EventBus源码解析 源码阅读记录
EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...
随机推荐
- 【spring源码分析】IOC容器初始化(二)
前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...
- 017_python常用小技巧
一.进行十六进制运算 print(hex(int("6500000001", 16) - int("640064c6e7",16))) 0xff9b391a
- C语言函数的格式
#include <stdio.h>#include <stdlib.h>extern int addf(int a,int b);//函数能多次声明//int addf(in ...
- Neutron:浮动ip
如果需要从外网直接访问 instance,则可以利用 floating IP. 下面是关于 floating IP 必须知道的事实: 1. floating IP 提供静态 NAT 功能,建立外网 ...
- vscode 打开多个标签页
默认只打开2个,按如下设置可以支持多开: 路径C:\Users\admin\AppData\Roaming\Code\User下的settings.json添加一条配置:"workbench ...
- HashMap源码分析(基于jdk8)
我们知道在jdk7中HashMap的实现方式是数组+链表.而在jdk8中,实现有所变化,使用的是数组+链表+红黑树实现的. 当链表长度达到8时转化为红黑树. static final int TREE ...
- Python两个栈实现一个队列
牛客网原题: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 实现这个算法的方式有很多种,这里就写一种比较简单易懂的:虽然可能算法和效率上不太出色,当大多数人 ...
- OpenCV4.1.0实践(3) - 图片缩放
简单的案例: (1)通过比例进行缩放 import cv2 as cv import numpy as np # 图片缩放 img = cv.imread('images/animal.jpg', f ...
- Spring 事务传播特性
Spring 事务属性一共有四种:传播行为.隔离级别.只读和事务超时 a) 传播行为定义了被调用方法的事务边界. 传播行为 意义 PROPERGATION_MANDATORY 表示方法必须运行在一 ...
- python之单例模式、栈、队列和有序字典
一.单例模式 import time import threading class Singleton(object): lock = threading.RLock() # 定义一把锁 __inst ...