Stream API详解(附22道练习题)

Stream API是 Java 8 引入的一种新特性,用于简化集合操作,支持函数式编程,便于并行处理,具有延迟计算的特点。

Stream API的优势在于代码简洁、内置丰富的操作,能够提高数据处理效率。

流的操作分为三个步骤:它包括创建流中间操作(如过滤、映射、排序等)和终止操作(如遍历、汇总、转换等),实现对集合的高效处理。


目录

一、什么是 Stream API

二、Stream API 的优势

三、什么是流

四、Stream 的三个操作

1.  创建流

2.  中间操作

3.  终止操作

五、Stream API 的练习

1. 基础练习

(1)计算整数列表的总和

(2)找出整数列表中的最大值

(3)计算整数列表中所有偶数的平均值

(4)筛选出一个整数列表中的偶数并打印

(5)将字符串列表中的每个元素转换为大写并收集到新的列表

​(6)对整数列表进行降序排序,并获取前3个元素

(7)将整数列表中的每个数字乘以2,并收集到一个新的列表中

(8)检查整数列表中是否所有数字都是正数

(9)找出整数列表中大于5的最小值

(10)检查整数列表中是否存在至少一个数字大于10

(11)检查整数列表中是否包含连续的数字

(12)将整数列表中的数字进行去重

(13)从字符串列表中找出最长的字符串

2. 进阶练习

(14)从员工(姓名、年龄)列表中找出年龄大于30岁的员工姓名列表

(15)计算列表中每个元素出现的次数

(16)对字符串列表按单词长度进行分组,并打印出每个长度组的单词列表

(17)将整数列表中的数字分为奇数和偶数,分别存储在不同的列表中

(18)将一个字符串列表中的每个字符串长度求和

(19)对员工列表按年龄分组,并打印每个年龄组的人数

(20)计算字符串中每个字符出现的次数

(21)给定两个字符串列表,合并这两个列表,并去除重复项,然后按字母顺序排序

(22)将字符串列表转换为Map,其中键是字符串,值是字符串长度


前置知识:Java集合

可参考 Java 集合用法和25道练习题-CSDN博客

进阶知识:Collectors

可参考 Collectors 详解-CSDN博客

一、什么是 Stream API

Stream API 是 Java 8 引入的一个新特性,它提供了一种处理集合的新方式,可以更简洁、更易读地操作数据。Stream API 可以用来处理集合中的元素,类似于使用 SQL 进行查询,可以进行过滤、映射、排序、聚合等操作。

以下是Stream API的一些关键概念:

  1. 源:Stream可以是从集合、数组、文件等生成的。
  2. 中间操作:诸如filter、map、sorted等操作会返回一个新Stream,这些操作不会修改原始数据源,它们返回的是一个新的Stream作为结果。
  3. 终端操作:诸如forEach、collect、reduce等操作,这些操作会返回一个结果或者一个副作用,比如对集合进行遍历、汇总或者转换成其他形式。

二、Stream API 的优势

  1. 支持函数式编程:Stream API 基于函数式接口,可以使用 Lambda 表达式来传递行为,使得代码更为灵活和可维护。
  2. 便于并行处理:Stream API 内置支持并行处理,并且可以利用多核架构来提高性能。通过 parallel() 方法可以轻松地将串行流转换为并行流。
  3. 延迟计算:Stream 中的操作可以进行延迟计算,只有在需要结果时才会执行。这种特性使得 Stream 在处理大数据集时能够有效地优化性能。
  4. 代码简洁:Stream API 提供了一套函数式编程风格的方法,使得代码更为简洁,可以通过链式操作完成复杂的数据处理任务。
  5. 内置丰富的操作:Stream API 提供了丰富的中间操作(如 filter、map、sorted 等)和终端操作(如 forEach、collect、reduce 等),可以满足各种数据处理需求。

三、什么是流

流(Stream)是一种数据通道,它用于处理数据源(如集合、数组等)所产生的元素序列。“集合关注的是数据本身,而流关注的是对数据的计算处理。”             

四、Stream 的三个操作

