JAVA8 Stream运用

Java利用stream将一个List中部分字段复制到另一个List中

例:将MyCrmBaseCustomerInfo的lisi结果复制到UpCustCustomerVO的list中
说明【1、res代指 listParentList 中的每一个数据 2、UpCustCustomerVO类需要有构造参数getCustCode、getName 3、赋值的顺序需要和构造参数顺序一致,CustCode在前,Name在后,顺序乱则赋值乱。】

List<MyCrmBaseCustomerInfo> listParentList = baseMapper.queryPartentInfoTwo(partentList);
List<UpCustCustomerVO> list= listParentList.stream()
.map(res ->new UpCustCustomerVO(res.getCustCode(),res.getName()))
.collect(Collectors.collect)

根据单个条件找出重复数据

List<String> prodCdRepeat = prodVoList.stream().filter(f -> StringUtils.isNotEmpty(f.getProdCdDis()))
                    .map(ImportProdVo::getProdCdDis).collect(Collectors.groupingBy(Function.identity()))
                    .values().stream()
                    .filter(list -> list.size() > 1)
                    .flatMap(Collection::stream).collect(Collectors.toList());

根据多个条件找出重复数据

List<ImportProdVo> prodVoRepeat = prodVoList.stream().collect(Collectors.groupingBy(p -> p.getProdNm() + p.getSpec()
                            + p.getModel() + p.getBrand()))
                    .values().stream()
                    .filter(list -> list.size() > 1)
                    .flatMap(Collection::stream).collect(Collectors.toList());

如果对象不为空

Optional.ofNullable(whVoOne).ifPresent(t -> { 
system.out.print("代码体");
});
Optional.ofNullable(whZoneVo).ifPresent(t -> {
                            item.setUpdPgmId(pgmId);
                            item.setUpdUserId(userId);
                            item.setUpdUserNm(userNm);
                            CommonUtils.setCommonInfo(item, request);
                            //去除已更新的数据
                            zoneVos.remove(whZoneVo);
                        });

**提取id属性,转List **

//提取属性转List<String>
List<String> list = CollectionUtil.getFieldValues(updBoxDetails, "id", String.class);

一、流的初始化与转换:
Java中的Stream的所有操作都是针对流的,所以,使用Stream必须要得到Stream对象:
1、初始化一个流:

  Stream stream = Stream.of("a", "b", "c");

2、数组转换为一个流:

  String [] strArray = new String[] {"a", "b", "c"};
  stream = Stream.of(strArray);
  或者
  stream = Arrays.stream(strArray);

3、集合对象转换为一个流(Collections):

  List<String> list = Arrays.asList(strArray);
    stream = list.stream();

二、流的操作:
流的操作可以归结为几种:

1、遍历操作(map):
使用map操作可以遍历集合中的每个对象,并对其进行操作,map之后,用.collect(Collectors.toList())会得到操作后的集合。

1.1、遍历转换为大写:
List output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList());

1.2、平方数:
List nums = Arrays.asList(1, 2, 3, 4);
List squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());

2、过滤操作(filter):
使用filter可以对象Stream中进行过滤,通过测试的元素将会留下来生成一个新的Stream。
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
int count = strings.stream().filter(string -> string.isEmpty()).count();

2.1、得到其中不为空的String
List filterLists = new ArrayList<>();
filterLists.add(“”);
filterLists.add(“a”);
filterLists.add(“b”);
List afterFilterLists = filterLists.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());

3、循环操作(forEach):
如果只是想对流中的每个对象进行一些自定义的操作,可以使用forEach:
List forEachLists = new ArrayList<>();
forEachLists.add(“a”);
forEachLists.add(“b”);
forEachLists.add(“c”);
forEachLists.stream().forEach(s-> System.out.println(s));

4、返回特定的结果集合(limit/skip):
limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素:
List forEachLists = new ArrayList<>();
forEachLists.add(“a”);
forEachLists.add(“b”);
forEachLists.add(“c”);
forEachLists.add(“d”);
forEachLists.add(“e”);
forEachLists.add(“f”);
List limitLists = forEachLists.stream().skip(2).limit(3).collect(Collectors.toList());
注意skip与limit是有顺序关系的,比如使用skip(2)会跳过集合的前两个,返回的为c、d、e、f,然后调用limit(3)会返回前3个,所以最后返回的c,d,e

