基于Spring Boot应用Java的Stream流API

记录:292

场景:Stream流操作基本步骤一般归纳为:Stream流的创建、Stream流的中间操作、Stream流的终止操作。以数据源List为例,先把List<E>转换为Stream<E>;再对Stream<E>进行中间操作,比如使用Stream的filter函数筛选;最后使用Stream的forEach遍历输出结果。

版本:

JDK 1.8
Spring Boot 2.6.3

一、基础

1.函数式接口

(1)使用@FunctionalInterface注解标记的接口,接口中有且只有一个抽象方法。

(2)接口中的默认方法、静态方法等不计入抽象方法。

(3)JDK 1.8及其后续版本。

(4)函数入参中使用函数式接口,本质就是重写函数式接口中的抽象方法。

(5)函数入参中有函数式接口定义的参数是,使用Lambda表达式或者匿名类实现抽象方法是常用的方式。

(6)Stream流式编程中的API中大量使用了函数式接口作为入参。

2.Lambda 表达式

Lambda表达式,是Java 8 发布的重要特性。

Lambda允许把函数作为一个方法的参数,即函数作为参数传递进方法中。

Lambda表达式是代码变得更加简洁和紧凑。

Lambda表达式语法规则:

#方式一:
(parameters) -> expression
#方式二:
(parameters) ->{ expression; }

3.对<? super T>和<? extends R>理解

对<? super T>和<? extends R>理解,就是对泛型的理解。

3.1 概念理解

<? super T>:表示?匹配的类型都是T的父类,包括T本身。

<? extends R>:表示?匹配的类型都是类型R的子类,包括R本身

3.2 使用List协助理解

3.2.1 List<? super T>

List<? super T> list:表示集合中存放的都是T的父类(包括T本身)。

针对变量List<? super T> list。

(1)对List做添加(add(T))操作,必须使用T或者T的子类添加到list中。

(2)对List做遍历查询操作,必须使用T父类去遍历list,取出元素。

小结:拿到一个变量使用? super T修饰时,应该是对该变量做添加操作,不做查询操作。这种方式修饰叫做put原则。

3.2.2 List<? extends R> 

List<? extends R> list:表示集合中存放的都是R的子类(包括R本身)。

针对变量List<? extends R> list。

(1)对List做添加(add(R))操作,必须使用R或者R的子类添加到list中。

(2)对List做遍历查询操作,必须使用R遍历list,取出元素.

小结:拿到一个变量使用? extends R修饰时,应该是对该变量做查询或取元素操作,不做添加操作。这种方式修饰叫做get原则。

二、Stream基础

1.Stream接口位置

(1)在jdk中,java.util.stream包下,存放的都是Stream相关的接口和实现类。

(2)在jdk中,Stream路径:java.util.stream.Stream。

Stream是interface类型,继承BaseStream和AutoCloseable接口。

BaseStream路径:java.util.stream.BaseStream。

AutoCloseable路径:java.lang.AutoCloseable

2.Stream理解

Stream,基于lambda表达式,是对集合对象功能的增强,以一种声明的方式处理数据。可以执行过滤、映射数据、查找、聚合等操作。

3.Stream操作

Stream的操作,一般归纳为3个步骤。

3.1 Stream流的创建

要操作流,需获取流,可以从集合、数组、或者Stream的静态方法创建流。

比如:

(1)java.util.Collection的Stream<E> stream()方法,那么实现Collection接口的类均可获取流。比如:java.util.List的实现类;java.util.Set的实现类;Map转换为流使用Map的entrySet等方法,这些方法返回值是Set。

(2)java.util.Arrays的stream方法,可以把数组转换为Stream。而且Arrays工具类重载了各种型式的stream方法,可以满足大部分从数组转换为Stream的需求。

(3)Stream的静态方法创建Stream流,比如of方法。

3.2 Stream流的中间操作

操作Stream流,比如filter过滤操作、map一个流转换为另一个流程、sorted排序、distinct去重等操作。

3.3 Stream流的终止操作

Stream流的终止操作后,可以从流中生成结果,其结果可以是任何不是流的值。比如forEach遍历结果、collect转换为其它型类型式。

4.stream包的几个Stream接口

java.util.stream包的几个Stream接口。Stream、IntStream、LongStream、DoubleStream接口都继承BaseStream。

java.util.stream.BaseStream
java.util.stream.Stream
java.util.stream.IntStream
java.util.stream.LongStream
java.util.stream.DoubleStream

三、Stream应用

