java流Stream

前言

Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作,类图如下
在这里插入图片描述

BaseStream

public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable
泛型含义: T 是流中元素的类型, S 是BaseStream的实现

void close() //关闭流,会导致上述方法中所有的closeHandler调用。

Iterator<T> iterator() //该方法返回流中元素的迭代器,泛型就是T(流中元素的类型)

Spliterator<T> spliterator() //该方法返回流中元素的分割迭代器,泛型就是T(流中元素的类型)

boolean isParallel() //该方法返回流是否是并行流(流中元素的类型),必须在终止操作之前调用此方法,否则会造成超出预期的结果。

S sequential() //该方法返回的是S,上述解释S就是一个新的Stream,新Stream的元素仍然是T,如果已经是串行的流调用此方法则返回本身。

S parallel() //同上述方法一致,此方法返回的流是并行流。

//该方法返回的是S,上述解释S就是一个新的Stream,新Stream的元素仍然是T。
//新流是无序的,如果旧流本身是无序的或者已经设置为无序,则
//新流就是旧流本身。
S unordered() 

Stream

1.创建Stream
static <T> Stream<T> empty() 返回空序列Stream。

static <T> Stream<T> of(T t) 返回Stream包含单个元素的顺序。

static <T> Stream<T> of(T... values)返回其元素为指定值的顺序有序流。

static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)拼接2个流

static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)

static <T> Stream<T> generate(Supplier<T> s)返回无限顺序无序流,其中每个元素由提供的生成Supplier。

static <T> Stream.Builder<T>builder()返回a的构建器Stream。
2.统计函数
Optional<T> max(Comparator<? super T> comparator)根据提供的内容返回此流的最大元素 Comparator。

Optional<T> min(Comparator<? super T> comparator)根据提供的内容返回此流的最小元素 Comparator。

long count()返回此流中元素的数量。

案例:使用 Stream 查找最短曲目

List<Track> tracks = asList(new Track("Bakai", 524),new Track("Violets for Your Furs", 378), new Track("Time Was", 451)); 

Track shortestTrack = tracks.stream().min(Comparator.comparing(track -> track.getLength())) .get();
3.对象流变成数值流
DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)
IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper)
LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper)
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)
IntStream mapToInt(ToIntFunction<? super T> mapper)
LongStream mapToLong(ToLongFunction<? super T> mapper)
4.加工函数
<R> Stream<R> map(Function<? super T,? extends R> mapper)
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

map和faltMap的共同点和区别

1、共同点
都是依赖FuncX(入参,返回值)进行转换(将一个类型依据程序逻辑转换成另一种类型,根据入参和返回值)都能在转换后直接被subscribe

2、区别

map返回的是结果集,flatmap返回的是包含结果集的Observable(返回结果不同)

map被订阅时每传递一个事件执行一次onNext方法,flatmap多用于多对多,一对多,再被转化为多个时,一般利用from/just进行一一分发,被订阅时将所有数据传递完毕汇总到一个Observable然后一一执行onNext方法(执行顺序不同)>>>>(如单纯用于一对一转换则和map相同)map只能单一转换,单一只的是只能一对一进行转换,指一个对象可以转化为另一个对象但是不能转换成对象数组(map返回结果集不能直接使用from/just再次进行事件分发,一旦转换成对象数组的话,再处理集合/数组的结果时需要利用for一一遍历取出,而使用RxJava就是为了剔除这样的嵌套结构,使得整体的逻辑性更强。)flatmap既可以单一转换也可以一对多/多对多转换,flatmap要求返回Observable,因此可以再内部进行from/just的再次事件分发,一一取出单一对象(转换对象的能力不同)

3、案例

假如我们有这样一个需求给定单词列表[“Hello”,“World”],你想要返回列表[“H”,“e”,“l”, “o”,“W”,“r”,“d”],

对于这样的需求,我们可能想到的第一个版本可能是这样子的:

words.stream().map(word -> word.split("")).distinct().collect(toList());

这个方法的问题在于,传递给map方法的Lambda为每个单词返回了一个String[](String列表)。因此, map 返回的流实际上是Stream 类型的。你真正想要的是用Stream来表示一个字符流。因此,这是行不通的。

String[]strings={"Hello","World"};	


List streamList1 = Arrays.asList(strings).stream()
                                         .map(str->str.split(""))
                                         .map(strings1->Arrays.stream(strings1))
                                         .collect(Collectors.toList());
