Java8函数式编程之七:Stream(流)的各种操作

时间:2021-10-07 17:01:28

上篇博客对流的基础知识进行了介绍,本篇博客将着重介绍关于流的各种操作,使用很多的实例代码,你只需要将其放进你的main函数中就能运行。

——————————————
创建流:

public class StreamTest1 {
    public static void main(String[] args){
        //流的创建方式
        //1.
        Stream stream1 = Stream.of("hello","world","hello world");
        //2.
        String[] array = new String[]{"hello","world"};
        Stream stream2 = Stream.of(array);
        //3.
        Stream stream3 = Arrays.stream(array);
        //4.通过结合创建,最常见的方式
        List<String> list = Arrays.asList(array);
        Stream stream4 = list.stream();

    }

}

————————————————

IntStream.of(new int[]{3,4,5,4,3,2,3,4,4,22,4}).forEach(System.out :: println);
//range()方法,范围 [3,6)
IntStream.range(3,8).forEach(System.out :: println);
//rangeClosed()方法,范围[3,8]
IntStream.rangeClosed(3,8);

————————————————————

//map()方法,映射
List<Integer> list = Arrays.asList(1,2,3,4,5);
System.out.print(list.stream().map(i -> i * 2).reduce(0,Integer :: sum));

————————————————————————

//构造流
Stream<String> stream = Stream.of("hello","world");
//遍历流
String[] array = stream.toArray(length -> new String[length]);
//方法引用
String[] array1 = stream.toArray(String[] :: new);
Arrays.asList(array).forEach(System.out ::println);
Arrays.asList(array1).forEach(System.out :: println);

————————————————————————————

Stream<String> stream = Stream.of("hello","world");
//将流转换为一个List
List<String> list = stream.collect(Collectors.toList());
list.forEach(System.out :: println);

————————————————————————————

//将流转换为Set
Stream<String> stream = Stream.of("hello","world");
Set<String> set = stream.collect(Collectors.toCollection(TreeSet ::new));
set.forEach(System.out :: println);

——————————————————

//拼接字符串
Stream<String> stream = Stream.of("hello","world");
String str = stream.collect(Collectors.joining()).toString();
System.out.print(str);

————————————————————————

//将集合中的每个元素转换为大写
List<String> list = Arrays.asList("hello","world","hello world");
list.stream().map(str -> str.toUpperCase()).collect(Collectors.toList()).forEach(System.out :: println);

————————————————

//flatMap 将每个List都平平方,再将其作为一个整体输出,也就是一个List。
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1,2),Arrays.asList(3,4,5),Arrays.asList(7,8,9));
stream.flatMap(theList -> theList.stream()).map(item -> item * item).forEach(System.out :: println);

————————————————

// generate()方法
Stream<String> stream = Stream.generate(UUID.randomUUID()::toString);
stream.findFirst().ifPresent(System.out::println);
// iterate方法
Stream.iterate(1, item -> item + 2).limit(6).forEach(System.out::println);

——————————————

// 找出流中大于2的元素,然后将每个元素乘以2,然后忽略掉流中的前两个元素,
// 再取流中的前两个元素,最后求出流中元素的总和
Stream<Integer> stream = Stream.iterate(1, item -> item + 2).limit(6);
System.out.println(stream.filter(item -> item > 2).mapToInt(item -> item * 2).skip(2).limit(2).sum());

——————————————

// 找出流中大于2的元素,然后将每个元素乘以2,然后忽略掉流中的前两个元素,
// 再取流中的前两个元素,最后求出流中最小的元素
// 注意 min()返回的是int的包装类型 OptionalInt
// 这样的区别在于返回的值是否能够为空,下面这种会抛出异常
 System.out.println(stream.filter(item -> item > 2).mapToInt(item -> item * 2).skip(2).limit(2).min());

——————————————————

List<String> list = Arrays.asList("hello", "world", "hello world");