1.  创建流

  • Stream.of(T… values):通过显式值创建一个流。
  • Collection.stream():通过集合的stream()方法创建一个流。
  • Collection.parallelStream():通过集合的parallelStream()方法创建一个并行流。
  • Arrays.stream(T[] array):通过数组创建一个流。
  • Stream.iterate(T seed, UnaryOperator f):创建一个无限流,种子值是seed,后续元素通过函数f迭代生成。
  • Stream.generate(Supplier s):创建一个无限流,元素通过Supplier函数生成。
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Stream;
import java.util.function.UnaryOperator;
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        // Stream.of(T… values) 通过显式值创建一个流
        Stream<String> streamOfValues = Stream.of("a", "b", "c");
        streamOfValues.forEach(s -> System.out.print(s + " "));
        // a b c
        System.out.println();

        // Collection.stream() 通过集合的stream()方法创建一个流
        Collection<String> collection = Arrays.asList("x", "y", "z");
        Stream<String> streamFromCollection = collection.stream();
        streamFromCollection.forEach(s -> System.out.print(s + " "));
        // x y z
        System.out.println();

        // Collection.parallelStream() 通过集合的parallelStream()方法创建一个并行流
        Stream<String> parallelStreamFromCollection = collection.parallelStream();
        parallelStreamFromCollection.forEach(s -> System.out.print(s + " "));
        // y x z
        System.out.println();

        // Arrays.stream(T[] array) 通过数组创建一个流
        String[] array = {"1", "2", "3"};
        Stream<String> streamFromArray = Arrays.stream(array);
        streamFromArray.forEach(s -> System.out.print(s + " "));
        // 1 2 3
        System.out.println();

        // Stream.iterate(T seed, UnaryOperator f) 创建一个无限流,种子值是0,后续元素通过函数f迭代生成
        UnaryOperator<Integer> f = x -> x + 2;
        Stream<Integer> iterateStream = Stream.iterate(0, f);
        iterateStream.limit(5).forEach(s -> System.out.print(s + " ")); // 限制输出前5个元素
        // 0 2 4 6 8
        System.out.println();

        // Stream.generate(Supplier s) 创建一个无限流,元素通过Supplier函数生成
        Supplier<Double> randomSupplier = Math::random;
        Stream<Double> generateStream = Stream.generate(randomSupplier);
        generateStream.limit(3).forEach(s -> System.out.print(s + " ")); // 限制输出前3个元素
        // 0.5262200929887488 0.07660005625390776 0.5097922636483587 
        System.out.println();
    }
}

2.  中间操作

  • filter(Predicate predicate):过滤流中的元素,只保留满足条件的元素。

  • map(Function<T, R> mapper):转换每个元素到对应的结果。

  • mapToInt(ToIntFunction mapper):转换元素为int类型。

  • mapToLong(ToLongFunction mapper):转换元素为long类型。

  • mapToDouble(ToDoubleFunction mapper):转换元素为double类型。

  • flatMap(Function<T, Stream> mapper):将每个元素转换为另一个流,然后将这些流连接成一个流。

  • distinct():返回一个元素各不相同的新流。

  • sorted():返回一个自然排序后的流。

  • sorted(Comparator comparator):返回一个按照指定比较器排序后的流。

  • peek(Consumer action):对每个元素执行操作,并返回一个新的流。

  • limit(long maxSize):截断流,使其元素不超过指定数量。

  • skip(long n):跳过前n个元素,返回剩下的元素组成的流。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


public class Main {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");

        // filter:过滤流中的元素,只保留满足条件的元素
        List<String> filtered = strings.stream() //Collection.stream()集合方式创建流,得到的元素类型Stream<String>
                .filter(s -> !s.isEmpty())//筛选出不为空的字符串,不改变流的类型
                .collect(Collectors.toList()); //终止操作,把stream流中的每个元素收集到List集合中
        System.out.println("Filtered: " + filtered); //Filtered: [abc, bc, efg, abcd, jkl]

        // map:转换每个元素到对应的结果
        List<Integer> lengths = strings.stream()
                .map(s -> s.length())//对每个元素进行映射,s -> s.length()也可改写成String::length,得到元素类型Stream<Integer>
                .collect(Collectors.toList());
        System.out.println("Lengths: " + lengths); //Lengths: [3, 0, 2, 3, 4, 0, 3]

        // mapToInt:转换元素为int类型
        int[] intLengths = strings.stream()
                .mapToInt(String::length)//对生成的元素转换为int类型,得到IntStream类型的流
                .toArray();//终止操作,把stream流中的每个元素收集到数组中
        System.out.println("Int Lengths: " + Arrays.toString(intLengths));//Int Lengths: [3, 0, 2, 3, 4, 0, 3]