System.out.println(streamList1);//[java.util.stream.ReferencePipeline$Head@1d81eb93,java.util.stream.ReferencePipeline$Head@7291c18f]

ListstreamList2=Arrays.asList(strings).stream()
                                      .map(str->str.split(""))
                                      .flatMap(strings1->Arrays.stream(strings1))
                                      .collect(Collectors.toList());

System.out.println(streamList2);[H,e,l,l,o,W,o,r,l,d]

flatMap的总结:这个在这里的主要作用是对流进行扁平化</stream</stream</stream

5.聚合函数
Optional<T> reduce(BinaryOperator<T> accumulator)

T reduce(T identity, BinaryOperator<T> accumulator)

<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

案例

int count = Stream.of(1, 2, 3) .reduce(0, (acc, element) -> acc + element);
System.out.println(count);//6
int count = Stream.of(1, 2, 3) .reduce(1, (acc, element) -> acc + element);
System.out.println(count);//7

在这里插入图片描述

上面代码展示了这一过程。Lambda 表达式就是 reducer,它执行求和操作,有两个 参数:传入 Stream 中的当前元素和 acc。将两个参数相加,acc 是累加器,保存着当前的 累加结果。

identity: 一个初始化的值;这个初始化的值其类型是泛型U,与Reduce方法返回的类型一致;注意此时Stream中元素的类型是T,与U可以不一样也可以一样,这样的话操作空间就大了;不管Stream中存储的元素是什么类型,U都可以是任何类型,如U可以是一些基本数据类型的包装类型Integer、Long等;或者是String,又或者是一些集合类型ArrayList等;后面会说到这些用法。

accumulator: 其类型是BiFunction,输入是U与T两个类型的数据,而返回的是U类型;也就是说返回的类型与输入的第一个参数类型是一样的,而输入的第二个参数类型与Stream中元素类型是一样的。

combiner: 其类型是BinaryOperator,支持的是对U类型的对象进行操作;第三个参数combiner主要是使用在并行计算的场景下;如果Stream是非并行时,第三个参数实际上是不生效的。

因此针对这个方法的分析需要分并行与非并行两个场景。

案例

System.out.println(Stream.of(1,2,3).parallel().reduce(4,(a,b)->a+b,(c,d)->c*d));//210

System.out.println(Stream.of(1,2,3).parallel().reduce(4,(a,b)->a+b,(c,d)->c+d));//18

System.out.println(Stream.of(1,2,3).reduce(4,(a,b)->a+b,(c,d)->c*d));//10

System.out.println(Stream.of(1,2,3).reduce(4,(a,b)->a+b,(c,d)->c+d));//10

为什么并行时结果是210,而串行结果是10呢?现在我们分析他们的过程

串行过程:累加器初始值是4,执行 4+1 = 5 累加器值是5,执行 5+2=7 累加器值是7,执行 7+3=10,所以结果是10

并行过程1 :

猜测初始值4是存储在一个变量result中的;并行计算时,线程之间没有影响,因此每个线程在调用第二个参数BiFunction进行计算时,直接都是使用result值当其第一个参数(由于Stream计算的延迟性,在调用最终方法前,都不会进行实际的运算,因此每个线程取到的result值都是原始的4),因此计算过程现在是这样的:线程1:1 + 4 = 5;线程2:2 + 4 = 6;线程3:3 + 4 = 7;Combiner函数: 5 * 6 * 7 = 210

并行过程2 :

猜测初始值4是存储在一个变量result中的;并行计算时,线程之间没有影响,因此每个线程在调用第二个参数BiFunction进行计算时,直接都是使用result值当其第一个参数(由于Stream计算的延迟性,在调用最终方法前,都不会进行实际的运算,因此每个线程取到的result值都是原始的4),因此计算过程现在是这样的:线程1:1 + 4 = 5;线程2:2 + 4 = 6;线程3:3 + 4 = 7;Combiner函数: 5 + 6 + 7 = 18

6.数组化
Object[] toArray()

<A> A[] toArray(IntFunction<A[]> generator)

发现 java 使用 stream 时,经常会将 map 后的数据输入到数组中,这时一般在 stream 语句后面 加上 toArray().
若是对象数组,则要在 toArray 里面加上 生产对象数组的方法引用。

例如:

Integer 数组: toArray(Integer[] :: new).

person 数组: toArray(person[] ::  new)
7.去重 截断 忽略
Stream<T> distinct()

Stream<T> limit(long maxSize)

Stream<T> skip(long n)//超过集合长度返回空,不会影响集合