本例根据操作Stream的3个基本步骤,把函数分为3类,在逐个应用。

1.应用Stream流的创建函数

应用Stream流的创建方式,使用这些函数可以从数据源获取Stream流。

1.1 操作场景

操作场景,就是函数功能。

(1)使用List获取Stream流。

(2)使用Map获取Stream流。

(3)使用List获取Stream流。

(4)使用List获取Stream流。

(5)使用Stream.of获取Stream流

(6)使用Stream.Builder获取Stream流。

(7)使用Stream.generate获取Stream流。

(8)使用Stream.iterate获取Stream流。

(9)使用Stream.concat合并两个流。

(10)使用Stream.empty获取空流。

1.2 操作实例

操作实例,就是函数应用。

/**
 * 1.1使用List获取Stream流
 */
public static void f1_1() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream = list.stream();
  // 3.遍历Stream流
  stream.forEach(girlVo -> {
      System.out.println(girlVo.toString());
  });
}

/**
 * 1.2使用Map获取Stream流
 */
public static void f1_2() {
  // 1.获取数据(Map)
  Map<String, Object> map = getMap();
  // 2.获取Stream流(使用Map)
  Stream<Map.Entry<String, Object>> stream = map.entrySet().stream();
  // 3.遍历Stream流
  stream.forEach(girlVo -> System.out.println(girlVo.toString()));
}

/**
 * 1.3使用List获取Stream流
 */
public static void f1_3() {
  // 1.获取数据(set)
  Set<GirlVo> list = getSet();
  // 2.获取Stream流(使用set)
  Stream<GirlVo> stream = list.stream();
  // 3.遍历Stream流
  stream.forEach(girlVo -> {
      System.out.println(girlVo.toString());
  });
}

/**
 * 1.4使用List获取Stream流
 */
public static void f1_4() {
  // 1.获取数据(数组)
  String[] cityArray = new String[]{"厦门", "杭州", "苏州", "北京"};
  // 2.获取Stream流(使用数组)
  Stream<String> stream = Arrays.stream(cityArray);
  // 3.遍历Stream流
  stream.forEach(System.out::println);
}

/**
 * 1.5使用Stream.of获取Stream流
 */
public static void f1_5() {
  // 1.使用Stream.of获取Stream流(单个元素)
  Stream<String> stream01 = Stream.of("杭州");
  // 2.使用Stream.of获取Stream流
  Stream<String> stream02 = Stream.of("北京", "杭州", "厦门", "苏州");
  stream02.forEach(System.out::println);
}

/**
 * 1.6使用Stream.Builder获取Stream流
 */
public static void f1_6() {
  // 1.创建Builder
  Stream.Builder<Object> builder = Stream.builder();
  // 2.添加元素
  builder.add("北京");
  builder.add("苏州");
  // 3.创建Stream
  Stream<Object> stream = builder.build();
  // 4.遍历Stream
  stream.forEach(System.out::println);
}

/**
 * 1.7使用Stream.generate获取Stream流
 */
public static void f1_7() {
  Stream<Double> stream04 = Stream.generate(Math::random);
  stream04.forEach(num -> System.out.println("generate: " + num));
}

/**
 * 1.8使用Stream.iterate获取Stream流
 */
public static void f1_8() {
  Stream<Long> stream05 = Stream.iterate(30L, ele -> (ele + 2));
  stream05.forEach(num -> System.out.println("iterate: " + num));
}

/**
 * 1.9 使用Stream.concat合并两个流
 */
public static void f1_9() {
  // 1.使用Stream.of获取Stream流
  Stream<String> stream0401 = Stream.of("北京", "杭州");
  Stream<String> stream0402 = Stream.of("厦门", "苏州");
  // 2.使用Stream.concat合并两个流
  Stream<String> stream04 = Stream.concat(stream0401, stream0402);
  stream04.forEach(num -> System.out.println("合并流: " + num));
}

/**
 * 1.10  使用Stream.empty获取空流
 */
public static void f1_10() {
  // 1.使用Stream.empty获取空流
  Stream<GirlVo> stream01 = Stream.empty();
}

2.应用Stream流的中间操作函数

应用Stream流的中间操作函数,使用这些函数对Stream流进行操作,操作的结果还是Stream流。

2.1 操作场景

操作场景,就是函数功能。

(1)应用Stream的filter,做过滤筛选操作。

(2)应用Stream的map,把Stream<GirlVo>转换为Stream<Object>。

(3)应用Stream的mapToInt,把Stream<GirlVo>转换为IntStream。