5、排序(sort/min/max/distinct):
sort可以对集合中的所有元素进行排序。max,min可以寻找出流中最大或者最小的元素,而distinct可以寻找出不重复的元素:

5.1、对一个集合进行排序:
List sortLists = new ArrayList<>();
sortLists.add(1);
sortLists.add(4);
sortLists.add(6);
sortLists.add(3);
sortLists.add(2);
List afterSortLists = sortLists.stream().sorted((In1,In2)->In1-In2).collect(Collectors.toList());

5.2、得到其中长度最大的元素:
List maxLists = new ArrayList<>();
maxLists.add(“a”);
maxLists.add(“b”);
maxLists.add(“c”);
maxLists.add(“d”);
maxLists.add(“e”);
maxLists.add(“f”);
maxLists.add(“hahaha”);
int maxLength = maxLists.stream().mapToInt(s->s.length()).max().getAsInt();
System.out.println(“字符串长度最长的长度为”+maxLength);

5.2.1、list对象中取某个字符串值的最大值(max)
在这里插入图片描述

5.4、根据某个字段进行分组

List<TManufOrdEx> batchNoManufOrdList = tManufOrds.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()-> new
            TreeSet<>(Comparator.comparing(TManufOrdEx :: getBatchNo))),ArrayList::new));

5.5、根据某个字段分组

List<TManufOrdEx> batchNoManufOrdList =  tManufOrds.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()-> new
            TreeSet<>(Comparator.comparing(e -> e.getDaySort() + ";" + e.getEnterVatOrdDt() + ";" + e.getMachineId() + ";"))),ArrayList::new));

5.6、根据某个字段分组【bigdecimal求和】

 List<TManufOrdEx> sumKgsList = tManufOrdExList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
                new TreeSet<>(Comparator.comparing(o ->o.getSellConLineNo()))),ArrayList::new));

  //筛选过后的订单总数求和
            tManufOrdEx.setSumKgs(BigDecimal.valueOf(sumKgsList.stream().mapToDouble(e->e.getKgs().doubleValue()).reduce(0,Double::sum)));

6、匹配(Match方法):
有的时候,我们只需要判断集合中是否全部满足条件,或者判断集合中是否有满足条件的元素,这时候就可以使用match方法:
allMatch:Stream 中全部元素符合传入的 predicate,返回 true
anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

6.1、判断集合中没有有为‘c’的元素:
List matchList = new ArrayList<>();
matchList.add(“a”);
matchList.add(“a”);
matchList.add(“c”);
matchList.add(“d”);
boolean isExits = matchList.stream().anyMatch(s -> s.equals(“c”));

6.2、判断集合中是否全不为空:
List matchList = new ArrayList<>();
matchList.add(“a”);
matchList.add(“”);
matchList.add(“a”);
matchList.add(“c”);
matchList.add(“d”);
boolean isNotEmpty = matchList.stream().noneMatch(s -> s.isEmpty());
则返回的为false

7.Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

实例1:

 List<RmInterview> rmInterviewList = Optional.ofNullable(interviewMapperCustom.selectByExample(rmInterviewExample)).map(
                                t->t.stream().filter(
                                        each->each.getMainInfoId().equals(maininfoid)
                                                &&each.getInterviewType().equals(finalInterviewType)
                                                && each.getDeleteFlag().equals(NumberUtils.toByte("0"))
                                ).collect(Collectors.toList())).orElse(Lists.newArrayList());

Stream 完整实例

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;
 