案例1

List<Integer> list = Arrays.asList(1,1,2,2,3,3,4,4);
		
list.stream().distinct().forEach(System.out::print); //1234

返回由此流的元素组成的流,截断为不超过maxSize长度。

案例2

List<Integer>list=Arrays.asList(1,1,2,2,3,3,4,4);
		
list.stream().limit(2).forEach(System.out::print);// 11
		
list.stream().limit(3).forEach(System.out::print);//112

总结:maxSize表示,改从左往右应该保留多少数据

案例3

List<Integer>list=Arrays.asList(1,1,2,2,3,3,4,4);
		
list.stream().skip(2).forEach(System.out::print);// 223344
		
list.stream().skip(3).forEach(System.out::print);//23344		

总结:n表示,改从左往右应该丢弃多少数据

8.过滤
Stream<T> filter(Predicate<? super T> predicate)

假设要找出一组字符串 中以数字开头的字符串,比如字符串 “1abc” 和 “abc”,其中 “1abc” 就是符合条件的字符串。 可以使用一个 for 循

环,内部用 if 条件语句判断字符串的第一个字符来解决这个问题,代 码如例 3-10 所示。

例 3-10 使用循环遍历列表,使用条件语句做判断

List<String> beginningWithNumbers = new ArrayList<>(); 

for(String value : asList("a", "1abc", "abc1")) { 

        if (isDigit(value.charAt(0))) { 
        
                beginningWithNumbers.add(value); 
        } 
} 

你可能已经写过很多类似的代码:这被称为 filter 模式。该模式的核心思想是保留 Stream 中的一些元素,而过滤掉其他的。例 3-11 展示了如何使用函数式风格编写相同的代码。 例 函数式风格

 List<String> beginningWithNumbers = Stream.of("a", "1abc", "abc1").filter(value ->isDigit(value.charAt(0))).collect(toList());

和map很像,filter接受一个函数作为参数,该函数用Lambda表达式表示。该函数和前面 示例中 if 条件判断语句的功能一样,如果字符串首字母为数字,则返回 true。若要重构 遗留代码,for 循环中的 if 条件语句就是一个很强的信号,可用 filter 方法替代。 由于此方法和 if 条件语句的功能相同,因此其返回值肯定是 true 或者 false。经过过滤, Stream 中符合条件的,即 Lambda 表达式值为 true 的元素被保留下来。

疑问:filter会影响原集合吗?如下:显然不会

List<String>list1=Arrays.asList("A","B","C","D");
List<String>list2=list1.stream().filter(a->a.equals("A")).collect(Collectors.toList());
System.out.println(list1);//[A, B, C, D]
System.out.println(list2);//[A]
9.迭代
Stream<T> peek(Consumer<? super T> action)调试专用,能看出流每个元素,因为他是惰性函数

void forEach(Consumer<? super T> action)对此流的每个元素执行操作。

void forEachOrdered(Consumer<? super T> action)如果流具有已定义的遭遇顺序,则按流的遭遇顺序对此流的每个元素执行操作。
List<String> list = new ArrayList<>();
list.add("x");
list.add("y");
list.add("z");
		
list.parallelStream().forEach(x -> System.out.println(x));
list.parallelStream().forEachOrdered(x -> System.out.println(x));
		
//主要的区别在并行流的处理上
//输出的顺序不一定(效率更高)
Stream.of("AAA", "BBB", "CCC").parallel().forEach(s -> System.out.println("Output:" + s));
		
//输出的顺序与元素的顺序严格一致
Stream.of("AAA", "BBB", "CCC").parallel().forEachOrdered(s -> System.out.println("Output:" + s));		
10.查询
Optional<T> findAny()返回Optional描述流的某个元素,Optional如果流为空则返回空。

Optional<T> findFirst()返回Optional描述此流的第一个元素,Optional如果流为空则返回空。

findFirst和findAny,通过名字,就可以看到,对这个集合的流,做一系列的中间操作后,可以调用findFirst,返回集合的第一个对象,findAny返回这个集合中,取到的任何一个对象;通过这样的描述,我们也可以知道,在串行的流中,findAny和findFirst返回的,都是第一个对象;而在并行的流中,findAny返回的是最快处理完的那个线程的数据,所以说,在并行操作中,对数据没有顺序上的要求,那么findAny的效率会比findFirst要快的