(4)应用Stream的mapToLong,把Stream<GirlVo>转换为LongStream。

(5)应用Stream的mapToDouble,把Stream<GirlVo>转换为DoubleStream。

(6)应用Stream的flatMap,把List<List<GirlVo>>转换为Stream<GirlVo>。

(7)应用Stream的flatMapToInt,把List<List<GirlVo>>转换为IntStream。

(8)应用Stream的flatMapToLong,把List<List<GirlVo>>转换为LongStream。

(9)应用Stream的flatMapToDouble,把List<List<GirlVo>>转换为DoubleStream。

(10)应用Stream的distinct去重。

(11)应用Stream的sorted排序。

(12)应用Stream的sorted排序。

(13)应用Stream的peek调试。

(14)应用Stream的limit,限制数量。

(15)应用Stream的skip,跳过指定个数元素。

2.2 操作实例

操作实例,就是函数应用。

/**
 * 2.1 应用Stream的filter,做过滤筛选操作
 * 案例: 找出B罩杯,年龄最小的女孩.
 */
public static void f2_1() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream = list.stream();
  // 3.Stream的filter的使用
  OptionalLong optionalLong = stream.filter(girlVo -> Objects.equals(
                  girlVo.getCupSize(), "B"))
          .mapToLong(GirlVo::getAge).min();
  // 4.获取结果
  if (optionalLong.isPresent()) {
      System.out.println("B罩杯,年龄最小的女孩: " + optionalLong.getAsLong());
  }
}

/**
 * 2.2 应用Stream的map
 * 案例: 把Stream<GirlVo>转换为Stream<Object>
 */
public static void f2_2() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream = list.stream();
  // 3.Stream<GirlVo>转换为Stream<Object>
  Stream<Object> objStream = stream.map(girlVo -> {
      Object obj = girlVo.getGirlName();
      return obj;
  });
  // 4.遍历结果
  objStream.forEach(obj -> {
      System.out.println("Girl的名称: " + obj.toString());
  });
}

/**
 * 2.3 应用Stream的mapToInt
 * 案例: 把Stream<GirlVo>转换为IntStream
 */
public static void f2_3() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream = list.stream();
  // 3.Stream<GirlVo>转换为IntStream
  IntStream intStream = stream.mapToInt(girlVo -> {
      int girlId = Integer.parseInt(girlVo.getGirlId());
      return girlId;
  });
  // 4.遍历结果
  intStream.forEach(girlId -> {
      System.out.println("Girl的ID: " + girlId);
  });
}

/**
 * 2.4 应用Stream的mapToLong
 * 案例: 把Stream<GirlVo>转换为LongStream
 */
public static void f2_4() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream = list.stream();
  // 3.Stream<GirlVo>转换为LongStream
  LongStream longStream = stream.mapToLong(girlVo -> {
      long girlId = girlVo.getAge();
      return girlId;
  });
  // 4.使用LongStream的average求平均值
  OptionalDouble opt = longStream.average();
  if (opt.isPresent()) {
      System.out.println("Girl的平均年龄: " + opt.getAsDouble());
  }
}

/**
 * 2.5 应用Stream的mapToDouble
 * 案例: 把Stream<GirlVo>转换为DoubleStream
 */
public static void f2_5() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream = list.stream();
  // 3.Stream<GirlVo>转换为DoubleStream
  DoubleStream doubleStream = stream.mapToDouble(girlVo -> {
      double height = girlVo.getHeight();
      return height;
  });
  // 4.使用DoubleStream的max求最大值
  OptionalDouble opt = doubleStream.max();
  if (opt.isPresent()) {
      System.out.println("身高最高的girl身高: " + opt.getAsDouble());
  }
}

/**
 * 2.6 应用Stream的flatMap
 * 案例: 把List<List<GirlVo>>转换为Stream<GirlVo>
 */
public static void f2_6() {
  // 1.获取数据(List<List<GirlVo>>)
  List<List<GirlVo>> list = getMultiList();
  // 2.List<List<GirlVo>>转换为Stream<GirlVo>
  Stream<GirlVo> stream = list.stream().flatMap(mapper -> {
      return mapper.stream();
  });
  // 3.遍历结果
  stream.forEach(obj -> {
      System.out.println("遍历信息: " + obj.toString());
  });
}

/**
 * 2.7 应用Stream的flatMapToInt
 * 案例: 把List<List<GirlVo>>转换为IntStream
 */