        // mapToLong:转换元素为long类型
        long[] longLengths = strings.stream()
                .mapToLong(String::length)//对生成的元素转换为long类型,得到LongStream类型的流
                .toArray();
        System.out.println("Long Lengths: " + Arrays.toString(longLengths));//Long Lengths: [3, 0, 2, 3, 4, 0, 3]

        // mapToDouble:转换元素为double类型
        double[] doubleLengths = strings.stream()
                .mapToDouble(String::length)//对生成的元素转换为long类型,得到DoubleStream类型的流
                .toArray();
        System.out.println("Double Lengths: " + Arrays.toString(doubleLengths));//Double Lengths: [3.0, 0.0, 2.0, 3.0, 4.0, 0.0, 3.0]

        // flatMap:将每个元素转换为另一个流,然后将这些流连接成一个流
        List<String> flatMapped = strings.stream()
                .flatMap(s -> Arrays.stream(s.split("")))//对流的每个元素拆分成新的流,s.split("")后是String[]类型
                .collect(Collectors.toList());
        System.out.println("FlatMapped: " + flatMapped);//FlatMapped: [a, b, c, , b, c, e, f, g, a, b, c, d, , j, k, l]

        // distinct:返回一个元素各不相同的新流
        List<String> distinctStrings = strings.stream()
                .distinct()//对流的元素进行去重
                .collect(Collectors.toList());
        System.out.println("Distinct: " + distinctStrings);//Distinct: [abc, , bc, efg, abcd, jkl]

        // sorted:返回一个自然排序后的流
        List<String> sortedStrings = strings.stream()
                .sorted()//对流的元素进行字典升序排序
                .collect(Collectors.toList());
        System.out.println("Sorted: " + sortedStrings);//Custom Sorted: [, , abc, abcd, bc, efg, jkl]

        // sorted(Comparator):返回一个按照指定比较器排序后的流
        List<String> customSorted = strings.stream()
                //.sorted(Comparator.reverseOrder())//对流的元素进行降序排序
                .sorted((a, b) -> b.compareTo(a))//对流的元素进行降序排序
                .collect(Collectors.toList());
        System.out.println("Custom Sorted: " + customSorted);//Custom Sorted: [jkl, efg, bc, abcd, abc, , ]

        // peek:对每个元素执行操作,并返回一个新的流
        List<String> peeked = strings.stream()
                .peek(s -> System.out.print(s + " ")) //对每个元素进行打印 abc  bc efg abcd  jkl
                .collect(Collectors.toList());
        System.out.println("\nPeeked: " + peeked);//[abc, , bc, efg, abcd, , jkl]

        // limit:截断流,使其元素不超过指定数量
        List<String> limited = strings.stream()
                .limit(3) //截取流的前面三个
                .collect(Collectors.toList());
        System.out.println("Limited: " + limited); //Limited: [abc, , bc]

        // skip:跳过前n个元素,返回剩下的元素组成的流
        List<String> skipped = strings.stream()
                .skip(3)//跳过前面三个元素
                .collect(Collectors.toList());
        System.out.println("Skipped: " + skipped); //Skipped: [efg, abcd, , jkl]
    }
}


3.  终止操作

  • forEach(Consumer action):遍历流中的每个元素,执行指定的操作。

  • forEachOrdered(Consumer action):保证forEach操作在流被并行处理时,按照原始流的顺序执行。

  • toArray():将流转换为数组。

  • reduce(T identity, BinaryOperator accumulator):通过一个起始值,反复利用BinaryOperator来处理和累积元素,返回一个值。

  • reduce(BinaryOperator accumulator):没有起始值,通过BinaryOperator处理和累积元素,返回一个Optional对象。

  • collect(Collector<T, A, R> collector):将流中的元素累积成一个结果,利用Collector进行操作。

  • min(Comparator comparator):返回流中最小元素。

  • max(Comparator comparator):返回流中最大元素。

  • count():返回流中元素的数量。

  • anyMatch(Predicate predicate):判断流中是否至少有一个元素满足条件。

  • allMatch(Predicate predicate):判断流中所有元素是否都满足条件。

  • noneMatch(Predicate predicate):判断流中是否没有元素满足条件。

  • findFirst():返回流中的第一个元素。

  • findAny():返回流中的任意一个元素,主要用于并行流。

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.Comparator;