//将集合的每个单词首字母变大写后输出
list.stream().map(item -> item.substring(0, 1).toUpperCase() + item.substring(1)).forEach(System.out :: println);

//下面没有任何输出 因为map操作是惰性求值的,也就是在没有遇到终止操作之前,是不会求值的。   惰性求值
list.stream().map(item -> {
    String result = item.substring(0, 1).toUpperCase() + item.substring(1);
    System.out.println("test");
    return result;
});


//下面将会有输出 。因为有终止信号 forEach()   立即求值
list.stream().map(item -> {
    String result = item.substring(0, 1).toUpperCase() + item.substring(1);
    System.out.println("test");
    return result;
}).forEach(System.out::println);

————————————————————

流的短路与并发流:

//对比串行流与并行流
List<String> list = new ArrayList<>(5000000);

for (int i = 0; i < 5000000; ++i) {
    list.add(UUID.randomUUID().toString());
}
System.out.println("开始排序");
long startTime = System.nanoTime(); // 时间更精确

// 串行流
// list.stream().sorted().count(); //花费9s ,只有一个线程

// 并行流
list.parallelStream().sorted().count(); // 花费5s , 多个线程

long endTime = System.nanoTime();

long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);

System.out.println("排序耗时: " + millis);

————————————————————————

流的短路:

// 将列表中长度为5的单词的长度打印出来。
      List<String> list = Arrays.asList("hello", "world", "hello world");

      list.stream().mapToInt(item -> item.length()).filter(length -> length
       == 5).findFirst().ifPresent(System.out :: println);

      // 对比下面的方式
      list.stream().mapToInt(item -> {
          int length = item.length();
          System.out.println(item);
          return length;
      }).filter(length -> length == 5).findFirst().ifPresent(System.out::println);

/* * 打印的结果 hello 5 这其实就是流的短路。找到了符合条件的,其他的就不再执行。 */

——————————————————————————

// 找出所有单词,并且去重.

List<String> list = Arrays.asList("hello welcome", "world hello", "hello world hello", "hello welcome");
// 输出的是四个数组对象
 list.stream().map(item -> item.split(" ")).distinct().collect(Collectors.toList()).forEach(System.out :: println);

// 应该使用flatMap . flatMap()的作用在于打平
List<String> reList = list.stream().map(item -> item.split(" ")).flatMap(Arrays::stream).distinct()
        .collect(Collectors.toList());
reList.forEach(System.out::println);

————————————————

流的分组与分区:

Student student1 = new Student("zhangsan", 100, 20);
      Student student2 = new Student("lisi", 90, 20);
      Student student3 = new Student("wangwu", 50, 30);
      Student student4 = new Student("lisi", 90, 25);

      // 根据名字进行分组
/* * F 传统的方式 Map<String, List<Student>> 1.循环列表 2.取出学生的名字 * 3.检查map中是否存在该名字,不存在直接加到map中.存在则将map中的list对象取出来,然后将 student对象加到List中 * */

      // jdk8中提供的分组方式, 和SQL中的分组是一样的概念

      // 把对象加在流中
      List<Student> students = Arrays.asList(student1, student2, student3, student4);
      // 实现分组
      Map<String, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getName)); // 方法引用

      System.out.println(map);

      // 根据分数分组

      Map<Integer, List<Student>> map1 = students.stream().collect(Collectors.groupingBy(Student::getScore)); // 方法引用

      System.out.println(map1);


      // 求每个分组后的平均值

      Map<String, Double> map3 = students.stream()
              .collect(Collectors.groupingBy(Student::getName, Collectors.averagingDouble(Student::getScore)));
      System.out.println(map3);

      // 分区: partition by .分区是分组的特殊情况。结果只会有两组
      Map<Boolean, List<Student>> map4 = students.stream()
              .collect(Collectors.partitioningBy(student -> student.getScore() > 90));

      System.out.println(map4);

——————————————————————————————