java:stream的详细使用

java:stream的详细使用

1 案例

1.1 遍历/匹配(foreach/find/match)

Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。

package com.base;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Mstream {
    public static void main(String[] args) {
        List<Integer> i= Arrays.asList(1,5,8,7,9,10,13);
        //遍历输出符合条件的元素
        i.stream().filter(x->x>6).forEach(System.out::println);
        //匹配第一个
        Optional<Integer> findFirst = i.stream().filter(x->x>6).findFirst();
        //匹配任意(适用于并行流)
        Optional<Integer> findAny = i.stream().filter(x->x>6).findAny();
        Optional<Integer> findAny2 = i.stream().parallel().filter(x->x>6).findAny();
        //是否包含符合特定条件的元素
        boolean anyMatch = i.parallelStream().anyMatch(x->x>6);
        System.out.println("匹配第一个值:"+findFirst.get());
        System.out.println("匹配任意一个值:"+findAny.get());
        System.out.println("匹配任意一个值2:"+findAny2.get());
        System.out.println("是否存在大于6的数:"+anyMatch);
    }
}
8
7
9
10
13
匹配第一个值:8
匹配任意一个值:8
匹配任意一个值29
是否存在大于6的数:true

1.2 筛选(filter)

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
例1:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Mstream2 {
    public static void main(String[] args) {
        List<Integer> i= Arrays.asList(6,7,3,8,1,2,9);
        Stream<Integer> s=i.stream();
        s.filter(x->x>7).forEach(System.out::println);
    }
}
8
9

例2:
先创建一个类Fruit为后续的流使用构造数据:
在这里插入图片描述

import java.math.BigDecimal;
import java.math.BigInteger;

public class Fruit {
    private String name;
    private BigDecimal price;
    private BigInteger number;
    private int total;
    private double RealPrice;

    public Fruit(String name, BigDecimal price, BigInteger number, int total, double realPrice) {
        this.name = name;
        this.price = price;
        this.number = number;
        this.total = total;
        RealPrice = realPrice;
    }

    public String getName() {
        return name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public BigInteger getNumber() {
        return number;
    }

    public int getTotal() {
        return total;
    }

    public double getRealPrice() {
        return RealPrice;
    }
}

获取所有水果价格大于2的水果的名称:

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Mstream2 {
    public static void main(String[] args) {
        List<Fruit> f=new ArrayList<>();
        f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
        f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
        f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("12"),20,1.8));
        f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("7"),15,3.2));
        f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));
        List<String> b=f.stream().filter(x->(x.getPrice().compareTo(new BigDecimal("2")) > 0)).map(Fruit::getName).collect(Collectors.toList());
        System.out.println(b);
    }
}
[pear, banana]

1.3 聚合(max/min/count)

max/min/count在mysql中常用于进行数据统计。java stream中也引入了这些概念和用法,可以方便数组、集合等数据进行统计。

例1:获取集合中最长的元素

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

List<String> l=Arrays.asList("adam","lily","bob","merry","xiaoxu");
Optional<String> max=l.stream().max(Comparator.comparing(String::length));
System.out.println(max.get());

例2:获取Integer集合中的最大值

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

List<Integer> s= Arrays.asList(3,1,4,7,5);
//自然排序
Optional<Integer> max1=s.stream().max(Integer::compareTo);
//自定义排序
Optional<Integer> max2=s.stream().max(new Comparator<Integer>() {
   @Override
   public int compare(Integer o1, Integer o2) {
       return o1.compareTo(o2);
//                compare :return 0,1:返回第一个值3,-1返回最后一个值5
   }
});
System.out.println("自然排序的最大值:"+max1.get());
System.out.println("自定义排序的最大值:"+max2.get());
自然排序的最大值:7
自定义排序的最大值:7