public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // forEach:遍历流中的每个元素,执行指定的操作
        numbers.stream().forEach(s -> System.out.print(s + " "));//1 2 3 4 5 6 7 8 9
        System.out.println();

        // forEachOrdered:保证forEach操作在流被并行处理时,按照原始流的顺序执行
        numbers.parallelStream().forEachOrdered(s -> System.out.print(s + " "));//1 2 3 4 5 6 7 8 9
        System.out.println();

        // toArray:将流转换为数组
        Integer[] numbersArray = numbers.stream().toArray(Integer[]::new);
        //int[] array = numbers.stream().mapToInt(Integer::valueOf).toArray();
        System.out.println("Array: " + Arrays.toString(numbersArray));//Array: [1, 2, 3, 4, 5, 6, 7, 8, 9]

        // reduce(T identity, BinaryOperator accumulator):通过一个起始值,反复利用BinaryOperator来处理和累积元素,返回一个值
        int sum = numbers.stream().reduce(0, (a, b) -> a + b); //初始值sum = 0 ,(a, b) -> a + b可以改成Integer::sum
        System.out.println("Sum with identity: " + sum);//Sum with identity: 45

        // reduce(BinaryOperator accumulator):没有起始值,通过BinaryOperator处理和累积元素,返回一个Optional对象
        Optional<Integer> sumOptional = numbers.stream().reduce(Integer::sum); //Optional<Integer>类的实例可以包含一个的Integer值,也可以不包含任何值(即它是null的)。
        // System.out.println(sumOptional.orElse(null)); //该方式取值也可以,如果不存在则返回null,如果存在则取出Integer类型的值
        // Integer i = sumOptional.get(); //该方式取值也可以,要确保值存在;如果不存在会抛出异常
        sumOptional.ifPresent(s-> System.out.println(s));//45


        // collect(Collector<T, A, R> collector):将流中的元素累积成一个结果,利用Collector进行操作
        List<Integer> evenNumbers = numbers.stream()
                .filter(n -> n % 2 == 0)
                .collect(Collectors.toList());
        System.out.println("Even numbers: " + evenNumbers); //Even numbers: [2, 4, 6, 8]

        // min(Comparator comparator):返回流中最小元素
        Optional<Integer> min = numbers.stream().min(Comparator.naturalOrder());
        min.ifPresent(System.out::println); //1

        // max(Comparator comparator):返回流中最大元素
        Optional<Integer> max = numbers.stream().max(Comparator.naturalOrder());
        max.ifPresent(System.out::println); //9

        // count():返回流中元素的数量
        long count = numbers.stream().count();
        System.out.println("Count: " + count); //Count: 9

        // anyMatch(Predicate predicate):判断流中是否至少有一个元素满足条件
        boolean anyMatch = numbers.stream().anyMatch(n -> n > 5);
        System.out.println("Any match: " + anyMatch); //Any match: true

        // allMatch(Predicate predicate):判断流中所有元素是否都满足条件
        boolean allMatch = numbers.stream().allMatch(n -> n > 0);
        System.out.println("All match: " + allMatch); //All match: true

        // noneMatch(Predicate predicate):判断流中是否没有元素满足条件
        boolean noneMatch = numbers.stream().noneMatch(n -> n < 0);//没有元素小于0
        System.out.println("None match: " + noneMatch); //None match: true

        // findFirst():返回流中的第一个元素
        Optional<Integer> first = numbers.stream().findFirst();
        first.ifPresent(System.out::println);//1

        // findAny():返回流中的任意一个元素,主要用于并行流
        Optional<Integer> any = numbers.parallelStream().findAny();
        any.ifPresent(System.out::println);//1~9任意一个数字
    }
}

五、Stream API 的练习

1. 基础练习

(1)计算整数列表的总和

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("1", "2", "3");
        //方法一
        int IntAns = list.stream()
                .mapToInt(Integer::valueOf)            //IntStream类型
                .sum();
        
        //方法二
        Integer IntegerAns = list.stream()
                .map(Integer::parseInt)                //Stream<Integer>类型
                .reduce(0, Integer::sum);              //对Stream<Integer>和IntStream类型都可以进行规约
        System.out.println("总和为:" + IntAns);        //总和为:6
        System.out.println("总和为:" + IntegerAns);    //总和为:6
    }
}

(2)找出整数列表中的最大值

import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4);
        // 方法一
        OptionalInt max1 = list.stream()
                .mapToInt(Integer::valueOf)
                .max();
        max1.ifPresent(System.out::println); //4

        // 方法二
        int max2 = list.stream()
                .reduce(Integer.MIN_VALUE, (a, b) -> a >= b ? a : b);
        //  .reduce(Integer.MIN_VALUE, Integer::max); //初始值是第一个元素或最小值
        System.out.println(max2); //4

    }
}