public class Java8Tester {
   public static void main(String args[]){
      System.out.println("使用 Java 7: ");
        
      // 计算空字符串
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("列表: " +strings);
      long count = getCountEmptyStringUsingJava7(strings);
        
      System.out.println("空字符数量为: " + count);
      count = getCountLength3UsingJava7(strings);
        
      System.out.println("字符串长度为 3 的数量为: " + count);
        
      // 删除空字符串
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("筛选后的列表: " + filtered);
        
      // 删除空字符串,并使用逗号把它们合并起来
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("合并字符串: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        
      // 获取列表元素平方数
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("平方数列表: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        
      System.out.println("列表: " +integers);
      System.out.println("列表中最大的数 : " + getMax(integers));
      System.out.println("列表中最小的数 : " + getMin(integers));
      System.out.println("所有数之和 : " + getSum(integers));
      System.out.println("平均数 : " + getAverage(integers));
      System.out.println("随机数: ");
        
      // 输出10个随机数
      Random random = new Random();
        
      for(int i=0; i < 10; i++){
         System.out.println(random.nextInt());
      }
        
      System.out.println("使用 Java 8: ");
      System.out.println("列表: " +strings);
        
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("空字符串数量为: " + count);
        
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("字符串长度为 3 的数量为: " + count);
        
      filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
      System.out.println("筛选后的列表: " + filtered);
        
      mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("合并字符串: " + mergedString);
        
      squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
      System.out.println("Squares List: " + squaresList);
      System.out.println("列表: " +integers);
        
      IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
        
      System.out.println("列表中最大的数 : " + stats.getMax());
      System.out.println("列表中最小的数 : " + stats.getMin());
      System.out.println("所有数之和 : " + stats.getSum());
      System.out.println("平均数 : " + stats.getAverage());
      System.out.println("随机数: ");
        
      random.ints().limit(10).sorted().forEach(System.out::println);
        
      // 并行处理
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("空字符串的数量为: " + count);
   }
    
   private static int getCountEmptyStringUsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.isEmpty()){
            count++;
         }
      }
      return count;
   }
    
   private static int getCountLength3UsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.length() == 3){
            count++;
         }
      }
      return count;
   }
    
   private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
      List<String> filteredList = new ArrayList<String>();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
             filteredList.add(string);
         }
      }
      return filteredList;
   }
    
   private static String getMergedStringUsingJava7(List<String> strings, String separator){
      StringBuilder stringBuilder = new StringBuilder();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
            stringBuilder.append(string);
            stringBuilder.append(separator);
         }
      }
      String mergedString = stringBuilder.toString();
      return mergedString.substring(0, mergedString.length()-2);
   }
    
   private static List<Integer> getSquares(List<Integer> numbers){
      List<Integer> squaresList = new ArrayList<Integer>();
        
      for(Integer number: numbers){
         Integer square = new Integer(number.intValue() * number.intValue());
            
         if(!squaresList.contains(square)){
            squaresList.add(square);
         }
      }
      return squaresList;
   }
    
   private static int getMax(List<Integer> numbers){
      int max = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
        
         Integer number = numbers.get(i);
            
         if(number.intValue() > max){
            max = number.intValue();
         }
      }
      return max;
   }
    
   private static int getMin(List<Integer> numbers){
      int min = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
         Integer number = numbers.get(i);
        
         if(number.intValue() < min){
            min = number.intValue();
         }
      }
      return min;
   }
    
   private static int getSum(List numbers){
      int sum = (int)(numbers.get(0));
        
      for(int i=1;i < numbers.size();i++){
         sum += (int)numbers.get(i);
      }
      return sum;
   }
    
   private static int getAverage(List<Integer> numbers){
      return getSum(numbers) / numbers.size();
   }
}

执行以上脚本,输出结果为:

$ javac Java8Tester.java 
$ java Java8Tester
使用 Java 7: 
列表: [abc, , bc, efg, abcd, , jkl]
空字符数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
平方数列表: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9
随机数: 
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
使用 Java 8: 
列表: [abc, , bc, efg, abcd, , jkl]
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数: 
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
空字符串的数量为: 2

java8 【Stream API 筛选与切片 映射 排序 查找与匹配 归约与收集】

筛选与切片

filter(Predicate) 筛选元素,从流中排除不满足Predicate的某些元素
limit(n) 截断流,使其元素不超过给定数量
skip(n) 跳过前面n个元素,若元素不足n个,则返回空流
distinct() 去重,通过流所生成元素的hashCode()与equals()去除重复元素