例3:获得水果的最高价格

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class Mstream2 {
    public static void main(String[] args) {
        List<Fruit> f=new ArrayList<>();
        f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
        f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
        f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("12"),20,1.8));
        f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("7"),15,3.2));
        f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));
        Optional<Fruit> price_max=f.stream().max(Comparator.comparing(Fruit::getPrice));
        System.out.println("水果最高价格"+price_max.get().getPrice());
    }
}
水果最高价格4

例4:计算Integer集合中大于6的元素的个数

import java.util.List;
import java.util.Arrays;

List<Integer> s= Arrays.asList(3,1,4,7,5,9);
long count=s.stream().filter(x->x>6).count();
System.out.println("大于6的个数是:"+count);
大于6的个数是:2

1.4 映射(map/flatMap)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:

map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

例1:英文字符串数组的元素全部改为大写。整数数组每个元素+3。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

String[] s={"abcd","bcdd","defde","fTr","ASa"};
List<String> l=Arrays.stream(s).map(String::toUpperCase).collect(Collectors.toList());
List<Integer> i=Arrays.asList(3,1,5,4);
List<Integer> ini=i.stream().map(x->x+3).collect(Collectors.toList());
System.out.println("每个元素大写:"+l);
System.out.println("每个元素+3:"+ini);
每个元素大写:[ABCD, BCDD, DEFDE, FTR, ASA]
每个元素+3[6, 4, 8, 7]

例2:

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

public class Mstream2 {
    public static void main(String[] args) {
        List<Fruit> f=new ArrayList<>();
        f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
        f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
        f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("12"),20,1.8));
        f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("7"),15,3.2));
        f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));
        //不改变原来集合的方式
        List<Fruit> fruits_new=f.stream().map(fruit -> {
            Fruit fNew=new Fruit(fruit.getName(),null,null,0,0);
            fNew.setPrice(fruit.getPrice().add(new BigDecimal("10")));
            return fNew;
        }).collect(Collectors.toList());
        System.out.println("改动前:"+f.get(0).getName()+"-->"+f.get(0).getPrice());
        System.out.println("改动后:"+fruits_new.get(0).getName()+"-->"+fruits_new.get(0).getPrice());

        //改变原来集合的方式
        List<Fruit> fruits_new2=f.stream().map(Fruit->{
            Fruit.setPrice(Fruit.getPrice().add(new BigDecimal("20")));
            return Fruit;
        }).collect(Collectors.toList());
        System.out.println("再次改动前:"+f.get(0).getName()+"-->"+f.get(0).getPrice());
        System.out.println("再次改动后:"+fruits_new2.get(0).getName()+"-->"+fruits_new2.get(0).getPrice());
    }
}
改动前:apple-->1.46
改动后:apple-->11.46
再次改动前:apple-->21.46
再次改动后:apple-->21.46

改变原来集合的方式,可以使用以下的写法(peek,不需要像map返回list中的对象):

//改变原来集合的方式
List<Fruit> fruits_new2=f.stream().peek(Fruit-> Fruit.setPrice(Fruit.getPrice().add(new BigDecimal("20")))).collect(Collectors.toList());
System.out.println("再次改动前:"+f.get(0).getName()+"-->"+f.get(0).getPrice());
System.out.println("再次改动后:"+fruits_new2.get(0).getName()+"-->"+fruits_new2.get(0).getPrice());
//效果是一样的:
再次改动前:apple-->21.46
再次改动后:apple-->21.46

例3:将两个字符数组合并成一个新的字符数组。

import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.List;
import java.util.Arrays;

List<String> l=Arrays.asList("x,i,x,u","1,4,7,8");
List<String> l_new = l.stream().flatMap(s->{
	String[] spl=s.split(",");
	Stream<String> s2=Arrays.stream(spl);
	return s2;
}).collect(Collectors.toList());
System.out.println("处理前的集合:"+l);
System.out.println("处理后的集合:"+l_new);
处理前的集合:[x,i,x,u, 1,4,7,8]
处理后的集合:[x, i, x, u, 1, 4, 7, 8]