(3)计算整数列表中所有偶数的平均值

import java.util.Arrays;
import java.util.List;
import java.util.OptionalDouble;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4);

        //OptionalDouble是一个可能包含double数值容器,数值也有可能不存在
        OptionalDouble average = list.stream()
                .filter(n -> n % 2 == 0)
                .mapToInt(Integer::valueOf)//转换成IntStream类型
                .average();

        //ifPresent():这是OptionalDouble类中的一个方法,用于检查这个Optional对象中是否包含值。如果Optional对象包含值,那么ifPresent()方法会执行传递给它的lambda表达式。
        average.ifPresent(value -> System.out.println(value)); //3.0

    }
}

(4)筛选出一个整数列表中的偶数并打印

import java.util.Arrays;
import java.util.List;
​
public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("1", "2", "5", "3", "6");
        list.stream()
                .mapToInt(Integer::valueOf)//转换成int类型,也可以parseInt
                .filter(x -> x % 2 == 0)
                .forEach(System.out::println); 
    }
}

(5)将字符串列表中的每个元素转换为大写并收集到新的列表

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        // 初始化列表
        List<String> list = Arrays.asList("aaa", "bbb", "cc", "D");

        // 将列表中的字符串转换为大写,并收集结果到新的列表中
        List<String> collect = list.stream()
                .map(String::toUpperCase) // 映射操作,将每个字符串转换为大写
                .collect(Collectors.toList()); // 收集操作,将结果收集到列表中

        // 打印转换后的列表
        System.out.println(collect); //[AAA, BBB, CC, D]
    }
}

​(6)对整数列表进行降序排序,并获取前3个元素

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 4, 3, 6, 3, 8, 5);
        List<Integer> collect = list.stream()
                .sorted((a, b) -> b - a)
                .limit(3)
                .collect(Collectors.toList());
        System.out.println(collect);//[8, 6, 5]

    }
}

(7)将整数列表中的每个数字乘以2,并收集到一个新的列表中

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4);
        List<Integer> collect = list.stream()
                .map(s -> s * 2)
                .collect(Collectors.toList());
        collect.forEach(s -> System.out.print(s + " ")); //2 4 6 8 
    }
}

(8)检查整数列表中是否所有数字都是正数

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 4, 3, 6, 3, 8, 5);
        boolean b = list.stream()
                .allMatch(Main::IsPositive); //对list里面的所有数进行判断
                //.allMatch(n -> n > 0); //也可以直接该写法

        System.out.println(b); //true
    }

    public static boolean IsPositive(int n) {
        return n > 0;
    }
}

(9)找出整数列表中大于5的最小值

import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 4, 3, 6, 3, 8, 5);
        OptionalInt min = list.stream()
                .mapToInt(Integer::valueOf)
                .filter(n -> n > 5)
                .findFirst();
        min.ifPresent(System.out::println); //6
    }
}

(10)检查整数列表中是否存在至少一个数字大于10

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 4, 3, 6, 3, 8, 5);
        boolean b = list.stream().anyMatch(n -> n > 5);//判断列表中是否有一个存在>5的数字
        System.out.println(b);

    }
}

(11)检查整数列表中是否包含连续的数字

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 5, 6, 7);
        boolean hasConsecutiveNumbers = list.stream()
                .anyMatch(n -> list.contains(n + 1));
        System.out.println("列表中是否包含连续的数字:" + hasConsecutiveNumbers);//列表中是否包含连续的数字:true
    }
}

(12)将整数列表中的数字进行去重

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(3, 1, 4, 1, 5, 9);
        List<Integer> collect = list.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println(collect);//[3, 1, 4, 5, 9]
    }
}

(13)从字符串列表中找出最长的字符串

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("hello", "world2222", "stream22", "api", "java");
        // 方法一
        Optional<String> longestString = strings.stream().max((s1, s2) -> s1.length() - s2.length());
        longestString.ifPresent(System.out::println); //world2222

        // 方法二
        Optional<String> reduce = strings.stream().reduce((a, b) -> a.length() > b.length() ? a : b);
        System.out.println(reduce.orElse(null));//world2222
    }
}

2. 进阶练习

(14)从员工(姓名、年龄)列表中找出年龄大于30岁的员工姓名列表

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }


}

