1.Lambda表达式的简化
1.1-指向静态方法的方法引用
/** * 指向静态方法的方法引用 * (args) -> ClassName.staticMethod(args) * ClassName::staticMethod; */ @Test public void test1(){ Consumer<String> consumer=new Consumer<String>() { @Override public void accept(String s) { Integer.parseInt(s); } }; Consumer<String> consumer1= s -> Integer.parseInt(s); Consumer<String> consumer2= Integer::parseInt; }
1.2-指向任意类型实例方法的方法引用
/** * 指向任意类型实例方法的方法引用 * (args) -> args.instanceMethod() * ClassName::instanceMethod; * */ @Test public void test2(){ Consumer<String> consumer1= s -> s.length(); Consumer<String> consumer2=String::length; }
1.3-指向现有对象的实例方法的方法引用
/** * 指向现有对象的实例方法的方法引用 * (args) -> object.instanceMethod(args) * object::instanceMethod */ @Test public void test3(){ StringBuilder stringBuilder=new StringBuilder(); Consumer<String> consumer1= s -> stringBuilder.append(s); Consumer<String> consumer2= stringBuilder::append; }
2.Stream流概念
package java.util.stream; Java 8 API添加了一个新的抽象称为流Stream , 可以让你以一种声明的方式处理数据 Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达 的高阶抽象 Stream API可以极大提高Java程序员的生产力 , 让程序员写出高效率、干净、简洁的代码 这种风格将要处理的元素集合看作一种流 , 流在管道中传输 , 并且可以在管道的节点上进行处理 , 比如筛选 , 排序 , 聚合等 元素流在管道中经过中间操作(intermediate operation)的处理 , 最后由最终操作(terminal operation)得到前面处理的结果
3.IDEA匿名内部类与Stream转换
使用场景: 如果匿名内部类是一个接口,并且当中只有一个抽象方法需要重写,可以使用Lambda表达式。 匿名内部类转成lambda: 将鼠标放到内部类对象上然后按下Alt+enter,会提示Replace with lambda lambda转成匿名内部类: 将鼠标放到lambda表达式上然后按下Alt+enter,然后选择提示Split into declaration and assignment
4.Stream流与集合的区别
// 对集合遍历都是通过Iterator或者For-Each的方式 , 显式的在集合外部进行迭代 , 这叫做外部迭代 // Stream提供了内部迭代的方式 , 通过访问者模式(Visitor)实现 ( 只能遍历一次 ) 集合相当于空间维度的存储 , Stream流相当于时间维度的存储 集合面向的是存储 , Stream流面向的是计算
5.流的组成与分类
// 1. 数据源 // 2. 中间操作: 主要是做业务处理( 过滤 , 排序 ) 无状态: 无状态操作执行完一个元素就走到下面的状态 , 不需要操作完所有的数据 有状态: 有状态的中间操作要等到上一个状态所有的数据都操作完 , 再统一的进行操作 // 3. 终端操作: 对流数据的一个收集 , 形成一个新的数据结构 短路: 只要找到符合条件的第一个数据 , 那么后面的元素就都不会去执行了 非短路: 数据集有多少个数据 , 就要执行多少次操作
6.创建Stream流
6.1-由数值直接构建流
/** * 1 由数值直接构建流 */ @Test public void streamFormValue(){ Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50); stream.forEach(integer -> System.out.println(integer)); }
6.2-通过文件生成流
/** * 2 通过文件生成流 */ @Test public void streamFormFile() throws IOException { // TODO 此处替换为本地文件的地址全路径 String filePath = ""; // import java.nio.file.Files; // import java.nio.file.Paths; Stream<String> lines = Files.lines(Paths.get(filePath)); lines.forEach(s -> System.out.println(s)); }
6.3-通过数组构建流
/** * 3 通过数组构建流 */ @Test public void streamForArray(){ int[] arrs={1,2,3,4,5}; IntStream stream = Arrays.stream(arrs); stream.forEach(i-> System.out.println(i)); }
6.4-通过集合构建流
/** * 4 通过集合构建流 * Collection 单列集合体系下的 都有 stream() * ! ! ! Map 双列集合体系不能直接构建流 可以转成单列集合 再调用 stream() */ @Test public void streamForCollection(){ Collection<Integer> collection=new ArrayList<>(); Collections.addAll(collection,1,2,3,4,5); Stream<Integer> stream = collection.stream(); stream.forEach(i-> System.out.println(i)); }
6.5-通过函数生成流 (无限流)
/** * 5 通过函数生成流 (无限流) */ @Test public void streamForFunction(){ // 第一种 /*Stream<Integer> stream = Stream.iterate(0, new UnaryOperator<Integer> () { @Override public Integer apply(Integer integer) { return integer + 2; } }); stream.forEach(i-> System.out.println(i));*/ //第二种 Stream<Integer> stream = Stream.generate(new Supplier<Integer>() { @Override public Integer get() { return new Random().nextInt(100) + 1; } }); stream.limit(100).forEach(i-> System.out.println(i)); }
7.中间常用方法
无状态
7.1-filter (过滤)
List<String> strings = Arrays.asList("foo", "bar", "baz", "qux"); // 使用 filter 方法过滤符合条件的元素 List<String> filtered = strings.stream() .filter(s -> s.startsWith("b")) .collect(Collectors.toList()); // 输出过滤后的结果 System.out.println(filtered); // 输出 [bar, baz] # List自带的removeIf同样可以实现filter的功能 List<String> strings = new ArrayList<>(Arrays.asList("foo", "bar", "baz", "qux")); // 使用 removeIf 方法删除以字母 b 开头的元素 strings.removeIf(s -> s.startsWith("b")); // 输出删除后的结果 System.out.println(strings); // 输出 [foo, qux] # removeIf与filter区别 removeIf 和 filter 都是流或集合中常用的元素过滤方法,它们之间的区别在于: removeIf 方法是用于删除集合中符合条件的元素,而 filter 方法只是将符合条件的元素留下来,并生成一个新的流。 removeIf 方法会实际地修改原始集合,而 filter 方法则不会。filter 方法只是生成一个新的流,而不修改原始流或集合。 removeIf 方法适用于对集合进行修改或删除操作,而 filter 方法适用于仅选择符合条件的元素的场景。 因此,如果您需要删除集合中符合条件的元素,则应使用 removeIf 方法。如果您只需要选择符合条件的元素并创建一个新的流或集合,则应使用 filter 方法
7.2-map (映射)
List<String> strings = Arrays.asList("foo", "bar", "baz", "qux"); // 使用 map 方法将字符串转换为大写字母 List<String> capitalized = strings.stream() .map(String::toUpperCase) .collect(Collectors.toList()); // 输出映射后的结果 System.out.println(capitalized); // 输出 [FOO, BAR, BAZ, QUX]
7.3-flatMap (扁平化)
// 嵌套集合或多维数组的场景 List<List<Integer>> numbers = Arrays.asList( Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6) ); // 使用 flatMap 方法将多个列表扁平化为一维列表 List<Integer> flattened = numbers.stream() .flatMap(List::stream) .collect(Collectors.toList()); // 输出扁平化后的结果 System.out.println(flattened); // 输出 [1, 2, 3, 4, 5, 6]
7.4-peek (遍历)
// 调试或日志场景 int sum = Arrays.stream(new int[] {1, 2, 3, 4, 5}) .peek(System.out::println) .sum(); System.out.println("Sum: " + sum);
有状态
7.5-distinct (去重)
List<String> strings = Arrays.asList("foo", "bar", "baz", "bar", "qux", "foo"); // 使用 distinct 方法去除重复元素 List<String> uniqueStrings = strings.stream() .distinct() .collect(Collectors.toList()); // 输出去重后的结果 System.out.println(uniqueStrings); // 输出 [foo, bar, baz, qux]
7.6-skip (跳过)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 skip 方法跳过前三个元素 List<Integer> skippedNumbers = numbers.stream() .skip(3) .collect(Collectors.toList()); // 输出跳过后的结果 System.out.println(skippedNumbers); // 输出 [4, 5]
7.7-limit (截断)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 limit 方法只保留前三个元素 List<Integer> limitedNumbers = numbers.stream() .limit(3) .collect(Collectors.toList()); // 输出截断后的结果 System.out.println(limitedNumbers); // 输出 [1, 2, 3]
7.8-sorted (排序)
List<Student> students = Arrays.asList( new Student("Alice", 70), new Student("Bob", 90), new Student("Charlie", 80) ); // 使用 sorted 方法根据成绩字段进行排序 List<Student> sortedStudents = students.stream() .sorted(Comparator.comparing(Student::getScore)) .collect(Collectors.toList()); // 输出排序后的结果 System.out.println(sortedStudents); // 输出 [Student{name='Alice', score=70}, Student{name='Charlie', score=80}, Student{name='Bob', score=90}]
8.终端操作常用方法
短路操作
8.1-allMatch (所有匹配)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0); System.out.println(allEven); // false
8.2-anyMatch (任意匹配)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0); System.out.println(hasEven); // true
8.3-noneMatch(不匹配)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); boolean noneNegative = numbers.stream().noneMatch(n -> n < 0); System.out.println(noneNegative); // true
8.4-findFirst (查找首个)
List<String> words = Arrays.asList("apple", "banana", "cherry", "date"); Optional<String> firstWord = words.stream().findFirst(); if (firstWord.isPresent()) { System.out.println(firstWord.get()); // "apple" }
8.5-findAny (查找任意)
List<String> words = Arrays.asList("apple", "banana", "cherry", "date"); Optional<String> anyWord = words.stream().findAny(); if (anyWord.isPresent()) { System.out.println(anyWord.get()); // 可能会输出 "apple" 或其他字符串 }
非短路操作
8.6-forEach (遍历)
List<String> words = Arrays.asList("apple", "banana", "cherry", "date"); words.stream().forEach(word -> System.out.println(word.toUpperCase()));
8.7-max (最大值)
List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1")); BigDecimal maxDecimal = decimalList.stream() .max(BigDecimal::compareTo) .orElse(BigDecimal.ZERO); System.out.println("Maximum decimal: " + maxDecimal);
8.8-min (最小值)
List<BigDecimal> list = Arrays.asList(BigDecimal.valueOf(10), BigDecimal.valueOf(20), BigDecimal.valueOf(5)); BigDecimal min = list.stream() .min(BigDecimal::compareTo) .orElse(BigDecimal.ZERO);
8.9-count (计数)
List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1")); long count = decimalList.stream().count(); System.out.println("Number of decimals: " + count);
8.10-sum (求和)
List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1")); BigDecimal sum = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add); System.out.println("Sum of decimals: " + sum);
8.11-avg (平均值)
List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1")); OptionalDouble average = decimalList.stream() .mapToDouble(BigDecimal::doubleValue) .average(); if (average.isPresent()) { System.out.println("Average of decimals: " + BigDecimal.valueOf(average.getAsDouble())); } else { System.out.println("BigDecimal list is empty"); }
9.Collectors 收集器
9.1-集合收集器
收集器的作用就是将流中的元素累积成一个结果,作用于终端操作。 Collectors 是一个工具类 , 它帮我们提前封装好了一些实现了Collector接口的收集器 , 我们可以直接 拿过来用:
toList()方法:将流中的元素收集到一个
List中。
Map<Integer, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));
toSet()
方法:将流中的元素收集到一个 Set
中。
Set<String> set = stream.collect(Collectors.toSet());
toMap()
方法:将流中的元素收集到一个 Map
中。可以指定键和值的映射关系。
Collectors.toMap()
方法接受三个参数,用于指定生成 Map
对象的键和值。这三个参数分别是:
-
键选择器(key mapper):用于指定如何从元素中提取 Map 的键(即 key)。可以使用 Lambda 表达式、方法引用或者 Function 接口实现来指定。
-
值选择器(value mapper):用于指定如何从元素中提取 Map 的值(即 value)。同样可以使用 Lambda 表达式、方法引用或者 Function 接口实现来指定。
-
合并函数(merge function):用于处理重复键的情况。当遇到重复键时,应该将两个值合并成一个。可以使用 Lambda 表达式、方法引用或者 BinaryOperator 接口实现来指定。如果省略,则会抛出 IllegalStateException 异常。
List<Person> persons = Arrays.asList( new Person("Alice", 25), new Person("Bob", 30), new Person("Charlie", 20), new Person("Alice", 35) ); Map<String, Integer> ageByName = persons.stream() .collect(Collectors.toMap(Person::getName, Person::getAge, Math::max)); System.out.println(ageByName);
9.2-分组
/** * 分组 根据Sku的类别分组 */ @Test public void toGroup(){ Map<Object, List<Sku>> resultMap = list.stream().collect(Collectors.groupingBy(sku-> sku.getSkuCategory())); System.out.println(JSON.toJSONString(resultMap,true)); }
9.3-分区
/** * 分区 根据sku的总价分区 * 大于100的为true 单独为一区 * 小于100的为false 单独为一区 */ @Test public void toPartition(){ Map<Boolean, List<Sku>> collect = list.stream() .collect(Collectors.partitioningBy(sku -> sku.getTotalPrice() > 100)); System.out.println(JSON.toJSONString(collect,true)); }