1、概述

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

特点

  • 不是数据结构,不会保存数据
  • 不会修改原来的数据源,他会将操作后的数据保存到另一个对象中;(peek方法可以修改流中的元素)
  • 惰性求值,流在中间处理过程中,只对操作进行了记录,并不会立即执行,需要等到执行中止操作时才会进行实际的计算
  • 代码简洁,函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环
  • 多核友好,Java 函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法

需要注意的是,对于基本数值型,目前有三种对应的包装类型StreamIntStream、LongStream、DoubleStream。当然我们也可以用 Stream<Integer>、Stream<Long>Stream<Double>,但是==boxing/unboxing会很耗时==,所以特别为这三种基本数值型提供了对应的Stream。

Java8中还没有提供其它数值型Stream,因为这将导致扩增的内容较多。而常规的数值型聚合运算可以通过上面三种Stream进行。

1.1预备知识点

2、流程

  1. 第一步:把集合转换为流stream
  2. 第二步:操作stream

stream流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果

3、分类

afPOAK.png

4、流的常用创建方法

4.1、使用Collection下的 stream() 和 parallelStream() 方法

List<String> list = new ArrayList<>();
//获取一个顺序流
Stream<String> stream = list.stream();
//获取一个并行流
Stream<String> parallelStream = list.parallelStream();

4.2、使用Arrays 中的 stream() 方法,将数组转成流

Integer[] nums = new Integer[]{1,2,3,4,5,6,8};
Stream<Integer> stream = Arrays.stream(nums);
stream.forEach(System.out::println);

4.3、使用Stream中的静态方法:of()、iterate()、generate()

String[] strings = {"a","b","c"};
Stream.of(strings).forEach(System.out::println);
System.out.println("================================================");
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
stream.forEach(System.out::println);
System.out.println("================================================");
Stream<User> userStream = Stream.of(new User(10),new User(21),new User(19));
userStream.forEach(item->System.out.println(item.getAge()));
System.out.println("================================================");

/**
 * <p> 根据函数生成流:无限流,一定要加limit <p>
 * @author hubz
 * @date 2020/8/7 16:50
 * @param seed:初始值
 * @param 参数二:函数
 **/
Stream<Integer> stream2 = Stream.iterate(1, (x) -> x + 2).limit(10);
stream2.forEach(System.out::println); // 1 3 5 7 9
System.out.println("================================================");


/**
 * <p>
 *     1.这种情形通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream。
 *     2.把 Supplier 实例传递给 Stream.generate() 生成的 Stream,默认是串行(相对 parallel 而言)
 *          但无序的(相对 ordered 而言)
 * <p>
 * @author hubz
 * @date 2020/8/7 17:07
 **/
Stream<Integer> stream3 = Stream.generate(()->new Random().nextInt()).limit(3);
stream3.forEach(System.out::println);
System.out.println("================================================");
Stream.generate(()->new Random().nextInt(24)).limit(3).forEach(System.out::println);
class User{
    int age;

