Java 8 添加了一个新的抽象称为流 Stream API,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API 可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
集合创建:
stream() − 为集合创建串行流。在串行流中,每个元素都是由同一个线程处理的,因此操作是顺序执行的。
parallelStream() − 为集合创建并行流。在并行流中,流会将集合分成多个子集,然后多线程并行处理这些子集中的元素。
/** * 集合创建流 */ List<String> list = new ArrayList<>(); //串行流 Stream<String> stream = list.stream(); //并行流 Stream<String> stream = list.parallelStream();
数组创建:
通过数组创建的方式有:Stream.of()
、Stream.generate()
、Stream.iterate()
、IntStream
、LongStream
等,如下代码。
/** * 数组创建流 */ String[] strs = new String[3]; Stream<String> stream1 = Arrays.stream(strs); /** *Stream.of() 创建流 */ Stream<String> stream2 = Stream.of("Apple", "Orange", "Banana"); /** *Stream.generate()创建流 */ Stream<Double> randomStream = Stream.generate(Math::random).limit(5); /** *Stream.iterate()创建流 */ Stream<Integer> integerStream = Stream.iterate(0, n -> n + 2).limit(5); /** *IntStream创建流 */ IntStream intStream = IntStream.range(1, 5); // [1,2,3,4] /** * LongStream创建流 */ LongStream longStream = LongStream.rangeClosed(1, 5); // [1,2,3,4,5]
通常,我们遍历一个集合时会使用 for(int i = 0; i < list.size(); i++)
这种方式,但是当我们有 IntStream
可用时,可以优化为使用 IntStream.rangeClosed(0, list.size() - 1).forEach(i -> {...})
来遍历集合。
过滤操作(filter )
过滤操作,可以保留满足过滤条件的元素。如下代码为:将 lists 流中的等于 1 的元素过滤出来,并打印结果。
/** * filter 过滤操作 * @param lists */ public static void filterTest(List<Integer> lists){ List<Integer> integers = lists.stream() .filter(list ->Objects.equals(1, list)).toList(); integers.forEach(System.out::println); }
映射操作(map / flatMap)
映射操作,可以对流中的每个元素提取并转换。如下代码为:
(1)map 映射操作:将 lists 流中的字符串,处理成大写的字符串;
(2)flatMap 映射操作:将 lists 流中的二位数组,转成一维数组。(flatMap 用于将流中的一个元素转换为一个流,然后将所有转换后的流组装成一个流)
/** * map映射操作 */ public static void mapTest(List<String> lists){ lists.stream().map(String::toLowerCase).toList(); lists.forEach(System.out::println); } /** * flatMap映射操作,将嵌套集合转换为扁平集合 */ public static void flatMapTest(List<List<String>> lists){ lists = Arrays.asList( Arrays.asList("Java", "Kotlin"), Arrays.asList("Python", "Ruby"), Arrays.asList("JavaScript", "TypeScript")); List<String> wordList = lists.stream().flatMap(List::stream).toList(); wordList.forEach(System.out::println); }
mapToInt / mapToLong / mapToDouble 操作
mapToInt / mapToLong / mapToDouble 操作,可以将流中的元素映射为对应 int / Long / Double 类型,并进一步做数值计算。
public class Student{ //年龄 private int age; //姓名 private String Name; } public static void mapTest(){ int totalAge1 = students.stream().mapToInt(Student::getAge).sum(); Long totalAge2 = students.stream().mapToLong(Student::getAge).sum(); Double totalAge3 = students.stream().mapToDouble(Student::getAge).sum(); }
排序操作(sorted)
排序流中的元素。
/** * 排序操作 sorted,对于集合对象排序,必须实现 Comparable接口,并重写 compareTo 方法,如果没有实现则需要给 sorted 函数传递参数 */ public static void sortedTest(){ List<String> cities = Arrays.asList("New York", "Tokyo", "London", "Paris"); // 对城市按字母顺序排序 List<String> sortedStream = cities.stream().sorted(Comparator.comparingInt(city -> city.charAt(1))).toList(); sortedStream.forEach(System.out::println); }
去重操作(distinct)
去除流中的重复元素。
/** * 去重操作(distinct) */ public static void distinctTest(){ List<String> cities = Arrays.asList("New York", "Tokyo", "London", "Paris"); // 对城市去重 List<String> distinctStream = cities.stream().distinct(); sortedStream.forEach(System.out::println); }
截断操作 / 跳过操作 / 观察操作(limit / skip / peek)
/** * 截断操作(limit),只取流中前3个元素 */ List<Integer> numbers = Lists.newArrayList(1, 2, 3, 4, 5, 6); List<Integer> limitedList = numbers.stream().limit(3).collect(Collectors.toList()); /** * 跳过操作(skip),跳过流中前3个元素 */ List<Integer> numbers = Lists.newArrayList(1, 2, 3, 4, 5, 6); List<Integer> limitedList = numbers.stream().skip(3).collect(Collectors.toList()); /** * 观察操作,用于调试和观察流中的元素 */ List<String> words = Arrays.asList("apple", "banana", "orange"); List<String> modifiedWords = words.stream() .filter(word -> word.length() > 5) .peek(word -> System.out.println("Filtered Word: " + word)) .map(String::toUpperCase) .peek(word -> System.out.println("Uppercase Word: " + word)) .collect(Collectors.toList());
迭代操作(forEach)
迭代操作,可以用于遍历流中的每一个元素。
List<String> fruits = Arrays.asList("apple", "banana", "orange"); fruits.stream().forEach(fruit -> System.out.println(fruit)); //fruits.forEach(fruit -> System.out.println(fruit)); //fruits.stream().forEach(System.out::println);
收集操作(collect)
收集操作,可以将流转换为 List、Set、Map 等集合。通过 collect 函数,对流中的元素进行收集。
// 将学生流转换为 ListList<Student> limitStu = students.stream().collect(Collectors.toList()); // 将学生流转换为 SetList<Student> limitStu = students.stream().collect(Collectors.toSet()); // 将学生流转换为 Map,将年龄作为 key,将学生信息作为 value (Function.identity() 为提取元素自身的函数,(e1, e2)-> e1 代表当两个学生年龄相同时,取第一个学生) Map<Integer, Student> studentMap = students.stream().collect(Collectors.toMap( Student::getAge, Function.identity(), (e1,e2) -> e1)); //将学生的名字通过逗号拼接成一个字符串: studentNameString studentName = students.stream().map(Student::getName).collect(Collectors.joining(",")); //通过字符串的长度对 fruits 流分组 List<String> fruits = Arrays.asList("apple", "banana", "orange"); Map<Integer, List<String>> lengthToNamesMap = fruits.stream() .collect(Collectors.groupingBy(String::length)); // counting(计算流元素个数)、maxBy(找到流中最大的元素)、minBy(找到流中最小的元素)、averagingInt(计算流中元素的平均值)、summarizingInt(计算流中元素的汇总统计信息,包括总数、平均值、最大值和最小值。)
partitioningBy(分组操作)
// 通过学生的年龄是否等于1进行分组,等于则分为 true 组,不等于则分为 false 组 Map<Boolean,List<Student>> partStudent = students.stream().collect(Collectors.partitioningBy(student -> Objects.equals(1,student.getAge())));
findFirst 操作
找到流中第一个元素。如下代码:找打学生流中第一个年龄等于1的元素。
Student firstStu = students.stream() .filter(student -> Objects.equals(1, student.getAge())) .findFirst().orElse(null);
findAny 操作
找到流中任何一个元素。如下代码:找打学生流中任何一个年龄等于1的元素。(相当于 findFirst 操作)
Student student = students.stream() .filter(student -> Objects.equals(1, student.getAge())) .findAny().orElse(null);
anyMatch 操作
检测是否存在一个或多个满足指定的参数行为,如果满足则返回true。
boolean result = students.stream() .anyMatch(student -> Objects.equals(1, student.getAge()));
noneMatch 操作
检测是否不存在满足指定行为的元素,如果不存在则返回true。
boolean result = students.stream() .noneMatch(student -> Objects.equals(1, student.getAge()));
allMatch 操作
检测是否全部都满足指定的参数行为,如果全部满足则返回true。
boolean result = students.stream() .allMatch(student -> Objects.equals(1, student.getAge()));
以上就是 Java 流式开发的介绍了,基本覆盖了日常工作中需要用到的 Java 流式操作。