public static void f2_7() {
  // 1.获取数据(List<List<GirlVo>>)
  List<List<GirlVo>> list = getMultiList();
  // 2.List<List<GirlVo>>转换为IntStream
  IntStream stream = list.stream().flatMapToInt(mapper -> {
      Stream<GirlVo> girlStream = mapper.stream();
      return girlStream.mapToInt(girl -> {
          return (int) girl.getAge();
      });
  });
  // 3.遍历结果
  stream.forEach(age -> {
      System.out.println("年龄: " + age);
  });
}

/**
 * 2.8 应用Stream的flatMapToLong
 * 案例: 把List<List<GirlVo>>转换为LongStream
 * 相当于: 把List<List<GirlVo>>循环遍历2次直接在Stream中完成
 */
public static void f2_8() {
  // 1.获取数据(List<List<GirlVo>>)
  List<List<GirlVo>> list = getMultiList();
  // 2.List<List<GirlVo>>转换为LongStream
  LongStream stream = list.stream().flatMapToLong(mapper -> {
      Stream<GirlVo> girlStream = mapper.stream();
      return girlStream.mapToLong(girl -> Long.parseLong(girl.getGirlId()));
  });
  // 3.遍历结果
  stream.forEach(age -> {
      System.out.println("年龄: " + age);
  });
}

/**
 * 2.9 应用Stream的flatMapToDouble
 * 案例: 把List<List<GirlVo>>转换为DoubleStream
 */
public static void f2_9() {
  // 1.获取数据(List<List<GirlVo>>)
  List<List<GirlVo>> list = getMultiList();
  // 2.List<List<GirlVo>>转换为LongStream
  DoubleStream stream = list.stream().flatMapToDouble(mapper -> {
      Stream<GirlVo> girlStream = mapper.stream();
      // Lambda表达式写法
      return girlStream.mapToDouble(GirlVo::getHeight);
  });
  // 3.遍历结果
  stream.forEach(height -> {
      System.out.println("身高: " + height);
  });
}

/**
 * 2.10 应用Stream的distinct去重
 * 案例: 应用Stream的distinct去重
 * 原理: 去重根据Object.equals(Object)判断
 * Girl01是从写了equals(Object obj)和 hashCode(),去重效果才会生效
 */
public static void f2_10() {
  // 1.获取数据(List)
  List<Girl01> list = getList01();
  // 2.获取Stream流(使用List)
  Stream<Girl01> stream01 = list.stream();
  // 3.使用distinct去重
  Stream<Girl01> stream02 = stream01.distinct();
  // 4.遍历结果
  stream02.forEach(Girl01 -> {
      System.out.println("Girl信息: " + Girl01);
  });
}

/**
 * 2.11 应用Stream的sorted排序
 * 案例: 应用Stream的sorted排序
 */
public static void f2_11() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream01 = list.stream();
  // 3.使用sorted排序
  Stream<Long> stream02 = stream01.map(GirlVo::getAge).sorted();
  // 4.遍历结果
  stream02.forEach(girl -> {
      System.out.println("Girl年龄: " + girl);
  });
}

/**
 * 2.12 应用Stream的sorted排序
 * 案例: 应用Stream的sorted排序
 */
public static void f2_12() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream01 = list.stream();
  // 3.使用sorted排序 int compare(T o1, T o2);o1-o2代表正序排序,o2-o1代表倒序排序
  Stream<GirlVo> stream02 = stream01.sorted((girl01, girl02) -> {
      return (int) (girl01.getAge() - girl02.getAge());
  });
  // 4.遍历结果
  stream02.forEach(girl -> {
      System.out.println("Girl信息: " + girl);
  });
}

/**
 * 2.13 应用Stream的peek调试
 * 案例: 应用Stream的peek对流操作中的流水线进行调试
 */
public static void f2_13() {
  // 1.获取数据(List)
  List<GirlVo> list = getList();
  // 2.应用Stream的peek记录调试过程
  Stream<GirlVo> stream01 = list.stream().peek(girlVo -> {
        System.out.println("首次peek: " + girlVo);
    }).filter(girlVo -> girlVo.getAge() > 25)
    .peek(girlVo -> {
        System.out.println("filter后peek: " + girlVo);
    }).sorted((girl01, girl02) -> {
        return (int) (girl01.getAge() - girl02.getAge());
    }).peek(girlVo -> {
        System.out.println("sorted后peek: " + girlVo);
    });
  // 3.遍历结果
  stream01.forEach(girl -> {
      System.out.println("forEach遍历girl信息: " + girl);
  });
}