public class Main {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
                new Employee("Alice", 32),
                new Employee("Bob", 29),
                new Employee("Charlie", 34)
        );

        String collect = employees.stream()
                .filter(e -> e.getAge() > 30)
                .map(e -> e.getName())//对每个员工取出姓名,或直接Employee::getName
                .collect(Collectors.joining(", ")); 
        System.out.println(collect); //Alice, Charlie
    }
}

(15)计算列表中每个元素出现的次数

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> integerNumbers = Arrays.asList(1, 2, 4, 3, 6, 3, 8, 5);
        Map<Integer, Long> collect = integerNumbers
                .stream()
                .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
        //groupingBy类似与SQL中的GROUP BY
        //<e, Collectors.counting())>中,e值key,而Collectors.counting()是对每个key聚合后的值
        System.out.println(collect); // {1=1, 2=1, 3=2, 4=1, 5=1, 6=1, 8=1}
    }
}

(16)对字符串列表按单词长度进行分组,并打印出每个长度组的单词列表

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");

        Map<Integer, List<String>> wordsByLength = words.stream()
                .collect(Collectors.groupingBy(String::length)); 
        //groupingBy只有一个参数时,key就是String::length,而value就是元素本身
        
        //wordsByLength: {3=[fig], 4=[date], 5=[apple, grape], 6=[banana, cherry]}
        wordsByLength.forEach((length, wordList) -> System.out.println("Length: " + length + ", Words: " + wordList));
        
   
    }
}

(17)将整数列表中的数字分为奇数和偶数,分别存储在不同的列表中

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 4, 3, 6, 3, 8, 5);
        Map<Boolean, List<Integer>> partitionedMap = list.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        //partitioningBy是二元分组,groupingBy是多元分组
        System.out.println("偶数列表:" + partitionedMap.get(true)); //偶数列表:[2, 4, 6, 8]
        System.out.println("奇数列表:" + partitionedMap.get(false)); //奇数列表:[1, 3, 3, 5]
    }
}

(18)将一个字符串列表中的每个字符串长度求和

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("apple", "banana", "cherry");
        // 方法一
        int totalLength1 = strings.stream()
                .collect(Collectors.summingInt(String::length));
        System.out.println(totalLength1); // 输出:17
        
        // 方法二
        int totalLength2 = strings.stream()
                .mapToInt(String::length).sum();
        System.out.println(totalLength2); // 输出:17

        // 方法三
        int totalLength3 = strings.stream()
                .reduce("",String::concat)
                .length();
        System.out.println(totalLength3); // 输出:17
    }
}

(19)对员工列表按年龄分组,并打印每个年龄组的人数

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Employee {
    String name;
    int age;

    Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Employee> people = Arrays.asList(
                new Employee("Alice", 22),
                new Employee("Bob", 20),
                new Employee("Charlie", 21),
                new Employee("David", 20)
        );

        //按照age进行分组,对每个分组求和
        Map<Integer, Long> peopleByAge = people.stream()
                .collect(Collectors.groupingBy(Employee::getAge, Collectors.counting()));
        peopleByAge.forEach((age, count) -> System.out.println("Age: " + age + ", Count: " + count));


        //按照age进行分组
        Map<Integer, List<Employee>> collect = people.stream()
                .collect(Collectors.groupingBy(person -> person.getAge()));
        System.out.println(collect);
        
    }
}

(20)计算字符串中每个字符出现的次数

import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        String str = "hello world";
        
        Map<Character, Long> charCountMap = str.chars() // IntStream
                .mapToObj(c -> (char) c) // Stream<Character>
                .collect(Collectors.groupingBy(c -> c, Collectors.counting()));

        System.out.println(charCountMap); //{ =1, r=1, d=1, e=1, w=1, h=1, l=3, o=2}
    }
}

(21)给定两个字符串列表,合并这两个列表,并去除重复项,然后按字母顺序排序

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("a", "b", "c");
        List<String> list2 = Arrays.asList("b", "c", "d");

        List<String> mergedList = Stream.concat(list1.stream(), list2.stream())
                .distinct()
                .sorted()
                .collect(Collectors.toList());
        System.out.println(mergedList);//[a, b, c, d]
    }
}

(22)将字符串列表转换为Map,其中键是字符串,值是字符串长度

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("apple", "banana", "cherry");

        Map<String, Integer> stringLengthMap = strings.stream()
                .collect(Collectors.toMap(s -> s, String::length));

        stringLengthMap.forEach((s, length) -> System.out.println(s + ": " + length));
//        banana: 6
//        apple: 5
//        cherry: 6
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值