Stream API是 Java 8 引入的一种新特性,用于简化集合操作,支持函数式编程,便于并行处理,具有延迟计算的特点。
Stream API的优势在于代码简洁、内置丰富的操作,能够提高数据处理效率。
流的操作分为三个步骤:它包括创建流、中间操作(如过滤、映射、排序等)和终止操作(如遍历、汇总、转换等),实现对集合的高效处理。
目录
(14)从员工(姓名、年龄)列表中找出年龄大于30岁的员工姓名列表
(16)对字符串列表按单词长度进行分组,并打印出每个长度组的单词列表
(17)将整数列表中的数字分为奇数和偶数,分别存储在不同的列表中
(21)给定两个字符串列表,合并这两个列表,并去除重复项,然后按字母顺序排序
(22)将字符串列表转换为Map,其中键是字符串,值是字符串长度
进阶知识:Collectors
一、什么是 Stream API
Stream API 是 Java 8 引入的一个新特性,它提供了一种处理集合的新方式,可以更简洁、更易读地操作数据。Stream API 可以用来处理集合中的元素,类似于使用 SQL 进行查询,可以进行过滤、映射、排序、聚合等操作。
以下是Stream API的一些关键概念:
- 源:Stream可以是从集合、数组、文件等生成的。
- 中间操作:诸如filter、map、sorted等操作会返回一个新Stream,这些操作不会修改原始数据源,它们返回的是一个新的Stream作为结果。
- 终端操作:诸如forEach、collect、reduce等操作,这些操作会返回一个结果或者一个副作用,比如对集合进行遍历、汇总或者转换成其他形式。
二、Stream API 的优势
- 支持函数式编程:Stream API 基于函数式接口,可以使用 Lambda 表达式来传递行为,使得代码更为灵活和可维护。
- 便于并行处理:Stream API 内置支持并行处理,并且可以利用多核架构来提高性能。通过 parallel() 方法可以轻松地将串行流转换为并行流。
- 延迟计算:Stream 中的操作可以进行延迟计算,只有在需要结果时才会执行。这种特性使得 Stream 在处理大数据集时能够有效地优化性能。
- 代码简洁:Stream API 提供了一套函数式编程风格的方法,使得代码更为简洁,可以通过链式操作完成复杂的数据处理任务。
- 内置丰富的操作: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
}
}