    public User(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

4.4、使用 BufferedReader.lines() 方法,将每行内容转成流

BufferedReader reader = new BufferedReader(new FileReader("E:\\test_stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);

4.5、使用 Pattern.splitAsStream() 方法,将字符串分隔成流

Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);

==(3)静态工厂==

  • ==java.util.stream.IntStream.range()==
  • ==java.nio.file.Files.walk()==

==(4)自己构建==

  • ==java.util.Spliterator==

==(5)其他==

  • ==Random.ints()==
  • ==BitSet.stream()==
  • ==Pattern.splitAsStream(java.lang.CharSequence)==
  • ==JarFile.stream()==

5、操作符

5.1、中间操作符

==测试过程中使用到的对象==

User

class User {
    int age;
    int heigh;

    public User(int age, int heigh) {
        this.age = age;
        this.heigh = heigh;
    }

    public User(int age) {
        this.age = age;
    }

    public User() {
    }

    public int getHeigh() {
        return heigh;
    }

    public void setHeigh(int heigh) {
        this.heigh = heigh;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", heigh=" + heigh +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

BillsNums

class BillsNums {
    private String id;
    private int nums;
    private int sums;

    public BillsNums() {
    }

    public BillsNums(int nums) {
        this.nums = nums;
    }

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public int getNums() {
        return nums;
    }
    public void setNums(int nums) {
        this.nums = nums;
    }
    public int getSums() {
        return sums;
    }
    public void setSums(int sums) {
        this.sums = sums;
    }

    @Override
    public String toString() {
        return "BillsNums{" +
                "id='" + id + '\'' +
                ", nums=" + nums +
                ", sums=" + sums +
                '}';
    }
}

5.1.1、filter

用于通过设置的条件过滤出元素

/**
* @desc filter中间操作符:过滤集合中不符合条件的元素
* @author hubz
* @date 2020/8/6 23:30
*/
public static void filter(){
    List<String> strings = Arrays.asList("123","dsa2","das","sda","65");
    List<String> res = strings.stream().filter(item->{
        if(item.contains("a")){
            System.out.println("包含a的元素:"+item);
            return true;
        }
        System.out.println(item);
        return false;
    }).collect(Collectors.toList());
    res.forEach(System.out::println);
}

5.1.2、distinct

通过流中元素的 hashCode() 和 equals() 去除重复元素

==对象去重、求最小值、求最大值==

/**
* @desc <p> distinct:去除集合中的重复 <p>
* @author hubz
* @date 2020/8/6 23:36
*/
public static void distinct(){
    List<String> strings = Arrays.asList("123","dsa2","dsa2","sda","123","65");
    List<String> distincted = strings.stream().distinct().collect(Collectors.toList());
    distincted.forEach(System.out::println);
    List<User> users = new ArrayList<>();
    users.add(new User(1));
    users.add(new User(1));
    users.add(new User(2));
    users.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
}

5.1.3、limit

返回一个不超过给定长度的流

/**
 * <p> limit获取流中的前n个元素 <p>
 * @author hubz
 * @date 2020/8/7 19:35
 **/
private static void limit(){
    List<String> strings = Arrays.asList("abc","bc","bc","efg","abcd","jkl");
    strings.stream().limit(3).collect(Collectors.toList())
        .forEach(System.out::println);
}

5.1.4、skip

返回一个跳过前n个元素的流

/**
 * <p> skip获取流中除去前n个元素的其他所有元素 <p>
 * @author hubz
 * @date 2020/8/7 19:36
 **/
private static void skip(){
    List<String> strings = Arrays.asList("abc","bc","bc","efg","abcd","jkl");
    strings.stream().skip(2).collect(Collectors.toList())
        .forEach(System.out::println);
}

5.1.5、map

接受一个函数作为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素

/**
* @desc <p> 对流中所有数据进行处理 <p>
* @author hubz
* @date 2020/8/7 0:00
*/
public static void map(){
    List<String> strings = Arrays.asList("123","dsa2","dsa2","sda","123","65");
    strings.stream().map(item -> {
        return item.concat("_HAHA");
    }).collect(Collectors.toList()).forEach(System.out::println);
    System.out.println("===========================================");
    List<String> res = new ArrayList<>();
    strings.forEach(item->{
        item = item+"_das_ASSAS";
        res.add(item);
    });
    res.forEach(System.out::println);
}

5.1.6、flatMap

  • 扁平化处理:各个数组不是分别映射成一个流而是映射成流的内容。
  • 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
public static void flatMap() {
    Stream.of(new String[]{"Hello", "World"})
        .flatMap(str -> Arrays.stream(str.split("")))
        .distinct()//去重
        .collect(Collectors.toList())
        .forEach(System.out::println);

    Stream.of("beijing huanying ni")
        .flatMap(str -> Arrays.stream(str.split(" ")))
        .collect(Collectors.toList())
        .forEach(System.out::println);
}

==map和flatMap的对比==

public static void mapAndflatMap(){
    Stream.of(new String[]{"Hello", "World"})
        .flatMap(str -> Arrays.stream(str.split("")))
        .distinct()//去重
        .collect(Collectors.toList())
        .forEach(System.out::println);
    System.out.println("====================================");
    Stream.of(new String[]{"Hello", "World"})
        .map(str -> Arrays.stream(str.split("")))
        .distinct()//去重
        .collect(Collectors.toList())
        .forEach(s->s.forEach(System.out::println));
}

a7wr0f.png

  • map:对流中每一个元素进行处理

  • flatMap:流扁平化,让你把一个流中的“每个值”都换成另一个流,然后把所有的流连接起来成为一个流;

  • 总结map是对每一个元素进行操作,flatmap是对二级元素进行操作。

  • 本质区别map返回一个值,flatmap返回一个流,多个值;

  • 应用场景

    • map对集合中每个元素加工,返回加工后结果;
    • flatmap对集合中每个元素加工后,做扁平化处理后(拆分层级,放到同一层)然后返回;

5.1.7、sorted

返回排序后的流,默认按照字母序

/**
 * <p> 将数据排序 <p>
 * @author hubz
 * @date 2020/8/8 9:18
 **/
public static void sorted(){
    //----------------------- 字母排序 -----------------------
    List<String> strings = Arrays.asList("abc","bcd","acd","eds");
    strings.stream().sorted().forEach(System.out::println);
    System.out.println("==============================");
    //----------------------- 数字排序 -----------------------
    List<Integer> list = Arrays.asList(3, 2, 1, 4);
    List<Integer> resList = list.stream().sorted().collect(Collectors.toList());
    resList.forEach(System.out::println);
    System.out.println("==============================");
    //----------------------- 根据对象属性排序 -----------------------
    List<User> userList = new ArrayList<>();
    userList.add(new User(12));
    userList.add(new User(52));
    userList.add(new User(20));
    userList.forEach(System.out::println);
    System.out.println("==============================");
    userList.stream().sorted(Comparator.comparing(User::getAge)).forEach(System.out::println);
    System.out.println("==============================");
    //----------------------- 汉字排序 -----------------------
    //反向排序
    List<String> nameList = Arrays.asList("张伟", "李四", "钱王对", "诸葛询");
    nameList.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA)))
            .forEach(System.out::println);
    //正向排序
    List<String> nameList = Arrays.asList("张伟", "李四", "钱王对", "诸葛询");
    nameList.stream().sorted(Collator.getInstance(Locale.CHINA)).
                collect(Collectors.toList()).forEach(System.out::println);
}

5.1.8、peek

如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值;

  • peek对对象操作会有效果;
  • peek主要用于debug操作;
public static void peek(){
    User user1 = new User(12);
    User user2 = new User(20);
    List<User> users = Arrays.asList(user1,user2);

    users.stream().peek(o->{
        o.setAge(100);
        }).collect(Collectors.toList()).forEach(System.out::println);
    System.out.println("===========================================");

    Stream.of("one", "two", "three","four").filter(e -> e.length() > 3)
        .peek(e -> System.out.println("Filtered value: " + e))
        .map(String::toUpperCase)
        .peek(e -> System.out.println("Mapped value: " + e))
        .collect(Collectors.toList());//.forEach(System.out::println);
}

突发奇想:

  • peek功能很像forEach,只不过forEach完事就结束了,peek完事之后还可以进行下一步的操作,操作空间增大;
public static void peek(){
    User user1 = new User(12);
    User user2 = new User(20);
    List<User> users = Arrays.asList(user1,user2);

    long sum = users.stream()
        .peek(o -> {o.setAge(o.getAge() / 2);})//对年龄除2
        .mapToInt(User::getAge)
        .summaryStatistics().getSum();//求和

    System.out.println(sum);
}

5.1.9、mapToXXX

  • mapToInt
  • mapToLong
  • mapToDouble
  • flatMapToInt
  • flatMapToLong
  • flatMapToDouble

mapToT方法,T表示基础数据类型,包括int,long,double,注意没有floatmapToT方法返回值是TStream类型,例如 IntStreamTStream类包含了一些处理基础数据的方法,可以让我们更方便。我们使用mapToT的原因,不仅仅是方便,还在于性能。我们知道,因为泛型的原因,可以有List但是不能有List,这里的IntStream就相当于是List,int 所占内存比Integer小。flatMapToInt()这种flatMapToT(),这里的T同样表示int long double基础数据类型。

5.2、终止操作符

5.2.1、anyMatch

检测是否至少匹配一个元素,返回boolean

/**
 * @desc <p> 集合中是否有一个元素满足条件 <p>
 * @author hubz
 * @date 2020/8/9 22:44
 */
public static void anyMatch(){
    List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
    boolean bc = stringList.stream().anyMatch(s->s.contains("bc"));
    System.out.println("anyMatch 有满足的:"+bc);//有满足的;true
    boolean z = stringList.stream().anyMatch(s -> s.contains("z"));
    System.out.println("anyMatch 都不满足:"+z);//都不满足:false
}

5.2.2、allMatch

检查是否匹配所有元素,返回boolean

/**
 * @desc <p> 集合中元素是否都满足条件 <p>
 * @author hubz
 * @date 2020/8/9 23:02
 */
public static void allMatch(){
    List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
    boolean b = stringList.stream().allMatch(str -> str.length() > 0);
    System.out.println("allMatch 都满足:"+b);//都满足:true
    boolean b1 = stringList.stream().allMatch(str -> str.length() > 3);
    System.out.println("allMatch 有不满足的:"+b1);//有不满足的:false
}

5.2.3、noneMatch

检查是否没有匹配所有元素,返回boolean

/**
 * @desc <p> 集合中元素是否都不满足条件 <p>
 * @author hubz
 * @date 2020/8/9 23:03
 */
public static void noneMatch(){
    List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
    boolean a = stringList.stream().noneMatch(str -> str.contains("a"));
    System.out.println("noneMatch 有满足的:"+a);//有满足的:false
    boolean z = stringList.stream().noneMatch(str -> str.contains("z"));
    System.out.println("noneMatch 都不满足:"+z);//都不满足:true
}

5.2.4、findAny

将返回当前流中的任意元素

/**
 * @desc <p> 返回集合中的任意元素 <p>
 * @author hubz
 * @date 2020/8/9 23:03
 */
public static void findAny(){
    List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
    String s = stringList.stream().findAny().get();
    System.out.println(s);
    System.out.println("=================================");
    for(int i=0;i<10000;i++){
        System.out.println(stringList.parallelStream().findAny().orElse("-1"));
    }
}

5.2.5、findFirst

返回流中的第一个元素

/**
 * @desc <p> 返回集合中的第一个元素 <p>
 * @author hubz
 * @date 2020/8/9 23:04
 */
public static void findFirst(){
    List<String> stringList = Arrays.asList("abc","bcd","edc","rsfdas","ufhb");
    String s = stringList.stream().findFirst().get();
    System.out.println(s);
    System.out.println("=================================");
    for(int i=0;i<10000;i++){
        System.out.println(stringList.parallelStream().findFirst().orElse("-1"));
    }
}

5.2.6、forEach

遍历流:==没啥好说的==

5.2.7、collect

收集器:将流转化为其他形式

/**
 * @desc <p> collect 将流转换成其他形式 <p>
 * @author hubz
 * @date 2020/8/9 23:23
 */
public static void collect() {
    List<String> stringList = Arrays.asList("abc", "bcd", "abc", "edc", "rsfdas", "ufhb");
    stringList.stream()
            .collect(Collectors.toSet())
            .forEach(System.out::println);
    System.out.println("============================");
    AtomicInteger i = new AtomicInteger();
    Map<String, String> stringMap = stringList.stream()
            .collect(Collectors.toMap(String::toUpperCase, v -> {
                i.getAndIncrement();
                return v.concat("_value" + i);
            }, (k, v) -> k));
    System.out.println(stringMap);
    System.out.println("============================");
    AtomicInteger j = new AtomicInteger();
    Map<String, String> stringMap1 = stringList.stream()
            .collect(Collectors.toMap(k->k.toUpperCase(), v -> {
                j.getAndIncrement();
                return v.concat("_value" + j);
            }, (k, v) -> v));
    System.out.println(stringMap1);
    //Collectors.toMap(keyMapper,valueMapper,mergeFunction,mapFactory)
    //参数1:key值映射
    //参数2:value值映射
    //参数3:当出现key值相同时,选取前面/后面的作为value值,就是出现相同key时的选择方式
    //参数4:默认返回的map类型为HashMap,可以自己返回不同的map实现
    System.out.println("============================");
    //对象操作更清晰
    List<User> userList = Arrays.asList(
            new User(12,170),
            new User(12,180),
            new User(22,175),
            new User(25,180)
    );
    Map<Integer, Integer> userMap = userList.stream()
        .collect(Collectors.toMap(User::getAge, User::getHeigh, (k, v) -> v));
    System.out.println(userMap);//12 的 170 被 180 覆盖
    System.out.println("============================");
    userMap = userList.stream().collect(Collectors.toMap(User::getAge, User::getHeigh, (k, v) -> k));
    System.out.println(userMap);//12 的 170 未被 180 覆盖
}

5.2.8、reduce

可以将流中的元素反复结合起来,得到一个值

public static void reduce(){
    int[] arr = {1,2,3,5,2,2,4,8};
    //求和
    //一个参数
    int sum = Arrays.stream(arr).reduce(Integer::sum).getAsInt();
    System.out.println(sum);
    System.out.println("============================");
    /**
         * @desc <p> 两个参数 <p>
         * @author hubz
         * @param identity:初始值,在初始值的基础上进行计算
         *            方法的返回结果为初始值identity类型的对象
         * @date 2020/8/10 10:50
         **/
    int sum1 = Arrays.stream(arr).reduce(10, Integer::sum);
    System.out.println(sum1);
    System.out.println("============================");
    /**
         * @desc <p>
         *     ① U类型的初始值。
         *     ② (T,U)→U,T+U返回U类型。
         *     ③ 组合器(T,T)→T,T+T返回T类型
         * <p>
         * @author hubz
         * @date 2020/8/10 10:49
         **/
    int mul = Arrays.stream(arr).reduce(1, (x, y) -> x * y);
    System.out.println(mul);
    System.out.println("============================");


    //非并行
    List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);
    ArrayList<Integer> arr0 = new ArrayList<>();
    arr0.add(7);
    arr0.add(8);
    arr0.add(9);
    arr0.add(10);
    List<Integer> reduce = num.stream().reduce(arr0, (x, y) -> {
        x.add(y);
        return x;
    }, (List<Integer> x, List<Integer> y) -> {
        System.out.println("并行才会出现");
        return x;
    });
    System.out.println(reduce);
    System.out.println("============================");
    //并行
    List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
    Integer num1 = nums.parallelStream().reduce(0, (x, y) -> x + y, (x, y)->{
        System.out.println("这里调用一次");
        return x + y;
    });
    System.out.println(num1);

}
public static void reduce(){
    List<String> strings = Arrays.asList("cd","sdc","sda","efg","jkl");
    //reduce 方法一
    Optional<String> reduce1 = strings.stream().reduce((acc,item)->{return acc+item;});

    //reduce 方法二
    String reduce2 = strings.stream().reduce("itcase",(acc,item)->{
        return acc+item;
    });

    //reduce 方法三
    ArrayList<String> reduce3 = strings.stream().reduce(
        new ArrayList<String>(),
        new BiFunction<ArrayList<String>, String, ArrayList<String>>() {
            @Override
            public ArrayList<String> apply(ArrayList<String> acc, String item) {
                acc.add(item);
                return acc;
            }
        }, new BinaryOperator<ArrayList<String>>() {
            @Override
            public ArrayList<String> apply(ArrayList<String> acc, ArrayList<String> item) {
                return acc;
            }
        });
    System.out.println(reduce1.get());
    System.out.println(reduce2);
    System.out.println(reduce3);
}

5.2.9、count

返回流中元素的个数

/**
 * @desc <p> 返回流中元素的个数 <p>
 * @author hubz
 * @date 2020/8/9 23:24
 */
public static void count() {
    List<String> stringList = Arrays.asList("abc", "bcd", "edc", "rsfdas", "ufhb");
    System.out.println(stringList.stream().count());
}

5.2.10、min

返回最小值

5.2.11、max

返回最大值

6、常见操作

==求和,平均值,最大值,最小值==

6.1、数值

6.1.1、求平均值

/**
 * @desc <p> 求平均值 <p>
 * @author hubz
 * @date 2020/8/9 14:10
 */
public static void avg(){
    Double[] list = {0.69D, 1D, 1.2, 5.6};
    double[] doubles = {0.15D,2D,2.3,93.1};
    List<Integer> integers = Arrays.asList(0, 1, 2, 56);

    //求平均值
    Double avgDouble = Arrays.stream(list).collect(Collectors.averagingDouble(Double::doubleValue));
    System.out.println("平均值为 avgDouble:"+avgDouble.intValue());
    double avgDouble1 = Arrays.stream(list).mapToDouble(Double::doubleValue).average().orElse(0D);
    System.out.println("平均值为 avgDouble1:"+(int)avgDouble1);
    double avgDouble2 = Arrays.stream(doubles).average().orElse(0D);
    System.out.println("平均值为 avgDouble2:"+ (int) avgDouble2);
    double avgDouble3 = Arrays.stream(list).mapToDouble(Double::doubleValue)
        .summaryStatistics().getAverage();
    System.out.println("平均值为 avgDouble3:"+ (int) avgDouble3);

    double intAvg = integers.stream().mapToInt(Integer::intValue).average().orElse(0);
    System.out.println("平均值为 intAvg:"+intAvg);
}

6.1.2、求最小值

/**
 * @desc <p> 求最小值 <p>
 * @author hubz
 * @date 2020/8/9 14:11
 */
public static void min(){
    Double[] list = {0.69D, 1D, 1.2, 5.6};
    double[] doubles = {0.15D,2D,2.3,93.1};
    List<Integer> integers = Arrays.asList(0, 1, 2, 56);


    //求最小值
    Double minDouble = Arrays.stream(list).min(Double::compare).get();
    System.out.println("最小值为 minDouble:"+minDouble);
    Double minDouble1 = Arrays.stream(list).min(Double::compareTo).get();
    System.out.println("最小值为 minDouble1:"+minDouble1);
    double minDouble2 = Arrays.stream(doubles).min().getAsDouble();
    System.out.println("最小值为 minDouble2:"+minDouble2);
    double minDouble3 = Arrays.stream(list).mapToDouble(Double::doubleValue)
        .summaryStatistics().getMin();
    System.out.println("最小值为 minDouble3:"+minDouble3);

    Integer minInteger = integers.stream().min(Integer::compare).get();
    System.out.println("最小值为 minInteger:"+minInteger);

}
Optional<Emp> max = list.stream().collect(Collectors.minBy(Employee::getSalary));

6.1.3、求最大值

/**
 * @desc <p> 求最大值 <p>
 * @author hubz
 * @date 2020/8/9 14:19
 */
public static void max(){
    Double[] list = {0.69D, 1D, 1.2, 5.6};
    double[] doubles = {0.15D,2D,2.3,93.1};
    List<Integer> integers = Arrays.asList(0, 1, 2, 56);


    //求最大值
    Double maxDouble = Arrays.stream(list).max(Double::compare).get();
    System.out.println("最大值为 minDouble:"+maxDouble);
    Double maxDouble1 = Arrays.stream(list).max(Double::compareTo).get();
    System.out.println("最大值为 minDouble1:"+maxDouble1);
    double maxDouble2 = Arrays.stream(doubles).max().getAsDouble();
    System.out.println("最大值为 maxDouble2:"+maxDouble2);
    double maxDouble3 = Arrays.stream(list).mapToDouble(Double::doubleValue)
        .summaryStatistics().getMax();
    System.out.println("最大值为 maxDouble3:"+maxDouble3);

    int maxInteger = integers.stream().max(Integer::compareTo).get();
    System.out.println("最大值为 maxInteger:"+maxInteger);
}
Optional<Emp> max = list.stream().collect(Collectors.maxBy(Employee::getSalary));

6.1.4、求和

/**
 * @desc <p>求和 <p>
 * @author hubz
 * @date 2020/8/9 14:20
 */
public static void sum(){
    Double[] list = {0.69D, 1D, 1.2, 5.6};
    double[] doubles = {0.15D,2D,2.3,93.1};
    List<Integer> integers = Arrays.asList(0, 1, 2, 56);


    // 求和
    double sum = Stream.of(list).mapToDouble(Double::doubleValue).sum();
    System.out.println("和为 sum:"+sum);
    double sum1 = Stream.of(list).mapToDouble(Double::doubleValue).summaryStatistics().getSum();
    System.out.println("和为 sum1:"+sum1);
    double sum2 = Arrays.stream(doubles).sum();
    System.out.println("和为 sum2:"+sum2);

    Integer sumInt = integers.stream().reduce(0,Integer::sum);
    System.out.println("和为 sumInt:"+sumInt);

    Integer sumInt1 = integers.stream().reduce(Integer::sum).get();
    System.out.println("和为 sumInt1:"+sumInt1);
}

6.2、对象

/**
 * @desc <p> 对象操作 <p>
 * @author hubz
 * @date 2020/8/9 13:24
 */
public static void testO() {
    List<BillsNums> billsNums = Arrays.asList(
            new BillsNums(1),
            new BillsNums(2),
            new BillsNums(4)
            );
    //求平均值
    int avgNum = billsNums.stream().collect(Collectors.averagingDouble(BillsNums::getNums)).intValue();
    System.out.println("平均值求法1:"+avgNum);
    avgNum = (int)billsNums.stream().mapToInt(BillsNums::getNums).summaryStatistics().getAverage();
    System.out.println("平均值求法2:"+avgNum);
    int asDouble = (int)Math.floor(billsNums.stream().mapToDouble(BillsNums::getNums)
                                   .average().orElse(0D));
    System.out.println("平均值求法3"+ asDouble);
    //根据这两个即可看出,对象和Double类似,其中方法均可使用
}

6.3、连接流中的字符串

String str = list.stream().map(Employee::getName).collect(Collectors.joining());

6.4、求结果集的size:包裹另一个函数,对其结果转换函数

public static void reduce2(){
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer collect = nums.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
System.out.println(collect);
}

7、高级应用

1、分组并统计数据

xx.stream().collect(Collectors.groupingBy(TmpData::getXX,Collectors.counting()));

2、根据对象属性过滤

xx.stream().filter(distinctByKey(TmpData::getIp)).collect(Collectors.toList());
public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor){
    Map<Object, Boolean> seen = new ConcurrentHashMap<>();
    return t->seen.putIfsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}