实体类

public class User {

    private String name;  // 姓名
    private String age;  // 年龄
    private double salary; // 薪水
    private Status status; // 工作状态:FREE 空闲, BUSY 繁忙 INVOCATION 休假

    public enum Status {
        BUSY, FREE, INVOCATION;
    }
    
    public User(){
        
    }

    public User(String name, String age, double salary, Status status) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.status = status;
    }
}

使用

 List<User> list = Arrays.asList(
                new User("张三", 21, 6000, User.Status.BUSY),
                new User("李四", 23, 7000, User.Status.FREE),
                new User("王五", 25, 6000, User.Status.INVOCATION),
                new User("赵六", 21, 10000, User.Status.BUSY),
                new User("赵六", 21, 10000, User.Status.BUSY)
        );

        // filter 筛选出BUSY状态的员工
        list.stream()
                .filter(u -> User.Status.BUSY.equals(u.getStatus()))
                .forEach(System.out::println);
                
        /*  结果:
            User{name='张三', age='21', salary=6000.0, status=BUSY}
            User{name='赵六', age='21', salary=10000.0, status=BUSY}
            User{name='赵六', age='21', salary=10000.0, status=BUSY}      
        */  

        // 筛选出工资等于6000的一个员工
        list.stream()
                .filter(u -> u.getSalary() == 6000)
                .limit(1)
                .forEach(System.out::println);
                
        /*  结果:
            User{name='张三', age='21', salary=6000.0, status=BUSY}   
        */  


        // 筛选工资等于6000,不是第一个员工的员工
        list.stream()
                .filter(u -> u.getSalary() == 6000)
                .skip(1)
                .forEach(System.out::println);
                
        /*  结果:
            User{name='王五', age='25', salary=6000.0, status=INVOCATION} 
        */          

        // 员工列表去重
        list.stream()
                .distinct()
                .forEach(System.out::println);

映射

