Springboot中Lambda表达式与Stream流

一、基础

1.函数式接口

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

实例:

/**
 * 自定义函数接口
 */
@FunctionalInterface
public interface InterFuncation<T>{
    /**
     * 函数型接口唯一抽象方法
     * @param t
     * @return
     */
    String hello(T t);

    /**
     * 可以增加默认方法
     */
    default void geha(){

    }
}

(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

三、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));
}

1函数式编程:

(1):断言型:

例程:

/**
 * 断言型接口
 */

static  void testlombdaPredicate() {
    List<String>aslist= Arrays.asList("lsit1","lsiajsj","sakskkai","sasi");

        //方法1
    List<String >stringList=userPrecas(aslist,name->name.contains("l"));
    log.info("姓名集合{}",stringList);
    List<String >stringList1=userPrecas(aslist,name->name.contains("i")||name.contains("a"));
    log.info("姓名集合包含i和a{}",stringList1);
}

    static List<String >userPrecas(List<String>aslist,Predicate<String>stringPredicate){
    //定义要返回的姓名集合
        List<String >returnname=new ArrayList<>();
        aslist.forEach(name->{
            if (stringPredicate.test(name)){
                returnname.add(name);
            }
        });
        return returnname;
    }

(2):消费型:

例程:

static void userlombdaConsumer(Double salary, Consumer<Double> consumerData) {
    consumerData.accept(salary);
}

(3)函数式:

例程:

//函数式接口
static  void testlambdaFuncator(){
    Function<Integer,Double>function=num->new Random(num).nextInt()*1.0;
    log.info("---------使用函数型接口,接受整数:{},返回浮点型结果:{}-----",65,function.apply(65));
}

2Lambda简介

(1)Lambda 可定义为一种简洁、可传递的匿名函数,它是推动Java 8发布的最重要新特性

(2)Lambda 本质上是一个函数,虽然它不属于某个特定的类,但具备参数列表、函数主体、返回类型,甚至能够抛出异常

(3)Lambda 是匿名的,它没有具体的函数名称

(4)Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)

(5)Lambda 可以使代码变的更加简洁

(6)基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

  • parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数。

  • ->:可以理解为被用于

  • 方法体:可以是表达式,也可以是代码,是函数式接口里方法的实现

  • (1)遍历集合

  • 实例:List<Integer>list= Arrays.asList(1,2,3,4,5);
    
    list.forEach(integer -> System.out.println(integer));

3 Stream流使用方法总结

什么是流?
流是一种处理数据的高级手段,任何数据都可以转化成流进行处理。对Stream流来说,比较常见数据源有集合、数组、IO等。

流的特点
1、只能遍历一次  
我们可以把流想象成一条流水线,流水线的源头是数据源,数据源中的每个元素是流的操作对象。

数据源中的元素被依次输送到流水线上,然后我们就可以对这些流水线上的元素进行各种操作,一旦元素走到了流水线的尽头,那么该元素也被“消费掉了”,之后在此次流水线上我们便无法再对该元素进行任何操作。

2、内部迭代
平常我们是赢得for循环、增强for等一些遍历操作都是显示的操作数据源,而stream流的遍历过程对我们来说是不可见的,采用的是内部迭代的方式遍历。
3流分别有限流和无限流

log.info("输出1,5,7,9的各自平方");
  Stream.of(1,3,5,7,9).forEach(num-> System.out.println(num*num+";"));
  //无限流;输出10个随机数
  log.info("输出前10个奇数");
  Stream.iterate(1,n->n+2).limit(10).forEach(num-> System.out.println(num+";"));
  //无限流;输出100以内,10个随机数
  log.info("-----输出100以内,10个随机数");
  Stream.generate(()->new Random().nextInt(100)).limit(10).forEach(System.out::println);

流的各种操作
1、中间操作
当数据源中的元素进到流水线上,同时在元素走到流尽头之前,这个过程中的所有操作都是“中间操作”,元素进行完中间操作之后依旧处于流水线上,所以我们还可以继续对元素进行中间操作;因此,中间操作的特点是,操作后的结果依旧是流。