/**
 * 2.14 应用Stream的limit,限制数量
 * 案例: 应用Stream的limit,限制数量
 */
public static void f2_14() {
  // 1.获取数据(List)
  List<GirlVo> list01 = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream01 = list01.stream();
  // 3.应用Stream的limit
  List<GirlVo> list0101 = stream01.limit(2).collect(Collectors.toList());
}

/**
 * 2.15 应用Stream的skip,跳过指定个数元素
 * 案例: 应用Stream的skip,跳过指定个数元素
 */
public static void f2_15() {
  // 1.获取数据(List)
  List<GirlVo> list02 = getList();
  // 2.获取Stream流(使用List)
  Stream<GirlVo> stream02 = list02.stream();
  // 3.应用Stream的skip
  List<GirlVo> list0201 = stream02.skip(2).collect(Collectors.toList());
}

3.应用Stream流的终止操作函数

应用Stream流的终止操作函数,使用这些函数对Stream流进行操作后,生成结果不是Stream流了,而是一个期待类型的结果值。

3.1 操作场景

操作场景,就是函数功能。

(1)应用Stream的forEach和forEachOrdered遍历结果。

(2)应用Stream的toArray将流转换为数组。

(3)应用Stream的reduce,做累加操作。

(4)应用Stream的collect,将流转换为集合。

(5)应用Stream的collect,将流转换为连续字符串。

(6)应用Stream的collect,将流转换为List集合。

(7)应用Stream的collect,对流做分组操作,转换为Map<String, List<GirlVo>>。

(8)应用Stream的collect,对流做分组操作,转换为Map<String, Map<Long, List<GirlVo>>>。

(9)应用Stream的min,找到最小值。

(10)应用Stream的max,找到最大值。

(11)应用Stream的count,找到元素个数。

(12)应用Stream的anyMatch,有一个匹配则true。

(13)应用Stream的allMatch,全部匹配则true。

(14)应用Stream的noneMatch,不存在则true。

(15)应用Stream的findFirst,找到第一个元素。

(16)应用Stream的findAny,找到任意一个元素。

3.2 操作实例

操作实例,就是函数应用。

/**
 * 3.1 应用Stream的forEach遍历结果
 * 案例: 应用Stream的forEach和forEachOrdered
 */
public static void f3_1() {
  // 1.1 获取数据(List)
  List<GirlVo> list03 = getList();
  // 1.2 获取Stream流(使用List)
  Stream<GirlVo> stream03 = list03.stream();
  // 1.3 使用forEach遍历结果
  stream03.forEach(girlVo -> System.out.println("girl信息: " + girlVo));
  // 2.1 获取数据(List)
  List<GirlVo> list04 = getList();
  // 2.2 获取Stream流(使用List)
  Stream<GirlVo> stream04 = list04.stream();
  // 2.3 使用forEachOrdered遍历结果
  stream04.forEachOrdered(girlVo -> System.out.println("girl信息Ordered: " + girlVo));
}

/**
 * 3.2 应用Stream的toArray
 * 案例: 应用Stream的toArray将流转换为数组
 */
public static void f3_2() {
  // 1.1 获取数据(List)
  List<GirlVo> list05 = getList();
  // 1.2 获取Stream流(使用List)
  Stream<GirlVo> stream05 = list05.stream();
  // 1.3 应用toArray将Stream流转换为数组
  Object[] objs = stream05.toArray();
  // 2.1 获取数据(List)
  List<GirlVo> list06 = getList();
  // 2.2 获取Stream流(使用List)
  Stream<GirlVo> stream06 = list06.stream();
  // 2.3 应用toArray将Stream流转换为数组
  Object[] objs2 = stream06.toArray(GirlVo[]::new);
}

/**
 * 3.3 应用Stream的reduce
 * 案例: 应用Stream的reduce,做累加操作
 */
public static void f3_3() {
  // 1.1 获取数据(List)
  List<GirlVo> list01 = getList();
  // 1.2.获取Stream流(使用List)
  LongStream stream01 = list01.stream().mapToLong(GirlVo::getAge);
  // 1.3 应用reduce求和操作
  OptionalLong opt01 = stream01.reduce((a, b) -> a + b);
  if (opt01.isPresent()) {
      System.out.println("输出值: " + opt01.getAsLong());
  }
  // 2.1 获取数据(List)
  List<GirlVo> list02 = getList();
  // 2.2.获取Stream流(使用List)
  LongStream stream02 = list02.stream().mapToLong(GirlVo::getAge);
  // 2.3 应用reduce求和操作
  long opt02 = stream02.reduce(100, (a, b) -> a + b);
  System.out.println("输出值: " + opt02);
  // 3.1 获取Stream流(Stream.of)
  Stream<Integer> stream = Stream.of(100, 200, 300, 400);
  // 3.2 应用reduce求和操作
  Integer result = stream.reduce(0, Integer::sum, Integer::sum);
  System.out.println("result" + result);
}