map(Function<T, R>) 提取元素,使用Function应用到每个元素
flatMap(Function<T, Stream>) 提取元素,应用每个元素得到每一个新的Stream,然后将这些Stream合并成新的Stream

 public static void test() {
        List<String> list = Arrays.asList("abc", "def", "ghi");

        // 将每个元素(这里指的每个元素是指"abc", "def"这种),转换成大写
        list.stream()
                .map(String::toUpperCase)
                .forEach(System.out::print);
        
        /*  结果:
            ABCDEFGHI
        */            

        // 提取所有字符
        // 步骤:应用每个元素,比如"abc"将其转换成Stream<Charactor>,然后得到三个Stream<Charactor>,最终合并到一个新的Stream<Character>,类似于list.addAll
        list.stream()
                .flatMap(Test::strToCharator)  // ==> .flatMap(s -> strToCharator(s))
                .forEach(System.out::print);    
                        
        /*  结果:
            abcdefghi
        */ 
    }

    public static Stream<Character> strToCharator(String s){
        List<Character> list = new ArrayList<>();
        for (char c : s.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }  

    //区别

    Stream<Stream<Character>> characterStream = list.stream()
        .map(Test::strToCharator);
         characterStream.forEach(s -> s.forEach(System.out::println));
// s = Stream<Character> ,所有需要再迭代遍历一次,共两次   
// 变化为 "abc","bcd", "ghi" --> {a, b, c}, {b, c, d}, {g, h , i} --> {  {a, b, c}, {b, c, d}, {g, h , i}  }


Stream<Character> characterStream2 = list.stream()
        .flatMap(Test::strToCharator);
        characterStream2.forEach(System.out::println);
// 变化为 "abc","bcd", "ghi" -->  {a, b, c }, {b, c, d}, {g, h , i} -->  {a,b,c,d,e,f,g,h,i}


类比于List list1, List list2
list1.add(list2)     // 将list2作为list1的元素
list1.addAll(list2)  // 将list2中所有元素放入到list1中

排序

sorted() 自然排序
sorted(Comparator) 自定义排序

List<String> list = Arrays.asList("bcd", "abe", "afa");

        // 自然排序
        list.stream()
                .sorted()
                .forEach(System.out::println);

        // 按照string排序
        list.stream()
                .sorted(String::compareTo)
                .forEach(System.out::println);

        // 按照第二个元素排序        
        list.stream()
                .sorted((s1, s2) -> Character.valueOf(s1.charAt(1)).compareTo( Character.valueOf(s2.charAt(1))))
                .forEach(System.out::println);

        // 等于上面,使用工具类  Comparator 更加方便      
        list.stream()
                .sorted(Comparator.comparing(s -> s.charAt(1)))
                .forEach(System.out::println);

查找与匹配

allMatch 流中所有元素都匹配成功,返回true
anyMatch 流中匹配一个元素即返回true
noneMatch 流中所有元素都不匹配,返回true,与allMatch相反
findFirst 返回流中匹配的第一个元素
findAny 返回流中匹配到的第一个元素,由于可能是parallelStream并行方式,所以不等于findFirst
count 返回流中元素个数
max 返回流中最大值
min 返回流中最小值

  List<User> list = Arrays.asList(
                new User("张三", 21, 6000, User.Status.BUSY),
                new User("李四", 23, 7000, User.Status.FREE),
                new User("王五", 25, 6000, User.Status.INVOCATION),
                new User("赵六", 21, 10000, User.Status.BUSY)
        );

        // 1. 所有员工是否都处于BUSY状态
        boolean b = list.stream().allMatch(u -> User.Status.BUSY.equals(u.getStatus()));  // ==> false
        // 更好的方式: list.stream().map(User::getStatus).allMatch(User.Status.BUSY::equals)

        // 2. 至少有一个员工处理BUSY状态
        boolean b2 = list.stream().map(User::getStatus).anyMatch(User.Status.BUSY::equals);  // ==> true

        // 3. 所有员工都不处于BUSY状态
        boolean b3 = list.stream().map(User::getStatus).noneMatch(User.Status.BUSY::equals);  // ==> false

        // 4. 找出处于BUSY状态的第一个员工
        Optional<User> firstUser = list.stream().filter(u -> User.Status.BUSY.equals(u.getStatus())).findFirst();  // firstUser.get() 张三

        // 5. 找出任意一个处于BUSY状态的员工
        Optional<User> anyUser = list.parallelStream().filter(u -> User.Status.BUSY.equals(u.getStatus())).findAny(); // anyUser.get() 赵六

        // 6. 处于BUSY状态的员工数量
        long count = list.stream().map(User::getStatus).filter(User.Status.BUSY::equals).count();  // ==> 2

        // 7. 找到工资最高的员工
        Optional<User> maxSalaryUser = list.stream().max(Comparator.comparingDouble(User::getSalary)); // maxSalaryUser.get() 赵六

        // 8. 找到年龄最小的员工
        Optional<User> minAgeUser = list.stream().min(Comparator.comparingInt(User::getAge)); 

归约与收集

reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的元素反复结合起来,得到一个值
collect 将流转换成其他形式,接收

BinaryOperator extends BiFunction 所以是 T, T, R, 两个参数,一个返回值
reduce

 List<User> list = Arrays.asList(
                new User("张三", 21, 6000, User.Status.BUSY),
                new User("李四", 23, 7000, User.Status.FREE),
                new User("王五", 25, 6000, User.Status.INVOCATION),
                new User("赵六", 21, 10000, User.Status.BUSY)
        );

        int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        // 1. 数组所有元素求和
        int sum = Arrays.stream(arr).reduce(0, (x, y) -> x + y); // 55
        // 说明:这里identity=0,指代第一次运算的x=0,y=数组第一个元素,也就是1,如果identity=2,那么第一次就是x=2, y=1, 那么最终结果=56
        // 由于有第一次运算默认值,所以这里一定有返回值,所以设计为返回int,假设没有初始值,也就是下面这种,不确定元素是否足够,返回Optional

        OptionalInt optionalInt = Arrays.stream(arr).reduce((x, y) -> x + y); // optionalInt.getAsInt() == 55
        // OptionalInt 为 Optional 专门为int的包装类,比Optional<Integer>性能更好,减少装箱拆箱操作

        // 2. 计算所有员工工资总和
        Optional<Double> sumSalary = list.stream().map(User::getSalary).reduce(Double::sum); 

collect

List<User> list = Arrays.asList(
                new User("张三", 21, 6000, User.Status.BUSY),
                new User("李四", 23, 7000, User.Status.FREE),
                new User("王五", 25, 6000, User.Status.INVOCATION),
                new User("赵六", 21, 10000, User.Status.BUSY)
        );
        
                // ---------------------- 转换为集合 -------------------
        // collect(Collector),可以工具类Collectors生成Collector
        // 1. 获取员工姓名列表
        // 返回一个list
        List<String> userNameList = list.stream().map(User::getName).collect(Collectors.toList());
        // 返回set
        Set<String> userNameSet = list.stream().map(User::getName).collect(Collectors.toSet());
        // 返回hashSet
        HashSet<String> userNameHashSet = list.stream().map(User::getName).collect(Collectors.toCollection(HashSet::new));
        // ---------------------- 计算 ------------------------
        // 2. 得到员工数量
        // 总数
        Long count = list.stream().collect(Collectors.counting()); // == list.stream().count()
        // 工资大于5000员工数量
        Long salaryConditionCount = list.stream().map(User::getSalary).filter(s -> s > 5000).collect(Collectors.counting()); // == filter().count()

        // 3. 所有员工平均工资
        Double averagSalary = list.stream().collect(Collectors.averagingDouble(User::getSalary));
        // 4. 最高/最低工资
        Optional<Double> maxSalary = list.stream().map(User::getSalary).collect(Collectors.maxBy(Double::compare)); // == map().max()
        // -------------------- 分组 --------------------------
        // 类似于SQL中的group by
        // 5. 根据工作状态分组 (单级分组) { BUSY: List<User>, FREE: List<User> }
        Map<User.Status, List<User>> userMapByStatus = list.stream().collect(Collectors.groupingBy(User::getStatus));
        // 6. 先根据工作状态分组,再根据年龄分组 (多级分组){ BUSY: {21 : List<User>, 23 : List<User>}, FREE : { 25 : List<User>, 26 : List<User> } }
        Map<User.Status, Map<Integer, List<User>>> userMapByStatusAndAge = list.stream()
                .collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy(User::getAge)));
        // 7. 更多级分组
        Map<User.Status, Map<Integer, Map<Double, List<User>>>> userMapByStatusAndAgeAndSalary = list.stream()
                .collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getSalary))));
        // 8. 自定义分组,先按工作状态分组,再自定义下一次分组key,比如小于30岁,key为青年,大于30岁,key为中年
        // ==> { BUSY : { "青年" : List<User>, "老年" : List<User> }  }
        list.stream().collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy(u -> {
            User user = (User)u;
            if (user.getAge() < 30) {
                return "青年";
            } else {
                return "中年";
            }
        })));
        // ------------------ 分区 ------------------------
        // 特殊情况下的分组形式,分组条件结果为true/false,即 { true : List<xx>, false : List<xx> }
        // 9. 将工资大于6000的分一个区,小于等的分一个区 ==> {true : List<工资大于6000的User>, false : List<工资小于等于6000的User> }
        Map<Boolean, List<User>> partitionSalaryMap = list.stream().collect(Collectors.partitioningBy(u -> u.getSalary() > 6000));


        // ------------------ 统计 -----------------------
        // 返回一个统计结果相关的操作类,可用来得到最大值,最小值等等,当要获取一个集合的各项情况时,这种方式比较好,必须要生成多次流操作获取
        DoubleSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingDouble(User::getSalary));
        double summaryStatisticsSum = summaryStatistics.getSum();  // 总和,工资总数
        long summaryStatisticsCount = summaryStatistics.getCount(); // 总的个数,员工数
        double summaryStatisticsMax = summaryStatistics.getMax();  // 最高工资
        double summaryStatisticsMin = summaryStatistics.getMin(); // 最低工资
        double summaryStatisticsAverage = summaryStatistics.getAverage(); // 平均工资