(1)、filter过滤

filter函数接受一个Lambda表达式作为参数,该表达式返回一个boolean值,数据源中的每个元素都将传入filter进行Lambda表达式判断,最终过滤出表达式为true的元素。

List<Person> result = list.stream()
                    .filter(Person::isStudent)
                    .collect(toList());

(2)、map映射
map函数接受一个Lambda表达式作为参数,该表达式执行的返回值类型将用作一个新类型流输出,数据源中的每个元素都将传入map进行Lambda表达式执行,最后执行的结果将存入一个以表达式返回值类型为目标的新流。如下,Person类型流通过map操作转变成String类型流


List<String> result = list.stream()
                    .map(Person::getName)
                    .collect(toList());

(3)、sorted排序

在不指定比较器参数的情况下,默认使用自然排序。

Stream<Integer> stream = Stream.of(1, 3, 21, 54, 34, 6, 9, 7, 11);
List<Integer> collect = stream.sorted().collect(Collectors.toList());
for (Intege integer : collect) {
    System.out.print(integer+"  ");
}

如果指定比较器则按比较器的作用目标的值排序,如果目标的值是基本数据类型则按自然排序,如果想从大到小排序则可以在自然排序完后调用reversed()进行倒置

Stream<Integer> stream = Stream.of(1, 3, 21, 54, 34, 6, 9, 7, 11);
// 如果比较器的比较目标是基本数据类型则按自然排序即从小到大。
List<Integer> collect = stream.sorted(Comparator.comparingInt(Integer::intValue).reversed()).collect(Collectors.toList());
for (Integer integer : collect) {
    System.out.print(integer+"  ");
}

(4)、peek遍历流
通过peek遍历流中的元素后返回的结果依旧是这条流,peek和filter的区别是,filter相当于一个过滤网会对流上元素进行条件筛选,符合条件的元素会继续作为流元素往下游传递,而peek可以理解为对流元素进行加工处理,处理后的流元素会依旧作为流元素向下游传递。
Integer[] array = {1, 3, 21, 54, 34, 6, 9, 7, 11};
int length = array.length;
System.out.println("初始流元素个数:"+length);
Stream<Integer> stream = Arrays.stream(array);
long count = stream.peek(element -> System.out.print(element+"  ")).count();
System.out.println();
System.out.println("peek遍历后的流元素个数:"+count);

(5)、distinct去重

去掉重复的元素

Stream<String> stream = Stream.of("hello", "world","hello");
List<String> collect = stream.distinct().collect(Collectors.toList());

(6)、limit截取

从头开始截取指定数量的元素

// 截取数据源的前两个元素
List<String> strings = stream.limit(2).collect(Collectors.toList());

(7)、skip跳过

跳过从头开始指定数量的元素

// 跳过数据源的前两个元素
List<String> collect = stream.skip(2).collect(Collectors.toList());

2、终结操作
        当完成了所有我们想要进行的中间操作,也就意味着我们对此次数据源的流处理已经结束,所以,我们应当将处理后的数据源从流水线取出,而取出的值就是整个stream流的最终处理的结果。

1、collect收集

    collect方法用于收集流中间操作完后的元素,至于收集成哪种类型的数据结构需要通过Collectors收集器指定,常见的有Collectors.toList()、Collectors.toSet()

实例:

static void testStreamAPiSix(){
    log.info("--------------收集:collect-,收集为一个新的集合,保存下来-------------");
   List<Story> storyList=StoryUtil.stories.stream().filter(story -> story.getCategory().equals("玄幻")).collect(Collectors.toList());
    log.info("所有小说:{}",storyList);

    Set<String>catelsit=StoryUtil.stories.stream().map(Story::getCategory).collect(Collectors.toSet());
    log.info("所有小说(去重):{}",catelsit);

    Map<Integer,String> stringMap=StoryUtil.stories.stream().collect(Collectors.toMap(Story::getId,Story::getName));
    log.info("获取所有小说中,编号和名称map集合:{}",stringMap);


    Map<String  ,List<Story>> stringCateMap=StoryUtil.stories.stream().collect(Collectors.groupingBy(Story::getCategory));
    log.info("获取所有小说中,编号和名称map集合:{}",stringCateMap);

    Double avgPrice=StoryUtil.stories.stream().map(Story::getPrice).collect(Collectors.averagingDouble(Double::doubleValue));
    log.info("获取所有小说平均价格:{}",avgPrice);

}

3查找 / 匹配操作

allMatch是否匹配所有元素

anyMatch是否至少匹配一个元素

noneMatch是否没有匹配的所有元素

findFirst返回第一个元素

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

count返回流中元素的总个数

max返回流中最大值

min返回流中最小值

实例:

public class StreamMatch {
    List<Employee> employees = new ArrayList<>();

    {
        employees.add(new Employee(1, "张三", 20, 8895.31, true));
        employees.add(new Employee(2, "张四", 28, 7894.34, true));
        employees.add(new Employee(3, "张柳", 46, 6895.37, false));
        employees.add(new Employee(66, "王一", 54, 5895.5, true));
        employees.add(new Employee(56, "李四", 55, 4895.8, false));
        employees.add(new Employee(89, "李十一", 32, 9895.354, false));
        employees.add(new Employee(546, "张十五", 20, 18895.37, false));
        employees.add(new Employee(43, "刘十六", 43, 28895.35, true));
        employees.add(new Employee(66, "刘十六", 43, 28895.35, false));
    }

    /**
     * 测试allMatch()方法 检查是否匹配所有元素
     */
    @Test
    public void testStreamAllMatch() {
        boolean b = employees.stream().allMatch(employee -> employee.getSalary() > 5000);
        System.out.println("测试是不是所有的职工的工资都大于4000:" + b);
    }

    /**
     * 测试AnyMatch()方法 检查是否至少匹配一个元素
     */
    @Test
    public void testStreamAnyMatch() {
        boolean b = employees.stream().anyMatch(employee -> employee.getSalary() > 20000);
        System.out.println("测试是不是有一个职工的工资大于20000:" + b);
    }

    /**
     * 测试NoneMatch()方法 检查是否没有匹配所有元素
     */
    @Test
    public void testStreamNoneMatch() {
        boolean b = employees.stream().noneMatch(employee -> employee.getSalary() > 20000);
        System.out.println("测试是不是没有一个职工的工资大于20000:" + b);
    }

    /**
     * 测试findFirst方法 返回第一个元素
     */
    @Test
    public void testStreamFindFirst() {
        Optional<Employee> first = employees.stream().findFirst();
        System.out.println("流中的第一个元素:" + first.get());
    }

    /**
     * 测试findAny方法 返回当前流中的任意元素
     */
    @Test
    public void testStreamFindAny() {
        //串行流结果是一样的
        Optional<Employee> first = employees.stream().findAny();
        System.out.println("流中的任意元素(串行流):" + first.get());
        //并行的查询流中,工资大于5000,并且状态是TRUE的
        Optional<Employee> any = employees.parallelStream().filter(employee -> 
        employee.getSalary() > 5000 && employee.getStatus()).findAny();
        System.out.println("流中的任意元素(并行流):" + any.get());
    }

    /**
     * 测试max和min方法 返回当前流中的最大或者最小元素
     */
    @Test
    public void testStreamMaxOrMin() {
        Optional<Employee> max = employees.stream().max(Comparator.comparing(Employee::getSalary));
        System.out.println("流中的工资最大的元素(串行流):" + max.get());
        Optional<Employee> min = employees.stream().min(Comparator.comparing(Employee::getSalary));
        System.out.println("流中的工资最大的元素(串行流):" + min.get());
    }

}
 

2

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值