1.5 归约(reduce)

归约,也称为缩减,可以把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

例1:求Integer集合的元素之和、乘积和最大值

import java.util.Arrays;
import java.util.List;
import java.util.Optional;


List<Integer> i= Arrays.asList(1,5,8,7,9,10,13);
//求和方式1
Optional<Integer> o=i.stream().reduce((x,y)->x+y);
//求和方式2
Optional<Integer> o1=i.stream().reduce(Integer::sum);
//求和方式3
Integer o2=i.stream().reduce(0,Integer::sum);
System.out.println(o.get());
System.out.println(o1.get());
System.out.println(o2);
53
53
53

例2:求所有水果的价格之和,以及最高的价格

所有价格之和:

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("12"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("7"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));
//1
Optional<BigDecimal> o1=f.stream().map(Fruit::getPrice).reduce((x,y)->x.add(y));
System.out.println(o1.get());
11.56
//2
Optional<BigDecimal> o1=f.stream().map(Fruit::getPrice).reduce(BigDecimal::add);
System.out.println(o1.get());
11.56

求最大值:

Optional<BigDecimal> max1=f.stream().map(Fruit::getPrice).reduce((x,y)->x.compareTo(y)>0?x:y);
System.out.println(max1.get());
4

1.6 收集(collect)

可以是收集成一个值,也可以收集成一个新的集合。

collect主要依赖java.util.stream.Collectors类内置的静态方法

1.6.1 归集(toList/toSet/toMap)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。常用toList/toSet/toMap,还有toCollection\toConcurrentMap等复杂一些的用法。

toList/toSet/toMap用法如下:
先重写Fruit类的toString方法,方便打印Fruit的对象:
在这里插入图片描述

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

List<Integer> i=Arrays.asList(1,5,4,8,4);
List<Integer> new_i=i.stream().filter(x->x%2==0).collect(Collectors.toList());
Set<Integer> new_set=i.stream().filter(x->x%2==0).collect(Collectors.toSet());
List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("12"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("7"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));

Map<?,Fruit> m=f.stream().filter(fr->fr.getPrice().compareTo(new BigDecimal("2"))>0)
     .collect(Collectors.toMap(Fruit::getName,x->x));

System.out.println("toList:"+new_i);
System.out.println("toSet:"+new_set);
System.out.println("toMap:"+m);
toList:[4, 8, 4]
toSet:[4, 8]
toMap:{banana=Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}, pear=Fruit{name='pear', price=4, number=7, total=15, RealPrice=3.2}}

1.6.2 统计(count/averaging)

Collectors提供了一系列用于数据统计的静态方法:

计数:count
平均值:averagingInt、averagingLong、averagingDouble
最值:maxBy、minBy
求和:summingInt、summingLong、summingDouble
统计以上所有:summarizingInt、summarizingLong、summarizingDouble

例:统计水果的种类数、平均数据、平均真实价格、平均价格、价格总额、最高价格

List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("12"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("7"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));