3、获取Map<String,Object>的最大值等

map.values().stream().mapToLong(Long::intValue).summaryStatistics().getMax();

map.entrySet().stream().max(Map.Entry.comparingByValue()).get().getValue();
//那既然可以这么做,那就可以对键进行排序

4、获取Map<String,Object>的最大值对应的键

map.entrySet().stream().max(Map.Entry.comparingByValue()).get().getKey();

5、分组+对组中数据进行去重统计

Map<String,List<TmpData>> preTmp = xx.stream().collect(Collectors.groupingBy(TmpData::getXX));//分组
Map<String,Long> tmp = new HashMap<>();
preTmp.forEach((k,v)->{tmp.put(k,v.stream().filter(distinctByKey(TmpData::getUserId)).count());});

6、读取文件并转换成字符串

String fileStr = Files.lines(Paths.get("simple_bean.xml")).collect(Collectors.joining());

7、读取CSV文件

8、分区:根据true和false分区

Map<Boolean, List<Double>> booleanListMap = Arrays.stream(list).collect(Collectors.partitioningBy(item -> {
            return item > 2;
        }));
        booleanListMap.forEach((k,v)->{
            System.out.println(k);
            v.forEach(System.out::println);
        });

8、注意

forEach 不能修改自己包含的本地变量值,也不能用break/return之类的关键字提前结束循环。