11.元素是否匹配
boolean allMatch(Predicate<? super T> predicate)检查是否匹配所有元素
boolean anyMatch(Predicate<? super T> predicate)检查是否至少匹配一个元素
boolean noneMatch(Predicate<? super T> predicate)检查是否没有匹配所有元素

案例

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
		
boolean result1 = list.stream().allMatch(a->a<10);//true
		
boolean result2 = list.stream().allMatch(a->a<5);//false
		
		
boolean result3 = list.stream().allMatch(a->a==2);//true
		
boolean result4= list.stream().allMatch(a->a==11);//false
		
		
boolean result5 = list.stream().noneMatch(a->a==2);//false
		
boolean result6 = list.stream().noneMatch(a->a==11);//true
12.元素排序
Stream<T> sorted()默认排序规则:从小到大
Stream<T> sorted(Comparator<? super T> comparator)自定义排序规则

案例

List<Integer>list=Arrays.asList(3,1,4,6,7,3,5,8,5,3);
		
list.stream().sorted().forEach(System.out::print);//1333455678
		
list.stream().sorted((a,b)->b-a).forEach(System.out::print);//8765543331
13.收集函数
<R,A> R collect(Collector<? super T,A,R> collector)使用a对此流的元素执行可变减少操作 Collector。

<R,A> R collect(Collector<? super T,A,R> collector)使用a对此流的元素执行可变减少操作 Collector。

<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)对此流的元素执行可变减少操作。

IntStream

1.创建IntStream对象
static IntStream.Builder builder()
static IntStream concat(IntStream a, IntStream b)
static IntStream generate(IntSupplier s)
static IntStream empty()
static IntStream iterate(int seed, IntUnaryOperator f)
static IntStream of(int... values)
static IntStream of(int t)
static IntStream range(int startInclusive, int endExclusive)返回子序列 [a,b),左闭右开(不包括 b)增长步值为 1
static IntStream rangeClosed(int startInclusive, int endInclusive)返回子序列 [a,b],左闭右闭(包括 b 元素,增长步值为 1
2.元素匹配
boolean allMatch(IntPredicate predicate)检查是否匹配所有元素
boolean anyMatch(IntPredicate predicate)检查是否至少匹配一个元素
boolean noneMatch(IntPredicate predicate)检查是否没有匹配所有元素
3.去重
IntStream distinct()
4.过滤
IntStream filter(IntPredicate predicate)
5.查询
OptionalInt findAny()
OptionalInt findFirst()
6.数值流变成其他流
DoubleStream mapToDouble(IntToDoubleFunction mapper)
LongStream mapToLong(IntToLongFunction mapper)
<U> Stream<U> mapToObj(IntFunction<? extends U> mapper)
DoubleStream asDoubleStream()
LongStream asLongStream()
Stream<Integer> boxed()//将基本类型流变成其包装器流

问题1、为什么会出现boxed这个方法

其实这个方法是为将流变成集合时使用的,因为java的集合不能储存基本类型

 IntStream.range(0, 10).collect(Collectors.toList());//报错的
 IntStream.range(0,10).boxed().collect(Collectors.toList());//正确的

当然了,如果我们不将其变成集合,那么可以不用boxed方法

IntStream.range(0, 10).forEach(System.out::print);//正确的
7.加工函数
IntStream flatMap(IntFunction<? extends IntStream> mapper)
IntStream map(IntUnaryOperator mapper)
8.流的截取
IntStream limit(long maxSize)
IntStream skip(long n)
9.遍历
IntStream peek(IntConsumer action)
void forEach(IntConsumer action)
void forEachOrdered(IntConsumer action)
10.聚合函数
OptionalInt reduce(IntBinaryOperator op)
int reduce(int identity, IntBinaryOperator op)
<R> R collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)
11.数组化
int[] toArray()
12.排序
IntStream sorted()
13.统计函数
int sum()
IntSummaryStatistics summaryStatistics()
long count()
OptionalInt max()
OptionalInt min()
OptionalDouble average()

LongStream