//List求总数
long count=f.stream().collect(Collectors.counting());
long count1=f.stream().count();
long count2=f.size();
System.out.print(count+" "+count1+" "+count2+"\n");
//求总数目平均值\真实价格平均值\价格平均值(BigDecimal)
Double average_total=f.stream().collect(Collectors.averagingInt(Fruit::getTotal));
Double average_real_price=f.stream().collect(Collectors.averagingDouble(Fruit::getRealPrice));
System.out.println(average_real_price);
System.out.println(average_total);
f.stream().map(Fruit::getPrice).mapToDouble(BigDecimal::doubleValue).average().ifPresent(
System.out::println
);
//求价格之和,total求和,price求和
//BigDecimal求和,用reduce
BigDecimal sum=f.stream().map(Fruit::getPrice).reduce(BigDecimal.ZERO,BigDecimal::add);
//int、double等可以使用collect(Collectors.summingInt())或者summingDouble
Double real_price_sum = f.stream().collect(Collectors.summingDouble(Fruit::getRealPrice));
int total_sum = f.stream().collect(Collectors.summingInt(Fruit::getTotal));
System.out.println("BigDecimal总和:"+sum);
System.out.println("Double总和:"+real_price_sum);
System.out.println("int总和:"+total_sum);
//求最高的价格 1.2.3
Optional<BigDecimal> max_price=f.stream()
.map(Fruit::getPrice)
.collect(Collectors.maxBy((x,y)->x.compareTo(y)));
Optional<BigDecimal> max_price2=f.stream()
.map(Fruit::getPrice).max(BigDecimal::compareTo);
Optional<BigDecimal> max_price3=f.stream()
.map(Fruit::getPrice)
.collect(Collectors.maxBy(BigDecimal::compareTo));
System.out.println(max_price.get());
System.out.println(max_price2.get());
System.out.println(max_price3.get());
//一次性统计所有信息
DoubleSummaryStatistics d= f.stream().collect(Collectors.summarizingDouble(Fruit::getRealPrice));
System.out.println("统计所有的信息:"+d);
5 5 5
1.766
21.8
2.3120000000000003
BigDecimal总和:11.56
Double总和:8.83
int总和:109
4
4
4
统计所有的信息:DoubleSummaryStatistics{count=5, sum=8.830000, min=0.600000, average=1.766000, max=3.200000}

1.6.3 分组(partitioningBy/groupingBy)

分区:将stream按条件分为两个Map,比如水果价格是否高于2分成两部分

分组:将集合分为多个Map,比如水果按照编号number分组。有单级和多级分组。

List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("5"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("15"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));

//按照水果价格是否高于2分成两部分
Map<Boolean,List<Fruit>> m=f.stream()
.collect(Collectors.partitioningBy(x->x.getPrice().compareTo(new BigDecimal("2"))>0));
//按照水果编号分组
Map<BigInteger,List<Fruit>> m1=f.stream()
.collect(Collectors.groupingBy(Fruit::getNumber));
//先按照编号分组,再按照total分组
Map<BigInteger,Map<Integer,List<Fruit>>> m2=f.stream()
.collect(Collectors.groupingBy(Fruit::getNumber,
Collectors.groupingBy(Fruit::getTotal)));
System.out.println("水果价格是否高于2:"+m);
System.out.println("按照水果编号分组:"+m1);
System.out.println("先按照编号、再按照total分组:"+m2);
水果价格是否高于2{false=[Fruit{name='apple', price=1.46, number=15, total=40, RealPrice=1.23}, Fruit{name='watermelon', price=1.1, number=5, total=10, RealPrice=0.6}, Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}], true=[Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}, Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}]}
按照水果编号分组:{5=[Fruit{name='watermelon', price=1.1, number=5, total=10, RealPrice=0.6}, Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}], 15=[Fruit{name='apple', price=1.46, number=15, total=40, RealPrice=1.23}, Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}, Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}]}
先按照编号、再按照total分组:{5={20=[Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}], 10=[Fruit{name='watermelon', price=1.1, number=5, total=10, RealPrice=0.6}]}, 15={24=[Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}], 40=[Fruit{name='apple', price=1.46, number=15, total=40, RealPrice=1.23}], 15=[Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}]}}

1.6.4 接合(joining)

joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串

List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("5"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("15"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));

String names = f.stream().map(Fruit::getName).collect(Collectors.joining(";"));
System.out.println(names);
List<String> s=Arrays.asList("a","y","t");
String s1=s.stream().collect(Collectors.joining("-"));
String s2= String.join("-", s);
System.out.println(s1);
System.out.println(s2);
apple;watermelon;peach;pear;banana
a-y-t
a-y-t

1.6.5 归约(reducing)

Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持。

