吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1281|回复: 2
收起左侧

[Java 转载] 笔记 Java8 Stream API

[复制链接]
saz 发表于 2021-11-22 13:11

Stream API

Stream API 三部曲

  • 创建流
  • 中间操作
  • 中止操作

1. 创建流

/*
    * 1. 创建Stream的方式
    */
// collection.stream()
Stream<Employee> stream1 = employees.stream();

// Arrays.stream(T[] array)
Stream<Employee> stream2 = Arrays.stream(empArr);

// Stream.of(T[] arr)
Stream<Employee> empArr = Stream.of(this.empArr);

// Stream.iterate(seed,UnaryOperator<>)
Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);

// Stream.generate(Supplier<>)
Stream<Double> stream5 = Stream.generate(() -> Math.random());

2. 中间操作

2.0 一次加载,惰性求值

  • 如果没有终止操作,中间操作不会有任何输出

    /**
    * 无中止操作是么有任何输出的,因为Stream是一次加载,“惰性求值”
    */
    @Test
    public void test02() {
      employees.stream().filter(e -> {
          System.out.println("中间操作:" + e.getName() + "是" + e.getAge() + "岁");
          return e.getAge() > 35;
      });
    }

2.1 筛选

/**
     * 中间操作
     * 筛选
     * 筛选年纪大于35岁的人员
     * 内部迭代输出
     */
@Test
public void test01() {
    employees.stream()
        .filter(e -> {
            System.out.println("中间操作:" + e.getName() + "是" + e.getAge() + "岁");
            return e.getAge() > 35;
        })
        .forEach(System.out::println);
}

2.2 切片

2.2.1 limit

limit(Long num)—— 截断前num个元素,之后不会向后迭代

 /**
     * 切片操作
     * 只取前两个
     */
@Test
public void test05() {
    employees.stream()
        .limit(2)
        .forEach(System.out::println);
}

limit切片会导致短路,也即是不会继续向后迭代:

/**
     * 切片操作
     * limit会造成短路
     */
@Test
public void test05_2() {
    employees.stream()
        .filter(employee -> {
            System.out.println("短路");
            return employee.getSalary()>3000;
        })
        .limit(2)
        .forEach(System.out::println);
}
2.2.2 skip

Skip(Long num) —— 跳过前num个元素

/**
     * 切片操作
     * 跳过前两个
     */
@Test
public void test06() {
    employees.stream()
        .skip(2)
        .forEach(System.out::println);
}

2.3 排序

2.3.1 自然排序

Stream<T> sorted();

/**
     * 自然排序
     */
@Test
public void test03_1(){
    int[] arr = {1,5,9,3,2,7,6,9};
    Arrays.stream(arr).sorted().forEach(System.out::println);
}
2.3.2 定制排序

复杂的对象需要定制排序规则

Stream<T> sorted(Comparator<? super T> comparator);

/**
     * 排序操作
     * 按照工资正序排序
     */
@Test
public void test03() {
    employees.stream()
        .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
        .forEach(System.out::println);
}

2.4 去重

2.4.1 默认去重

Stream<T> distinct();

/**
     * 去重操作
     * 通过流生成的hashCode和equals方法去重
     * 若是对象没有重写hashcode和equals方法,将无法成功去重
     */
@Test
public void test04() {
     employees.stream()
     .distinct()
     .forEach(System.out::println);
}
2.4.4 定制去重

参考: https://blog.csdn.net/haiyoung/article/details/80934467

​         https://www.concretepage.com/java/jdk-8/java-8-distinct-example

a 重写Employee的hashCode 和 equals方法

因为sorted()是基于 hashCode() 和 equals() 方法进行工作,所以第一个方法是重写这两个方法。

b 借助filter过滤

Stream<T> filter(Predicate<? super T> predicate);

  • 创建去重的规则,返回Predicate类型
static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {

        Map<Object, Boolean> employeeMap = new ConcurrentHashMap<>();
        return e -> employeeMap.putIfAbsent(keyExtractor.apply(e), Boolean.TRUE) == null;
    }
  • 使用
/**
     * 对象去重
     * 按照指定的方式去重
     */
@Test
public void test04_1() {
    employees.stream()
        .filter(distinctByKey(employee -> employee.getId()))
        .forEach(System.out::println);
}

2.5 映射

2.5.1 map映射

对流中每一个元素进行操作

 /**
     * map
     * 对每一个元素进行操作
     */
@Test
public void test01(){
    employees.stream().map(employee -> employee.getName().toLowerCase()).forEach(System.out::println);
}

提取对象的元素

/**
     * map
     * 提取元素
     */
@Test
public void test02(){
    employees.stream().map(Employee::getName).distinct().forEach(System.out::println);
}

狸猫换太子

需要遍历map ,找到所有value(对象列表)添加新对象