/**
 * 3.4 应用Stream的collect
 * 案例: 应用Stream的collect,将流转换为集合
 */
public static void f3_4() {
  // 1.获取Stream流(Stream.of)
  Stream<String> stringStream0101 = Stream.of("北京", "杭州", "厦门", "苏州");
  // 2.应用Stream的collect,将流转换为集合
  List<String> asList0101 = stringStream0101.collect(ArrayList::new, ArrayList::add,
        ArrayList::addAll);
  System.out.println("asList0101: " + asList0101);
}

/**
 * 3.5 应用Stream的collect
 * 案例: 应用Stream的collect,将流转换为连续字符串
 */
public static void f3_5() {
  // 1.获取Stream流(Stream.of)
  Stream<String> stringStream02 = Stream.of("北京,", "杭州,", "厦门,", "苏州,", "是不错的城市.");
  // 2.应用Stream的collect,将流转换为连续字符串
  String concat = stringStream02.collect(StringBuilder::new, StringBuilder::append,
          StringBuilder::append).toString();
  System.out.println("concat: " + concat);
}

/**
 * 3.6 应用Stream的collect
 * 案例: 应用Stream的collect,将流转换为List集合
 */
public static void f3_6() {
  // 1.获取Stream流(Stream.of)
  Stream<String> stringStream0201 = Stream.of("北京", "杭州", "郑州", "厦门", "苏州");
  // 2.应用Stream的collect,将流转换为List
  List<String> asList0201 = stringStream0201.collect(Collectors.toList());
  System.out.println("asList0201: " + asList0201);
}

/**
 * 3.7 应用Stream的collect
 * 案例: 应用Stream的collect,对流做分组操作,转换为Map<String, List<GirlVo>>
 */
public static void f3_7() {
  // 1.获取Stream流(Stream.of)
  Stream<GirlVo> girlStream0201 = getList().stream();
  // 2.应用Stream的collect,将流分组转换为Map<String, List<GirlVo>>
  Map<String, List<GirlVo>> girlByCupSize = girlStream0201.collect(Collectors.groupingBy(GirlVo::getCupSize));
  System.out.println("girlByCupSize: " + girlByCupSize);
}

/**
 * 3.8 应用Stream的collect
 * 案例: 应用Stream的collect,对流做分组操作,转换为Map<String, Map<Long, List<GirlVo>>>
 */
public static void f3_8() {
  // 1.获取Stream流(使用List)
  Stream<GirlVo> girlStream0202 = getList().stream();
  // 2.应用Stream的collect,对流做分组操作,转换为Map<String, Map<Long, List<GirlVo>>>
  Map<String, Map<Long, List<GirlVo>>> girlByCupSizeAndAge
          = girlStream0202.collect(Collectors.groupingBy(GirlVo::getCupSize,
          Collectors.groupingBy(GirlVo::getAge)));
  System.out.println("peopleByCupSizeAndAge: " + girlByCupSizeAndAge);
}

/**
 * 3.9 应用Stream的min
 * 案例: 应用Stream的min,找到最小值
 */
public static void f3_9() {
  // 1.获取Stream流(Stream.of)
  Stream<Long> stream01 = Stream.of(100L, 200L, 300L);
  // 2.应用Stream的min,求最小值
  Optional<Long> opt01 = stream01.min((o1, o2) -> (int) (o1 - o2));
  // 3.获取结果
  if (opt01.isPresent()) {
      System.out.println("opt01: " + opt01);
  }
}

/**
 * 3.10 应用Stream的max
 * 案例: 应用Stream的max,找到最大值
 */
public static void f3_10() {
  // 1.获取Stream流(Stream.of)
  Stream<Long> stream02 = Stream.of(100L, 200L, 300L);
  // 2.应用Stream的max,求最小值
  Optional<Long> opt02 = stream02.max((o1, o2) -> (int) (o1 - o2));
  // 3.获取结果
  if (opt02.isPresent()) {
      System.out.println("opt02: " + opt02);
  }
}