List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("1.46"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("1.1"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("5"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("15"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));

//每种水果,全部减价后的价格之和
//1.使用Collectors类的reducing()方法
BigDecimal sum_sub1=f.stream().collect(Collectors.reducing(new BigDecimal("0"),Fruit::getPrice,(x,y)->x.add(y).subtract(new BigDecimal("1"))));
//2.使用stream的reduce()方法
BigDecimal sum_sub2= f.stream().map(Fruit::getPrice).reduce(new BigDecimal("0"), (x, y) -> x.add(y).subtract(new BigDecimal("1")));
System.out.println(sum_sub1);
System.out.println(sum_sub2);
6.56
6.56

1.7 排序(sorted)

sorted,中间操作。有两种排序:

sorted():自然排序,流中元素需实现Comparable接口

sorted(Comparator c):Comparator排序器自定义排序

按照水果价格增序/倒序来排序

//数据如下
List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("2"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("4"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("5"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("15"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));
//1.排序和Collectors.toMap不能一起使用,排序会无效
//Redundant 'sorted' call: subsequent 'toMap' call doesn't depend on the sort order 
Map<String,BigDecimal> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice))
        .collect(Collectors.toMap(Fruit::getName,Fruit::getPrice));
System.out.println("排序sorted和Collectors.toMap一起使用:"+m);
排序sorted和Collectors.toMap一起使用:{banana=3, apple=2, pear=4, peach=2, watermelon=4}
//2.按照价格增序排序
List<Fruit> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice))
        .collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
//2.1 按照价格增序排序,获取水果名称
List<String> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice)).map(Fruit::getName)
        .collect(Collectors.toList());
System.out.println(m);
[apple, peach, banana, watermelon, pear]
//3 按照价格倒序排序
List<Fruit> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice).reversed())
        .collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
//4.1 先按照价格增序排序,再按照数目total倒序排序
List<Fruit> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice).reversed().thenComparing(Fruit::getTotal).reversed())
        .collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
//4.2 先按照价格倒序排序,再按照数目total倒序排序
List<Fruit> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice).thenComparing(Fruit::getTotal).reversed())
        .collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
//4.3 先按照价格倒序排序,再按照数目total增序排序
List<Fruit> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice).reversed().thenComparing(Fruit::getTotal))
        .collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
//4.4 先按照价格增序排序,再按照数目total增序排序
List<Fruit> m=f.stream().sorted(Comparator.comparing(Fruit::getPrice).thenComparing(Fruit::getTotal))
        .collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}

注意:上述特殊情况,只有在最末尾使用reversed()是指两个字段全部倒序,如果要达到第一个字段增序,第二个字段倒序,在comparing和thenComparing后都加上.reversed即可

自定义排序:

//自定义排序 5.1 先按照价格增序排序,再按照数目total倒序排序
List<Fruit> m=f.stream().sorted((v1,v2)->{
    if(Objects.equals(v1.getPrice(), v2.getPrice())){
        return -(v1.getTotal()-v2.getTotal());
    }else{
        return v1.getPrice().compareTo(v2.getPrice());
    }
}).collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
//自定义排序 5.2  先按照价格倒序排序,再按照数目total倒序排序
List<Fruit> m=f.stream().sorted((v1,v2)->{
    if(Objects.equals(v1.getPrice(), v2.getPrice())){
        return -(v1.getTotal()-v2.getTotal());
    }else{
        return -v1.getPrice().compareTo(v2.getPrice());
    }
}).collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
//自定义排序 5.3  先按照价格倒序排序,再按照数目total增序排序
List<Fruit> m=f.stream().sorted((v1,v2)->{
    if(Objects.equals(v1.getPrice(), v2.getPrice())){
        return (v1.getTotal()-v2.getTotal());
    }else{
        return -v1.getPrice().compareTo(v2.getPrice());
    }
}).collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
//自定义排序 5.4  先按照价格增序排序,再按照数目total增序排序
List<Fruit> m=f.stream().sorted((v1,v2)->{
    if(Objects.equals(v1.getPrice(), v2.getPrice())){
        return (v1.getTotal()-v2.getTotal());
    }else{
        return v1.getPrice().compareTo(v2.getPrice());
    }
}).collect(Collectors.toList());
m.forEach(System.out::println);
Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}