// dailyMap,目前已有的map -- Map<String, List<CapitalDaily>>
Map<String, List<CapitalDaily>> map = dailyMap.entrySet().stream().map(entry -> {
            String key = entry.getKey();
            List<CapitalDaily> value = entry.getValue();
            List<CapitalDaily> dailies = value.stream().filter(li -> null != li.getDate() && li.getDate().equals(date)).filter(i -> i.getBalance() != null).collect(Collectors.toList());
            BigDecimal balance = dailies.get(dailies.size() - 1).getBalance();
            BigDecimal creditAmount = value.stream().filter(li -> null != li.getDate() && li.getDate().equals(date)).filter(i -> i.getCreditAmount() != null).map(CapitalDaily::getCreditAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal debitAmount = value.stream().filter(li -> null != li.getDate() && li.getDate().equals(date)).filter(i -> i.getDebitAmount() != null).map(CapitalDaily::getDebitAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            CapitalDaily daily = new CapitalDaily();
//            daily.setDate(date);
            daily.setBalance(balance.equals(BigDecimal.valueOf(0)) ? null : balance);
            daily.setCreditAmount(creditAmount.equals(BigDecimal.valueOf(0)) ? null : creditAmount);
            daily.setDebitAmount(debitAmount.equals(BigDecimal.valueOf(0)) ? null : debitAmount);
            ArrayList<CapitalDaily> newDaily = new ArrayList<>(value);
            newDaily.add(daily);
            return new AbstractMap.SimpleEntry<>(key, newDaily);
        }).collect(Collectors.toMap(Map.Entry::<String, List<CapitalDaily>>getKey, Map.Entry::<String, List<CapitalDaily>>getValue));

        return map;
2.5.2 flatMap映射
/**
     * flatMap
     * 将字符串拆分打印
     */
@Test
public void test03(){
    Stream<Stream<Character>> streamStream = list.stream()
        .map(Demo03_map::departString);
    streamStream.forEach(s -> s.forEach(System.out::println));

    System.out.println("===============  biu~~ =======================");

    Stream<Character> characterStream = list.stream()
        .flatMap(Demo03_map::departString);
    characterStream.forEach(System.out::println);
}

 /**
     * 切割字符串的方法,返回一个流
     * @Param str 要切割的字符串
     * @Return characters.stream():Stream<Character>
     */
public static Stream<Character> departString(String str){
    List<Character> characters = new ArrayList<>();
    for (char c : str.toCharArray()) {
        characters.add(c);
    }
    return characters.stream();
}

3. 终止操作

3.1 查找与匹配

3.1.1 allMatch 是否匹配所有元素
/**
     * matchAll,是否匹配所有元素
     */
@Test
public void test01(){
    boolean b = employees.stream()
        .allMatch(employee -> employee.getAge() > 25);
    System.out.println(b); // false
}
3.1.2 anyMatch 是否匹配至少一个元素
/**
     *         anyMatch 是否匹配到至少一个元素
     */
@Test
public void test02(){
    boolean b = employees.stream()
        .anyMatch(employee -> employee.getAge() > 25);
    System.out.println(b); // true
}
3.1.3 noneMatch 是否没有匹配所有元素
/**
     *         noneMatch 是否没有匹配所有元素
     */
@Test
public void test03(){
    boolean b = employees.stream()
        .noneMatch(employee -> employee.getAge() > 25);
    System.out.println(b); // false
}

@Test
public void test03_1(){
    boolean b = employees.stream()
        .noneMatch(employee -> employee.getAge() > 125);
    System.out.println(b); // true
}
3.1.4 findFirst 返回第一元素
/**
     *         findFirst 返回第一元素
     */
@Test
public void test04(){
    Optional<Employee> first = employees.stream()
        .filter(employee -> employee.getAge() > 25)
        .findFirst();
    System.out.println(first); // false
}
3.1.5 findAny 返回任意元素
/**
     *  findAny 返回任意元素
     */
@Test
public void test05(){
    Optional<Employee> first = employees.stream()
        .filter(employee -> employee.getAge() < 25)
        .findAny();
    System.out.println(first);
}
3.1.6 count 返回流中元素总个数
 /**
     * count 返回流中元素总个数
     */
@Test
public void test06(){
    long count = employees.stream().count();
    System.out.println(count); // 7
}
3.1.7 max 返回流中最大值
 /**
     * max 返回流中最大值
     */
@Test
public void test07(){
    Optional<Employee> max = employees.stream()
        .max((e1, e2) -> e1.getAge() - e2.getAge());
    System.out.println(max==null?"null":max.get().getAge()); // 93
}
3.1.8 min 返回流中最小值
/**
     * min 返回流中最小值
     */
@Test
public void test08(){
    Employee employee = employees.stream()
        .min((e1, e2) -> e1.getAge() - e2.getAge()).orElse(null);
    System.out.println(employee==null?"null":employee.getAge()); // 23
    // Employee【id=2, name='SI LI', salary=4500.0, age=23】
    System.out.println(employee);  
}

3.2 归约和收集

3.2.1 reduce

reduce  -- -- -- 将流中元素反复结合,得到一个新的值

 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
/**
     * 归约,求和
     */
@Test
public void test01(){
    Integer sum = list.stream()
        .reduce(1, (t, s) -> t + s);// 初始为1
    System.out.println(sum); // 46
}
/**
     * 获取员工工资总和
     *      map-reduce 模式
     */
@Test
public void test02(){
    Double salarySum = employees.stream()
        .map(Employee::getSalary)
        // .reduce((double) 0, (s1, s2) -> s1 + s2);
        .reduce(Double::sum).orElse(0.0D);
    System.out.println(salarySum); // 44500.0
}
3.2.2 collectors
1 toList()/toSet()
/**
     * 收集名字到list/set里
     */
@Test
public void test01() {
    List<String> list = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.toList());
    list.forEach(System.out::println);
    System.out.println("===========================");
    Set<String> set = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.toSet());
    set.forEach(System.out::println);
}
2 HashSet/LinkedHashSet
/**
     * 收集名字到HashSet/LinkedHashSet里
     */