/**
 * 3.11 应用Stream的count
 * 案例: 应用Stream的count,找到元素个数
 */
public static void f3_11() {
  // 1.获取Stream流(Stream.of)
  Stream<Long> stream03 = Stream.of(100L, 200L, 300L);
  // 2.应用Stream的count,求元素个数
  long opt03 = stream03.count();
  // 3.打印结果
  System.out.println("opt03: " + opt03);
}

/**
 * 3.12 应用Stream的anyMatch
 * 案例: 应用Stream的anyMatch,有一个匹配则true
 */
public static void f3_12() {
  // 1.获取Stream流(使用List)
  Stream<GirlVo> girlStream01 = getList().stream();
  // 2.应用Stream的anyMatch,有一个匹配则true
  boolean result01 = girlStream01.anyMatch(girl -> Objects.equals(girl.getCupSize(), "B"));
  // 3.打印结果
  System.out.println("是否有B罩杯: " + result01);
}

/**
 * 3.13 应用Stream的allMatch
 * 案例: 应用Stream的allMatch,全部匹配则true
 */
public static void f3_13() {
  // 1.获取Stream流(使用List)
  Stream<GirlVo> girlStream02 = getList().stream();
  // 2.应用Stream的anyMatch,全部匹配则true
  boolean result02 = girlStream02.allMatch(girl -> Objects.equals(girl.getCupSize(), "B"));
  // 3.打印结果
  System.out.println("是否所有的都是B罩杯: " + result02);
}

/**
 * 3.14 应用Stream的noneMatch
 * 案例: 应用Stream的noneMatch,不存在则true
 */
public static void f3_14() {
  // 1.获取Stream流(使用List)
  Stream<GirlVo> girlStream03 = getList().stream();
  // 2.应用Stream的anyMatch,不存在则true
  boolean result03 = girlStream03.noneMatch(girl -> Objects.equals(girl.getCupSize(), "G"));
  // 3.打印结果
  System.out.println("是否所有的都是G罩杯: " + result03);
}

/**
 * 3.15 应用Stream的findFirst
 * 案例: 应用Stream的findFirst,找到第一个元素
 */
public static void f3_15() {
  // 1.获取Stream流(使用List)
  Stream<String> stringStream01 = Stream.of("北京", "杭州", "厦门", "苏州");
  // 2.应用Stream的findFirst,找到第一个元素
  Optional<String> opt01 = stringStream01.findFirst();
  // 3.打印结果
  opt01.ifPresent(city -> System.out.println("第一个: " + city));
}

/**
 * 3.16 应用Stream的findAny
 * 案例: 应用Stream的findAny,找到任意一个元素
 */
public static void f3_16() {
  // 1.获取Stream流(使用List)
  Stream<String> stringStream02 = Stream.of("北京", "杭州", "郑州", "厦门", "苏州");
  // 2.应用Stream的findAny,找到任意一个元素
  Optional<String> opt02 = stringStream02.findAny();
  // 3.打印结果
  opt02.ifPresent(city -> System.out.println("任意一个: " + city));
}

4.本例生成数据的函数和Java Bean对象

测试验证需要数据,生成辅助类和方法。

4.1 Java Bean对象

Java Bean对象,包括GirlVo和Girl01,主要使用GirlVo。Girl01在做去重时使用到,因为重写了基类Object的equals(Object obj)和 hashCode()。

(1)GirlVo

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class GirlVo {
  /**ID号*/
  String girlId;
  /**姓名*/
  String girlName;
  /**年龄*/
  long age;
  /**身高*/
  double height;
  /**罩杯*/
  String cupSize;
}

(2)Girl01

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Girl01 {
  /**ID号*/
  String girlId;
  /**姓名*/
  String girlName;
  /**年龄*/
  long age;
  /**身高*/
  double height;
  /**罩杯*/
  String cupSize;
  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    Girl01 var = (Girl01) obj;
    return (Objects.equals(this.girlId, var.girlId));
  }
  @Override
  public int hashCode() {
    return Objects.hash(girlId);
  }
}

4.2 生成数据的函数

生成数据的函数,包括以下几个。

(1)获取List数据,在List中存放GirlVo对象。

(2)获取Map数据,在Map中存放(key,value)对应(girlId,GirlVo)。

(3)获取Set数据,在Set中存放GirlVo对象。

(4)获取List<List<GirlVo>>。

(5)获取List数据,在List中存放Girl01对象。

/**
 * 获取List数据,在List中存放GirlVo对象
 */