1.8 提取/组合

流可以进行合并、去重、限制、跳过等操作。

注意:Stream.of会涉及到重用流的情况:

String[] a={"a","b","c","c","d"};
String[] b={"e","e","f","W"};
Stream<String> x1=Stream.of(a);
Stream<String> x2=Stream.of(b);
//concat:合并两个流   distinct:去重
List<String> l1=Stream.concat(x1,x2).collect(Collectors.toList());
List<String> l2=Stream.concat(x1,x2).distinct().collect(Collectors.toList());
System.out.println(l1);
System.out.println(l2);

在这里插入图片描述
因为在l1时,上面的流已经被使用了,下面再次使用x1和x2流就会抛错,解决方式如下:
Supplier接口产生一个给定类型的结果。与Function不同的是,Supplier没有输入参数。
在这里插入图片描述

String[] a={"a","b","c","c","d"};
String[] b={"e","e","f","W"};
//Stream<String> x1=Stream.of(a);
//Stream<String> x2=Stream.of(b);
Supplier<Stream<String>> y1=()->Stream.of(a);
Supplier<Stream<String>> y2=()->Stream.of(b);
//concat:合并两个流   distinct:去重
List<String> l1=Stream.concat(y1.get(),y2.get()).collect(Collectors.toList());
List<String> l2=Stream.concat(y1.get(),y2.get()).distinct().collect(Collectors.toList());
System.out.println(l1);
System.out.println(l2);
[a, b, c, c, d, e, e, f, W]
[a, b, c, d, e, f, W]
//limit:限制从流中获得前n个数据
List<Integer> l3=Stream.iterate(1,x->x+3).limit(3).collect(Collectors.toList());
System.out.println(l3);
//skip:跳过前n个数据
List<Integer> l4=Stream.iterate(3,x->x+2).skip(2).limit(5).collect(Collectors.toList());
System.out.println(l4);
[1, 4, 7]
//本来是从3开始,跳过3,5,所以从7开始
[7, 9, 11, 13, 15]

tips:idea快捷键输出System.err.println(); => serr

1.9 练习

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;
List<Fruit> f=new ArrayList<>();
f.add(new Fruit("apple",new BigDecimal("2"),new BigInteger("15"),40,1.23));
f.add(new Fruit("watermelon",new BigDecimal("4"),new BigInteger("5"),10,0.6));
f.add(new Fruit("peach",new BigDecimal("2"),new BigInteger("5"),20,1.8));
f.add(new Fruit("pear",new BigDecimal("4"),new BigInteger("15"),15,3.2));
f.add(new Fruit("banana",new BigDecimal("3"),new BigInteger("15"),24,2));
//分组Collectors.groupingBy,map的value是List
Map<BigInteger,List<Fruit>> m=f.stream().collect(Collectors.groupingBy(Fruit::getNumber));
System.err.println(m);
//希望map的value是单独的一个对象,使用Collectors.toMap,但是要注意Duplicate key错误
Map<BigInteger,Fruit> m1=f.stream().collect(Collectors.toMap(Fruit::getNumber,x->x));
System.err.println(m1);

在这里插入图片描述

//修改如上
//希望map的value是单独的一个对象,使用Collectors.toMap,但是要注意Duplicate key错误
//(k1,k2)->k1)表示重复的key,取第一个K1即可
Map<BigInteger,Fruit> m1=f.stream().collect(Collectors.toMap(Fruit::getNumber,x->x,(k1,k2)->k1));
System.err.println(m1);

在这里插入图片描述