1.创建LongStream对象
static LongStream of(long... values)返回其元素为指定值的顺序有序流。
static LongStream of(long t)
static LongStream.Builder builder()
static LongStream concat(LongStream a, LongStream b)
static LongStream empty()
static LongStream generate(LongSupplier s)
static LongStream iterate(long seed, LongUnaryOperator f)
static LongStream range(long startInclusive, long endExclusive)返回子序列 [a,b),左闭右开(不包括 b)增长步值为 1
static LongStream rangeClosed(long startInclusive, long endInclusive)返回子序列 [a,b],左闭右闭(包括 b 元素,增长步值为 1
2.元素匹配
boolean allMatch(LongPredicate predicate)检查是否匹配所有元素
boolean anyMatch(LongPredicate predicate)检查是否至少匹配一个元素
boolean noneMatch(LongPredicate predicate)检查是否没有匹配所有元素
3.查询
OptionalLong findAny()
OptionalLong findFirst()
4.将数值流转换其他流
DoubleStream asDoubleStream()
Stream<Long> boxed()
DoubleStream mapToDouble(LongToDoubleFunction mapper)
<U> Stream<U> mapToObj(LongFunction<? extends U> mapper)
IntStream mapToInt(LongToIntFunction mapper)
5.去重
LongStream distinct()
6.过滤函数
LongStream filter(LongPredicate predicate)
7.加工函数
LongStream flatMap(LongFunction<? extends LongStream> mapper)
LongStream map(LongUnaryOperator mapper)
9.遍历
LongStream peek(LongConsumer action)
void forEach(LongConsumer action)
void forEachOrdered(LongConsumer action)
10.排序
LongStream sorted()
11.流的截取
LongStream skip(long n)
LongStream limit(long maxSize)
12.聚合函数
OptionalLong reduce(LongBinaryOperator op)
long reduce(long identity, LongBinaryOperator op)
<R> R collect(Supplier<R> supplier, ObjLongConsumer<R> accumulator, BiConsumer<R,R> combiner)
13.数组化
long[] toArray()
14.统计函数
long sum()
LongSummaryStatistics summaryStatistics()
OptionalLong max()
OptionalLong min()
long count()
OptionalDouble average()

DoubleStream

1.创建DoubleStream
static DoubleStream.Builder builder()
static DoubleStream concat(DoubleStream a, DoubleStream b)
static DoubleStream empty()
static DoubleStream of(double... values)
static DoubleStream of(double t)
2.创建DoubleStream,使用迭代生成无限流
static DoubleStream generate(DoubleSupplier s)无序
static DoubleStream iterate(double seed, DoubleUnaryOperator f)有序

案例:需要有限制

Stream.iterate(1,n->n+1).limit(10).forEach(System.out::println);
	
Stream.generate(Math::random).limit(10).forEach(System.out::println);
3.将数值流转换其他流
Stream<Double> boxed()
IntStream mapToInt(DoubleToIntFunction mapper)
LongStream mapToLong(DoubleToLongFunction mapper)
<U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper)
4.元素匹配
boolean allMatch(DoublePredicate predicate)检查是否匹配所有元素

boolean anyMatch(DoublePredicate predicate)检查是否至少匹配一个元素

boolean noneMatch(DoublePredicate predicate)检查是否没有匹配所有元素
5.去重
DoubleStream distinct()返回由此流的不同元素组成的流。
6.过滤函数
DoubleStream filter(DoublePredicate predicate)
7.加工函数
DoubleStream map(DoubleUnaryOperator mapper)
DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper)
8.查询
OptionalDouble findAny()返回OptionalDouble描述流的某个元素,OptionalDouble如果流为空则返回空。
OptionalDouble findFirst()返回OptionalDouble描述此流的第一个元素,OptionalDouble如果流为空则返回空。
9.流的遍历
void forEach(DoubleConsumer action)对此流的每个元素执行操作。
void forEachOrdered(DoubleConsumer action)对此流的每个元素执行操作,确保以具有已定义的遭遇顺序的流的遭遇顺序处理每个元素。
DoubleStream peek(DoubleConsumer action)调试用的
10.流的截断
DoubleStream skip(long n)在丢弃流的第一个n元素后,返回由此流的其余元素组成的流。
DoubleStream limit(long maxSize)返回由此流的元素组成的流,截断为不超过maxSize长度。
11.聚合函数
OptionalDouble reduce(DoubleBinaryOperator op)
double reduce(double identity, DoubleBinaryOperator op)
<R> R collect(Supplier<R> supplier, ObjDoubleConsumer<R> accumulator, BiConsumer<R,R> combiner)
12.排序
DoubleStream sorted()以排序顺序返回由此流的元素组成的流。
13.统计函数
double sum()
OptionalDouble max()
OptionalDouble min()
OptionalDouble average()
DoubleSummaryStatistics summaryStatistics() 返回DoubleSummaryStatistics描述有关此流的元素的各种摘要数据。
long count()
14.数组化
double[] toArray()返回包含此流的元素的数组。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值