merge

merge是什么?
merge() 可以这么理解:它将新的值赋值到 key (如果不存在)或更新给定的key 值对应的 value

merge源码参考

default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    Objects.requireNonNull(remappingFunction);
    Objects.requireNonNull(value);
    V oldValue = this.get(key);
    V newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value);
    if (newValue == null) {
        this.remove(key);
    } else {
        this.put(key, newValue);
    }

    return newValue;
}
//该方法接收三个参数,一个 key 值,一个 value,
//一个 remappingFunction ,如果给定的key不存在,它就变成了 put(key, value) 。
//但是,如果 key 已经存在一些值,
//我们  remappingFunction 可以选择合并的方式,
//然后将合并得到的 newValue 赋值给原先的 key。

merge() 怎么用?
假设有一个学生成绩对象的列表,对象包含学生姓名、科目、科目分数三个属性,要求求得每个学生的总成绩。加入列表如下:

private List<StudentScore> buildATestList() {
    List<StudentScore> studentScoreList = new ArrayList<>();
    StudentScore studentScore1 = new StudentScore() {{
        setStuName("张三");
        setSubject("语文");
        setScore(70);
    }};
    StudentScore studentScore2 = new StudentScore() {{
        setStuName("张三");
        setSubject("数学");
        setScore(80);
    }};
    StudentScore studentScore3 = new StudentScore() {{
        setStuName("张三");
        setSubject("英语");
        setScore(65);
    }};
    StudentScore studentScore4 = new StudentScore() {{
        setStuName("李四");
        setSubject("语文");
        setScore(68);
    }};
    StudentScore studentScore5 = new StudentScore() {{
        setStuName("李四");
        setSubject("数学");
        setScore(70);
    }};
    StudentScore studentScore6 = new StudentScore() {{
        setStuName("李四");
        setSubject("英语");
        setScore(90);
    }};
    StudentScore studentScore7 = new StudentScore() {{
        setStuName("王五");
        setSubject("语文");
        setScore(80);
    }};
    StudentScore studentScore8 = new StudentScore() {{
        setStuName("王五");
        setSubject("数学");
        setScore(85);
    }};
    StudentScore studentScore9 = new StudentScore() {{
        setStuName("王五");
        setSubject("英语");
        setScore(70);
    }};

    studentScoreList.add(studentScore1);
    studentScoreList.add(studentScore2);
    studentScoreList.add(studentScore3);
    studentScoreList.add(studentScore4);
    studentScoreList.add(studentScore5);
    studentScoreList.add(studentScore6);
    studentScoreList.add(studentScore7);
    studentScoreList.add(studentScore8);
    studentScoreList.add(studentScore9);

    return studentScoreList;
}

常规做法

ObjectMapper objectMapper = new ObjectMapper();
List<StudentScore> studentScoreList = buildATestList();

Map<String, Integer> studentScoreMap = new HashMap<>();
studentScoreList.forEach(studentScore -> {
    if (studentScoreMap.containsKey(studentScore.getStuName())) {
        studentScoreMap.put(studentScore.getStuName(), 
                            studentScoreMap.get(studentScore.getStuName()) + studentScore.getScore());
    } else {
        studentScoreMap.put(studentScore.getStuName(), studentScore.getScore());
    }
});

System.out.println(objectMapper.writeValueAsString(studentScoreMap));

结果如下

 {"李四":228,"张三":215,"王五":235}

merge() 实现

Map<String, Integer> studentScoreMap2 = new HashMap<>();
studentScoreList.forEach(studentScore -> studentScoreMap2.merge(
  studentScore.getStuName(),
  studentScore.getScore(),
  Integer::sum));

System.out.println(objectMapper.writeValueAsString(studentScoreMap2));

结果如下

{"李四":228,"张三":215,"王五":235}

使用场景
比如分组求和这类的操作,虽然 stream 中有相关 groupingBy() 方法,但如果你想在循环中做一些其他操作的时候,merge() 还是一个挺不错的选择的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值