//求和
BigDecimal total_price=f.stream().map(Fruit::getPrice).reduce(BigDecimal.ZERO,BigDecimal::add);
System.err.println("和:"+total_price);
和:15
//maxBy:最大的有多个,只会取第一个,所以这种取不完(需要考虑多个max的情况)
Optional<Fruit> max_price_fruit=f.stream().collect(Collectors.maxBy(Comparator.comparing(Fruit::getPrice)));
Optional<Fruit> max_price_fruit2= f.stream().max(Comparator.comparing(Fruit::getPrice));
System.err.println(max_price_fruit.get());
System.err.println(max_price_fruit2.get());
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}
System.out.println("去重:");
//去重
List<Fruit> unique = f.stream().collect(
        Collectors.collectingAndThen(Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(Fruit::getPrice))),ArrayList::new)
);
unique.forEach(System.err::println);
去重:
Fruit{name='apple', price=2, number=15, total=40, RealPrice=1.23}
Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}
Fruit{name='watermelon', price=4, number=5, total=10, RealPrice=0.6}

上面的去重方式,按照price有小到大排序,且重复的price直接被去掉了,只取了一个值。

Collectors类的静态工厂方法(结构:工厂方法+返回类型+作用):

toList:List<>:把流中所有项目收集到一个List

toSet:Set< T >:把流中所有项目收集到一个Set,删除重复项

toCollection:Collection< T >:把流中所有项目收集到给定的供应源创建的集合,fruitStream.collect(Collectors.toCollection(),ArrayList::new)

counting:Long:计算流中元素的个数

summingInt:Integer:对流中项目的一个整数属性求和

averagingInt:Double:计算流中项目Integer属性的平均值

summarizingInt:IntSummaryStatistics(java.util.IntSummaryStatistics):收集关于流中项目Integer属性的统计值,例如最大、最小、总和与平均值

joining:String:连接对流中每个项目调用toString方法所生成的字符串collect(joining(","))

maxBy:Optional< T >:一个包裹了流中按照给定比较器选出的最大元素的Optional,或如果流为空则为Optional.empty()

minBy(形如上maxBy)

reducing:归约操作产生的类型:从一个作为累加器的初始值开始,利用BinaryOperator与流中的元素逐个结合,从而将流归约为单个值累加

collectingAndThen:转换函数返回的类型:包裹另一个收集器,对其结果应用转换函数 int howManySize=Fstream.collect(collectingAndThen(toList(),List::size))

int l=f.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size));
System.out.println(l);
5

groupingBy:Map<K,List< T >>:根据项目的一个属性的值对流中的项目作分组,并将属性值作为结果Map的键

partitioningBy:Map< Boolean,List< T >>:根据对流中每个项目应用谓词的结果来对项目进行分区

参考前面的例子:

//按照水果价格是否高于2分成两部分
Map<Boolean,List<Fruit>> m=f.stream()
.collect(Collectors.partitioningBy(x->x.getPrice().compareTo(new BigDecimal("2"))>0));
System.out.println("水果价格是否高于2:"+m);
水果价格是否高于2{false=[Fruit{name='apple', price=1.46, number=15, total=40, RealPrice=1.23}, Fruit{name='watermelon', price=1.1, number=5, total=10, RealPrice=0.6}, Fruit{name='peach', price=2, number=5, total=20, RealPrice=1.8}], true=[Fruit{name='pear', price=4, number=15, total=15, RealPrice=3.2}, Fruit{name='banana', price=3, number=15, total=24, RealPrice=2.0}]}

2.0

调用Stream的api执行操作:

延迟方法:该类方法调用后,会返回一个【新的Stream对象】,并且不会执行任何的业务操作
filter – 实现数据过滤
map – 将一种数据类型的流转成另一种数据类型的流
skip – 跳过前几个
limit – 取前几个
Stream.concat() – 合并流对象

终结方法:该类方法调用后,不会返回Stream流对象,会触发之前所有的业务操作
forEach — 实现遍历
count – 实现计数
collect – 将流中的数据重新转为集合

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值