public static List<GirlVo> getList() {
  List<GirlVo> list = new ArrayList<>();
  GirlVo girl01 = GirlVo.builder().girlId("1001").girlName("张一").age(27).height(169).cupSize("F").build();
  GirlVo girl02 = GirlVo.builder().girlId("1002").girlName("王二").age(29).height(175).cupSize("B").build();
  GirlVo girl03 = GirlVo.builder().girlId("1003").girlName("刘五").age(24).height(160).cupSize("B").build();
  GirlVo girl04 = GirlVo.builder().girlId("1004").girlName("陈六").age(21).height(168).cupSize("C").build();
  GirlVo girl05 = GirlVo.builder().girlId("1005").girlName("赵七").age(25).height(169).cupSize("C").build();
  GirlVo girl06 = GirlVo.builder().girlId("1006").girlName("张八").age(26).height(165).cupSize("A").build();
  list.add(girl01);
  list.add(girl02);
  list.add(girl03);
  list.add(girl04);
  list.add(girl05);
  list.add(girl06);
  return list;
}

/**
 * 获取Map数据,在Map中存放(key,value)对应(girlId,GirlVo)
 */
public static Map<String, Object> getMap() {
  Map<String, Object> map = new HashMap<>();
  List<GirlVo> list = getList();
  Stream<GirlVo> stream = list.stream();
  stream.forEach(girlVo -> {
      map.put(girlVo.getGirlId(), girlVo);
  });
  return map;
}

/**
 * 获取Set数据,在Set中存放GirlVo对象
 */
public static Set<GirlVo> getSet() {
  Set<GirlVo> set = new HashSet<>();
  List<GirlVo> list = getList();
  Stream<GirlVo> stream = list.stream();
  stream.forEach(girlVo -> {
      set.add(girlVo);
  });
  return set;
}

/**
 * 获取List<List<GirlVo>>
 */
public static List<List<GirlVo>> getMultiList() {
  List<GirlVo> list01 = new ArrayList<>();
  List<GirlVo> list02 = new ArrayList<>();
  List<List<GirlVo>> list = new ArrayList<>();
  GirlVo girl01 = GirlVo.builder().girlId("1001").girlName("张一").age(27).height(169).cupSize("F").build();
  GirlVo girl02 = GirlVo.builder().girlId("1002").girlName("王二").age(29).height(175).cupSize("B").build();
  GirlVo girl03 = GirlVo.builder().girlId("1003").girlName("刘五").age(24).height(160).cupSize("B").build();
  GirlVo girl04 = GirlVo.builder().girlId("1004").girlName("陈六").age(21).height(168).cupSize("C").build();
  GirlVo girl05 = GirlVo.builder().girlId("1005").girlName("赵七").age(25).height(169).cupSize("C").build();
  GirlVo girl06 = GirlVo.builder().girlId("1006").girlName("张八").age(26).height(165).cupSize("A").build();
  list01.add(girl01);
  list01.add(girl02);
  list01.add(girl03);
  list02.add(girl04);
  list02.add(girl05);
  list02.add(girl06);
  list.add(list01);
  list.add(list02);
  return list;
}

/**
 * 获取List数据,在List中存放Girl01对象
 * Girl01是重写了equals(Object obj)和 hashCode()
 * 在使用distinct时去重根据重写规则判断
 */
public static List<Girl01> getList01() {
  List<Girl01> list = new ArrayList<>();
  Girl01 girl01 = Girl01.builder().girlId("1001").girlName("张一").age(27).height(169).cupSize("F").build();
  Girl01 girl02 = Girl01.builder().girlId("1002").girlName("王二").age(29).height(175).cupSize("B").build();
  Girl01 girl03 = Girl01.builder().girlId("1003").girlName("刘五").age(24).height(160).cupSize("B").build();
  Girl01 girl04 = Girl01.builder().girlId("1004").girlName("陈六").age(21).height(168).cupSize("C").build();
  Girl01 girl05 = Girl01.builder().girlId("1005").girlName("赵七").age(25).height(169).cupSize("C").build();
  Girl01 girl06 = Girl01.builder().girlId("1001").girlName("张一").age(27).height(169).cupSize("F").build();
  list.add(girl01);
  list.add(girl02);
  list.add(girl03);
  list.add(girl04);
  list.add(girl05);
  list.add(girl06);
  return list;
}

四、小结

在研究API时,训练是一方面。归纳和分类有助于理解整体思路以及API应用场景。

以上,感谢。

2022年8月21日

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值