本文通过BaseStream和它的子接口,IntStream和Stream
BaseStream是java8 java.util.stream包下的接口,IntStream和Stream是BaseStream的子接口
目录
Stream API的特性
stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
stream不会改变数据源,通常情况下会产生一个新的集合;
stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
对stream操作分为终端操作和中间操作。
终端操作:会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
中间操作:中间操作会产生另一个流。
stream不可复用,对一个已经进行过终端操作的流再次调用,会抛出异常。
先上图:
父接口BaseStream的方法
两个泛型:T 用来指定流中存储数据的类型;S 另一个流的类型;
其中的close()方法就不用介绍了,是AutoCloseable接口中的方法。
方法名 | 解释 |
---|---|
boolean isParallel() | 如果调用的是一个并行流返回true,如果调用的是一个顺序流返回false; |
Iterator<T> iterator() | 获得流迭代器,并返回对该迭代器的引用(终端操作) |
S onClose(Runnable closeHandler) | 和close()有关,这里不介绍 |
S parallel() | 基于调用流,返回一个并行流(中间操作) |
S sequential() | 基于调用流,返回一个顺序流 (中间操作) |
Spliterator<T> spliterator() | 获取流的Spliterator ,并返回它的引用(终端操作) |
S unordered() | 基于调用流,返回一个无序流,非并行流(中间操作) |
代码演示:
iterator方法
用来串行的遍历流中的元素
int[] arr1 = {1,2,34,5};
BaseStream<Integer, IntStream> is = Arrays.stream(arr1);
Iterator it = is.iterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
运行结果:
1 2 34 5
spliterator方法
用来并行的遍历流中的元素
简单介绍一下用到的Spliterator接口中的方法:
方法名 | 介绍 |
---|---|
Spliterator trySplit() | 如果这个spliterator可以被分区,则返回一个包含元素的spliterator |
boolean tryAdvance(Consumer<? super T> action) | 如果存在剩余元素,则对其执行给定操作,返回true;否则返回false。 |
public static void main(String[] args) {
int[] arr2 = {1,2,3,4,5,6,7,8,9,10};
BaseStream<Integer, IntStream> is = Arrays.stream(arr2);
Spliterator<Integer> sit= is.spliterator();
Spliterator<Integer> sit1 = sit.trySplit();
Spliterator<Integer> sit2 = sit.trySplit();
Thread t = new Thread( () -> {
while(sit.tryAdvance(x -> System.out.println("sit :" + x))){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
});
Thread t1 = new Thread( () -> {
while(sit1.tryAdvance(x -> System.out.println("sit1 :" + x))){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
});
Thread t2 = new Thread( () -> {
while(sit2.tryAdvance(x -> System.out.println("sit2 :" + x))){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
});
t.start();
t1.start();
t2.start();
}
运行结果:
sit2 :6
sit1 :1
sit :8
sit1 :2
sit2 :7
sit :9
sit1 :3
sit :10
sit1 :4
sit1 :5
可以看到sit流中的数据{1,2,3,4,5,6,7,8,9,10}被分为sit1{1,2,3,4,5};sit2{6,7}和自己剩余的sit{8,9,10};
unordered
有时候取消流的顺序约束可以提高执行效率
打印有序流和无序流
Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().forEach(x -> System.out.print(x + " "));
System.out.println("\n");
Stream.of(5, 1, 2, 6, 3, 7, 4).unordered().parallel().forEach(x -> System.out.print(x + " "));
运行结果:
5 1 2 6 3 7 4
3 6 4 7 5 2 1
IntStream和Stream都有的方法
以Stream为示
静态方法 | 介绍 |
---|---|
static <T> Stream.Builder<T> builder() | 一个用于Stream的可变生成器。 |
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) | 创建一个连接流,其元素为第一个流的所有元素,然后是第二个流的所有元素。 |
static <T> Stream<T> empty() | 返回一个空的顺序流 |
static <T> Stream<T> generate(Supplier<T> s) | 生成一个无限长度的无序流,这适用于生成恒定流和随机元素流。 |
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) | 返回一个无限长度的有序流,该流由函数f迭代应用到初始元素种子产生,产生一个由seed、f(seed)、f(f(seed))等组成的流。 |
static <T> Stream<T> of(T… values) | 返回一个顺序流,其元素为指定的值 |
static <T> Stream<T> of(T t) | 返回一个包含单个元素的顺序流。 |
方法 | 介绍 |
---|---|
Stream<T> filter(Predicate<? super T> predicate) | Predicate接口是返回每个元素是否满足条件,filter函数将调用流中不满足条件的元素删去,返回一个新的流 |
<R> Stream<R> map(Function<? super T,? extends R> mapper) | 返回一个流,该流由对该流的元素应用给定函数的结果组成。 |
IntStream mapToInt(ToIntFunction<? super T> mapper) | 返回一个IntStream,该IntStream由将给定函数应用于该流元素的结果组成。 |
<U> Stream<U> mapToObj(IntFunction<? extends U> mapper) | 返回一个对象值流,该流由对该流的元素应用给定函数的结果组成。 |
mapToLong、mapToDouble | 不再介绍 |
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) | 返回一个流,该流由对该流的元素应用给定函数的结果的多个流拼接组成。 |
Stream<T> distinct() | 返回由该流的不同元素组成的流(根据Object.equals(Object))。 |
Stream<T> sorted() | 返回一个由该流的元素组成的流,按自然顺序排序。 |
Stream<T> peek(Consumer<? super T> action) | 返回由该流的元素组成的流,另外,在使用结果流中的元素时对每个元素执行提供的操作。 |
Stream<T> limit(long maxSize) | 返回由该流的前maxSize元素组成的流 |
Stream<T> skip(long n) | 在丢弃流的前n个元素后,返回由该流的剩余元素组成的流。 |
void forEach(Consumer<? super T> action) | 对流的每个元素执行一个操作。(终端操作) |
void forEachOrdered(Consumer<? super T> action) | 对流的每个元素执行一个操作,如果流有定义的相遇顺序,则按流的相遇顺序执行。 |
Object[] toArray() | 返回包含此流元素的数组。 |
reduce() | 使用关联累积函数对该流的元素执行缩减,并返回描述缩减值的可选值(如果有的话)。有三个重载,具体可参见这篇文章,这里就不在描述 |
<R,A> R collect(Collector<? super T,A,R> collector) | 使用收集器对该流的元素执行可变的缩减操作。下面的flatMap的代码中也用到了collect方法。具体可参见这篇文章 |
Optional<T> min(Comparator<? super T> comparator) | 根据提供的比较器返回流中的最小元素。 |
Optional<T> max(Comparator<? super T> comparator) | 根据提供的比较器返回该流的最大元素。 |
long count() | 返回此流中元素的计数。 |
boolean anyMatch(Predicate<? super T> predicate) | 返回此流的任何元素是否与提供的谓词匹配。 |
boolean allMatch(Predicate<? super T> predicate) | 返回此流的所有元素是否与提供的谓词匹配。 |
boolean noneMatch(Predicate<? super T> predicate) | 返回此流的任何元素是否与提供的谓词匹配。既就是anyMatch的值取反 |
Optional<T> findFirst() | 返回描述流的第一个元素的Optional实例,如果流为空则返回空Optional实例。 |
Optional<T> findAny() | 返回描述流的任意一个元素的Optional实例,如果流为空则返回空Optional实例。 |
其中mapToObj和mapToInt是两者互转的方法,并不是两个接口都有,只是放在一起说明而已
各种接口
- Supplier接口
Supplier s = new Supplier() {
@Override
public Object get() {
return null;
}
}
- UnaryOperator接口:
UnaryOperator u = new UnaryOperator() {
@Override
public Object apply(Object o) {
return null;
}
}
- Predicate接口
Predicate p = new Predicate() {
@Override
public boolean test(Object o) {
return false;
}
}
- Function接口
Function f = new Function() {
@Override
public Object apply(Object o) {
return null;
}
}
- ToIntFunction接口
ToIntFunction t = new ToIntFunction() {
@Override
public int applyAsInt(Object value) {
return 0;
}
}
- IntFunction接口
IntFunction i = new IntFunction() {
@Override
public Object apply(int value) {
return null;
}
}
- Consumer 接口
Consumer c = new Consumer() {
@Override
public void accept(Object o) {
}
}
- Collector接口
Collector c = new Collector() {
@Override
public Supplier supplier() {
return null;
}
@Override
public BiConsumer accumulator() {
return null;
}
@Override
public BinaryOperator combiner() {
return null;
}
@Override
public Function finisher() {
return null;
}
@Override
public Set<Characteristics> characteristics() {
return null;
}
}
- Comparator 接口
Comparator c = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
代码示例(以Stream为示):
builder静态方法
build()方法是Builder内部接口中的方法,将Builder的对象转换成stream对象。
add()方法也是Builder内部接口中的方法,在Builder的对象中添加元素。
public static void main(String[] args) throws InterruptedException {
Stream.Builder<String> builder = Stream.builder();
Stream<String> stream = builder.add("GEEKS")
.add("for")
.add("Geeks")
.add("GeEKSQuiz")
.build();
System.out.println(Arrays.toString(stream.toArray()));
}
运行结果:
[GEEKS, for, Geeks, GeEKSQuiz]
generate静态方法
参数是Supplier接口的实现,只有一个get()方法,无参数,返回值为Supplier申明的泛型。
打印5个10以内的整数随机数。
public static void main(String[] args) {
Stream.generate(() -> new Random().nextInt(10))
.limit(5).forEach(x -> System.out.print(x + " "));
}
输出结果:
3 3 0 8 5
打印10个相同数字
public static void main(String[] args) {
Stream.generate(() -> 100).limit(5).forEach(x -> System.out.print(x + " "));
}
输出结果:
100 100 100 100 100
iterate静态方法、filter方法和map方法
打印0以后的10个奇数
public static void main(String[] args) {
Stream.iterate(0, n -> n + 1)
.filter(x -> x % 2 != 0) //odd
.limit(10)
.forEach(x -> System.out.print(x + " "));
}
运行结果:
1 3 5 7 9 11 13 15 17 19
打印从0开始的斐切那波数列的前20项
public static void main(String[] args) {
Stream.iterate(new int[]{0, 1}, n -> new int[]{n[1], n[0] + n[1]})
.limit(20)
.map(n -> n[0])
.forEach(x -> System.out.print(x + " "));
}
运行结果:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
flatMap方法和map方法
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
list1.add(1);list1.add(2);list1.add(3);
list2.add(4);list2.add(5);
List<List<Integer>> lists = new ArrayList<>();
lists.add(list1);lists.add(list2);
Stream stream = lists.stream().flatMap(new Function<List<Integer>, Stream<?>>() {
@Override
public Stream<?> apply(List<Integer> integers) {
return integers.stream();
}
});
Stream stream1 = lists.stream().map(new Function<List<Integer>, Stream<?>>() {
@Override
public Stream<?> apply(List<Integer> integers) {
return integers.stream();
}
});
System.out.println(stream1.collect(Collectors.toList()));
System.out.println(stream.collect(Collectors.toList()));
}
运行结果:
[java.util.stream.ReferencePipeline $ Head@4dd8dc3, java.util.stream.ReferencePipeline $Head@6d03e736]
[1, 2, 3, 4, 5]
可以看到,flatMap可以将List中的元素即List中的List转换为流然后将他们拼接成了一个流。
map处理的是List的中的元素,并没有把处理后的Stream拼接起来。
peek方法
在使用结果流中的元素时对每个元素执行提供的操作。
这样解释是因为peek是一个中间操作,单独调用并不会执行。需要调用终端操作时发生作用。
forEach和forEachOrdered比较
List<String> strs = Arrays.asList("a", "b", "c");
strs.stream().forEachOrdered(System.out::print);//abc
System.out.println();
strs.stream().forEach(System.out::print);//abc
System.out.println();
strs.parallelStream().forEachOrdered(System.out::print);//abc
System.out.println();
strs.parallelStream().forEach(System.out::print);//bca
anyMatch方法
找stream流中是否存在2
Stream<Integer> stream = Stream.of(1,1,1,3,1,5,6,1);
System.out.println(stream.anyMatch(x -> x == 2));
IntStream中的方法
静态方法 | 介绍 |
---|---|
static IntStream range(int startInclusive, int endExclusive) | 返回一个顺序有序的IntStream,从startInclusive(包括)到endExclusive(不包括),逐步递增1。 |
static IntStream rangeClosed(int startInclusive, int endInclusive) | 返回一个顺序有序的IntStream,从startInclusive(包括)到endExclusive(包括),逐步递增1。 |
方法 | 介绍 |
---|---|
OptionalDouble average() | 返回描述流中元素算术平均值的OptionalDouble,如果流为空则返回empty Optional。 |
IntSummaryStatistics summaryStatistics() | 返回一个IntSummaryStatistics,描述关于这个流元素的各种汇总数据。 |
LongStream asLongStream() | 返回由该流的元素组成的LongStream,并将元素类型转换为long。 |
DoubleStream asDoubleStream() | 返回由该流的元素组成的DoubleStream,并将元素类型转换为double。 |
Stream<Integer> boxed() | 返回一个由该流的元素组成的流,每个元素都被装箱为一个Integer。 |