@Test
public void test02() {
    Set<String> set = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.toCollection(LinkedHashSet::new));
    set.forEach(System.out::println);
}

 ArrayList<IdtCorpBasic> disList = list.stream().collect(
                    Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(IdtCorpBasic::getUscc))), ArrayList::new)
            );
3 计数 count
/**
     * 总数
     */
@Test
public void test03() {
    Long count = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.counting());
    // [or]  .count();
    System.out.println(count); // 7
}
4 平均值 averagingDouble
/**
     * 平均值
     */
@Test
public void test04() {
    double count = employees.stream()
        .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println(count); // 6357.142857142857
    System.out.println(String.format("0.00", count)); //  0.00

}
5 最大值 maxBy
/**
     * 最大值
     */
@Test
public void test05() {
    Employee employee = employees.stream()
        .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))).orElse(null);
    System.out.println(employee.getSalary()); // 9000.0
6 最小值 minBy
 /**
     * 最小值
     */
@Test
public void test06() {
    Double minSalary = employees.stream()
        .map(Employee::getSalary)
        .collect(Collectors.minBy(Double::compare)).orElse(null);
    System.out.println(minSalary); // 3500.0
}
7 分组 groupingBy
/**
     * 分组
     */
@Test
public void test07_1() {
    Map<Integer, List<Employee>> byAge = employees.stream()
        .collect(Collectors.groupingBy(Employee::getAge));
    for (Map.Entry<Integer, List<Employee>> age : byAge.entrySet()) {
        System.out.println(age.getKey() + ":" + age.getValue());
    }
}

/**
     * 多属性拼接为key
     */
@Test
public void test07_2() {
    Map<String, List<Employee>> byIdAndName = employees.stream()
        .collect(Collectors.groupingBy(e -> ((Employee) e).getId() + "--" + ((Employee) e).getName()));
    for (Map.Entry<String, List<Employee>> map : byIdAndName.entrySet()) {
        System.out.println(map.getKey() + ":" + map.getValue());
    }
}
/**
     * 多级分组
     */
@Test
public void test08() {
    Map<String, Map<Object, List<Employee>>> levMap = employees.stream()
        .collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy(e -> {
            if (((Employee) e).getAge() <= 35) {
                return "青年";
            } else if (((Employee) e).getAge() <= 55) {
                return "中年";
            } else {
                return "老年";
            }
        })));

    System.out.println(levMap.getClass());// class java.util.HashMap

    for (Map.Entry<String, Map<Object, List<Employee>>> lev : levMap.entrySet()) {
        System.out.println(lev.getKey() + ":" + lev.getValue());
    }
}
8 分区 partitioningBy
/**
     * 分区
     *  返回一个map,内部有key为true和false的两个对象列表
     */
@Test
public void test09(){
    Map<Boolean, List<Employee>> depart = employees.stream()
        .collect(Collectors.partitioningBy(e -> e.getAge() > 30)
                );
    for (Map.Entry<Boolean, List<Employee>> part : depart.entrySet()) {
        System.out.println(part.getKey() + ":" + part.getValue());
    }
    /*
false:[Employee【id=2, name='SI LI', salary=4500.0, age=23】, Employee【id=4, name='SA ZHANG', salary=9000.0, age=25】, Employee【id=4, name='LIU ZHAO', salary=9000.0, age=25】]
true:[Employee【id=1, name='SA ZHANG', salary=3500.0, age=93】, Employee【id=1, name='SA ZHANG', salary=3500.0, age=93】, Employee【id=3, name='WU WANG', salary=6000.0, age=54】, Employee【id=5, name='QI A', salary=9000.0, age=35】]
         */
}
9 拼接 joining
/**
     * 拼接
     */
@Test
public void test11(){
    String names = employees.stream()
        .map(Employee::getName)
        // prefix和suffix是拼接之后,整体的前后缀
        .collect(Collectors.joining(",", "=", "=")); 
    System.out.println(names);
}

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
limanwuai001 + 1 + 1 hahaha ~这该死的群友java基础竟如此扎实 手动狗头

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| saz 发表于 2021-11-22 14:40
瞅瞅图片
I}]12(8861WP9VN0U)F($L3.jpg
unmask 发表于 2021-11-22 22:12
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 11:58

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表