type
Post
status
Published
date
Sep 13, 2023
slug
summary
tags
category
学习思考
icon
password
1 什么是Lambda(λ)2 不同语言中的Lambda3 Java中的Lambda表达式4 原生函数式接口4.1 @FunctionalInterface注解4.2 Consumer: 消费性接口4.3 Supplier: 供给型接口4.4 Function: 函数型接口4.5 Predicate: 断言型接口5 Stream表达式5.1 中间型操作5.2 终结型操作5.3 Stream的创建5.4 Stream的使用5.4.1 遍历/匹配(foreach/find/match)5.4.2 筛选(filter)5.4.3 聚合(max/min/count)5.4.4 映射(map/flatMap)5.4.5 归约(reduce)5.4.6 收集(collect)5.4.6.1 归集(toList/toSet/toMap)5.4.6.2 统计(count/averaging)5.4.6.3 分组(partitioningBy/groupingBy)5.4.6.4 接合(joining)5.4.6.5 归约(reducing)5.4.7 排序(sorted)5.4.8 提取/组合6 引用
1 什么是Lambda(λ)
Lambda 并不是一个什么的缩写,它是希腊第十一个字母 λ 的读音,同时它也是微积分函数中的一个概念,所表达的意思是一个函数入参和出参定义,在编程语言中其实是借用了数学中的 λ,并且多了一点含义,在编程语言中功能代表它具体功能的叫法是匿名函数(Anonymous Function)。
百度百科:
匿名函数(英语:Anonymous Function)在计算机编程中是指一类无需定义标识符(函数名)的函数或子程序。
Lambda 的历史,它在 JDK8 发布之后才正式出现,但是在编程语言界,它是一个具有悠久历史的东西,最早在 1958 年在Lisp 语言中首先采用,而且虽然Java脱胎于C++,但是C++在2011年已经发布了Lambda 了,但是 JDK8 的 LTS 在2014年才发布,现代编程语言则是全部一出生就自带 Lambda 支持。
Lambda 在编程语言中往往是一个匿名函数,也就是说Lambda 是一个抽象概念,而编程语言提供了配套支持,比如在 Java 中其实为Lambda 进行配套的就是函数式接口,通过函数式接口生成匿名类和方法进行Lambda 式的处理。
Lambda 所提供的好处在Java中就是函数式接口所提供的能力了,函数式接口往往则是提供了一些通用能力,这些函数式接口在JDK中也有一套完整的实践,那就是 Stream。
2 不同语言中的Lambda
Python
# 语法 lambda [arg1[,arg2,arg3....argN]]:expression
lam1 = lambda x,y:x+y print(lam1(1, 2)) # 3 # 带默认值 lam2 = lambda x,y=10:x+y print(lam2(1)) # 11 # 带多参数 lam3 = lambda *args:[i**2 for i in args] print(lam3(1, 2, 3)) # [1,4,9]
C++
[ capture clause ] (parameters) -> return-type { definition of method }

[1]:Lambda表达式的引入标志,在‘[]’里面可以填入‘=’或‘&’表示该lambda表达式“捕获”(lambda表达式在一定的scope可以访问的数据)的数据时以什么方式捕获的,‘&’表示一引用的方式;‘=’表明以值传递的方式捕获,除非专门指出。
[2]:Lambda表达式的参数列表
[3]:Mutable 标识
[4]:异常标识
[5]:返回值
[6]:“函数”体,也就是lambda表达式需要进行的实际操作。
int a = 10, b = 20; // 值捕获 auto f1 = [a, b] {return a + b;}; f1(); // 30 auto f2 = [=] {return a + b;}; f2(); // 30 // 引用捕获 auto f3 = [&a] {a++;}; f3() // a=11 auto f3 = [&] {a++; b++;); f4(); // a=12 b=21 void func(std::vector<int>& v) { std::for_each(v.begin(), v.end(), [](int i) { cout << i << endl; }); }
JavaScript
(p1 [,p2,p3,....pn]) => { code block }
let func = (x => x * x); func(2) // 4
3 Java中的Lambda表达式
Lambda 表达式在 Java 8 中添加的。
lambda 表达式是一小段代码,它接受参数并返回一个值。Lambda 表达式类似于方法,但它们不需要名称,并且可以直接在方法体中实现。
句法
最简单的 lambda 表达式包含一个参数和一个表达式:
0参数
() -> System.out.println("0参数");
1个参数
p -> System.out.println("1个参数:" + p);
多个参数
(p1 [,p2,p3,....pn]) -> System.out.println("多个参数:" + p1 + ", " + p2 + ... + pn);
上面的表达式有一定的限制。它们要么返回一个值要么执行一段方法,并且它们不能包含变量、赋值或语句,例如if or for 。为了进行更复杂的操作,可以使用带有花括号的代码块。如果 lambda 表达式需要返回一个值,那么代码块应该有一个return语句。
(parameter1, parameter2) -> { code block [return] }
句法
• 类 :: 静态方法
//Consumer<String> c = [ (s) -> System.out.println(s); <=> System.out::println; ] Consumer<Integer> c = System.out::println; Stream.of(1, 2, 3).forEach(c); // 1 // 2 // 3
• 对象 :: 实例方法
// List<String> list = Lists.newArrayList(); // Consumer<String> c = [ (e) => list.add(e); <=> list::add; ] List<Integer> list = new ArrayList<>(); Consumer<Integer> c = list::add; list.forEach(System.out::println); // 1 // 2 // 3
• 构造器 :: new
Supplier<List<String>> s = [ () -> new ArrayList<>(); <=> ArrayList::new; ]
4 原生函数式接口
4.1 @FunctionalInterface注解
有且只有一个抽象方法的接口被称为函数式接口,函数式接口适用于函数式编程的场景,Lambda就是Java中函数式编程的体现,可以使用Lambda表达式创建一个函数式接口的对象,一定要确保接口中有且只有一个抽象方法,这样Lambda才能顺利的进行推导。
与@Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解:
@FunctionalInterface 。该注解可用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法(equal和hashcode方法不算),否则将会报错。但是这个注解不是必须的,只要符合函数式接口的定义,那么这个接口就是函数式接口。4.2 Consumer: 消费性接口
Consumer通过名字可以看出它是一个消费函数式接口,主要针对的是消费(1..n 入参, 无返回)这个场景,它的代码定义如下:
@FunctionalInterface public interface Consumer<T> { void accept(T t); }
通过泛型 T 定义了一个入参,但是没有返回值,它代表你可以针对这个入参做一些自定义逻辑,比较典型的例子是 forEach 方法。
Demo
List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6"); list.foreach(System.out::println); // 1 // 2 // ...
4.3 Supplier: 供给型接口
Supplier通过名字比较难看出来它是一个场景的函数式接口,它主要针对的是说获取(无入参,有返回)这个场景,它的代码定义如下:
@FunctionalInterface public interface Supplier<T> { T get(); }
通过泛型 T 定义了一个返回值类型,但是没有入参,它代表你可以针对调用方获取某个值,比较典型的例子是 Stream 中的 collect 方法,通过自定义传入我们想要取得的某种对象进行对象收集。
Demo
List<Integer> list = Lists.newArrayList("1", "2", "3", "4", "5", "6"); List<Integer> newList = list.stream().filter(x -> x >= 2).collect(Collectors.toList()); // filter x大于2 // Collectors.toList() return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID);
4.4 Function: 函数型接口
Function 接口的名字不太能轻易看出来它的场景,它主要针对的则是 转换(有入参,有返回,其中T是入参,R是返回)这个场景,其实说转换可能也不太正确,它是一个覆盖范围比较广的场景,你也可以理解为扩展版的Consumer,接口定义如下:
@FunctionalInterface public interface Function<T, R> { R apply(T t); }
通过一个入参 T 进行自定义逻辑处理,最终得到一个出参 R,比较典型的例子是 Stream 中的 map 系列方法和 reduce 系列方法。
Demo
List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6"); List<Integet> newList = list.stream().map(Integer::parseInt).collect(Collectors.toList()); // String => Integer
4.5 Predicate: 断言型接口
Predicate主要针对的是判断(有入参,有返回,凡是返回的类型固定为Boolean。可以说Function 是包含Predicate的 )这个场景,它的代码定义如下:
@FunctionalInterface public interface Predicate<T> { boolean test(T t); }
通过泛型 T 定义了一个入参,返回了一个布尔值,它代表你可以传入一段判断逻辑的函数,比较典型的例子是 Stream 中的 filter方法。
List<Integer> list = Lists.newArrayList("1", "2", "3", "4", "5", "6"); List<Integer> newList = list.stream().filter(x -> x >= 2).collect(Collectors.toList()); // Predicate: x -> x >= 2
5 Stream表达式
Stream,就是JDK8又依托于函数式编程特性为集合类库做的一个类库,它其实就是jdk提供的函数式接口的最佳实践。它能让我们通过lambda表达式更简明扼要的以流水线的方式去处理集合内的数据,可以很轻松的完成诸如:过滤、分组、收集、归约这类操作。
其中Stream的操作大致分为两类
- 中间型操作
- 终结型操作
其中转换型操作又分为有状态和无状态两类。有状态是本次的结果需要依赖于前面的处理结果,而无状态则是不依赖。简单来讲就是无状态方法可以互相调换位置,而有状态方法不能调换位置。
注意:
- stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
- stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
- stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
5.1 中间型操作
中间型操作就是返回值依旧是stream类型的方法。api如下:

5.2 终结型操作
终结型操作与中间型相反,返回值是非Stream类型的。api如下:

5.3 Stream的创建
通过
java.util.Collection.stream() 方法用集合创建流List<String> list = Arrays.asList("a", "b", "c"); // 创建一个顺序流 Stream<String> stream = list.stream(); // 创建一个并行流 Stream<String> parallelStream = list.parallelStream();
使用
java.util.Arrays.stream(T[] array)方法用数组创建流int[] array={1,2,3}; IntStream stream = Arrays.stream(array);
使用
Stream的静态方法:of()、iterate()、generate()Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6); stream1.forEach(System.out::println); // 1 // 2 // ... Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4); stream2.forEach(System.out::println); // 0 // 3 // ... Stream<Double> stream3 = Stream.generate(Math::random).limit(3); stream3.forEach(System.out::println); // 0.231994043797901 // 0.9223616627075024 // 0.522176554775309
5.4 Stream的使用
什么是Optional?
Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
5.4.1 遍历/匹配(foreach/find/match)
Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1); // 遍历输出符合条件的元素 list.stream().filter(x -> x > 6).forEach(System.out::println); // 7,9,8 // 匹配第一个 Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst(); // 7 // 匹配任意(适用于并行流) Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny(); // 7/9/8 // 是否包含符合特定条件的元素 System.out.println("findFirst: " + findFirst.get()); System.out.println("findAny: " + findAny.get()); boolean anyMatch = list.stream().anyMatch(x -> x > 6); System.out.println("anyMatch: " + anyMatch);
5.4.2 筛选(filter)
按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

// 大于7 List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9); Stream<Integer> stream = list.stream(); stream.filter(x -> x > 7).forEach(System.out::println); // 8,9
// 对象筛选 List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95)); add(new Person("lisa", 100)); }}; list.stream().filter(e -> e.getScore() > 96).map(Person::getName).collect(Collectors.toList()).forEach(System.out::println);
5.4.3 聚合(max/min/count)
max、min、count 统计// 长度最长 List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd"); Optional<String> max = list.stream().max(Comparator.comparing(String::length)); System.out.println("max: " + max.get()); // max: weoujgsd
//排序 List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6); // 自然排序 Optional<Integer> max1 = list.stream().max(Integer::compareTo); // 自定义排序(从大到小排序) Optional<Integer> max2 = list.stream().max((o1, o2) -> o2 - o1); System.out.println("max1: " + max1.get()); System.out.println("max2: " + max2.get()); // max1: 11 // max2: 4
// 对象字段比较 List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95)); add(new Person("lisa", 100)); }}; Optional<Person> max = list.stream().max(Comparator.comparingInt(Person::getScore)); System.out.println("max: " + max.get().getScore()); // max: 100
// 大于6的个数 List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9); long count = list.stream().filter(x -> x > 6).count(); System.out.println("count: " + count); // count: 4
5.4.4 映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为
map和flatMap:map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

String[] strArr = {"abcd", "bcdd", "defde", "fTr"}; // 转大写 List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList()); // +3 List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11); List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList()); System.out.println("strList: " + strList); System.out.println("intListNew: " + intListNew); // strList: [ABCD, BCDD, DEFDE, FTR] // intListNew: [4, 6, 8, 10, 12, 14]
// 更改对象的属性值或者形成新对象 List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95)); add(new Person("lisa", 100)); }}; list.stream().map(e -> { e.score += 1; return e; }).collect(Collectors.toList()).forEach(e -> System.out.println(e.getScore())); // 96 // 101
// 数组合并 List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7"); List<String> listNew = list.stream().flatMap(s -> { // 将每个元素转换成一个stream return Arrays.stream(s.split(",")); }).collect(Collectors.toList()); System.out.println("list: " + list); System.out.println("listNew: " + listNew); // list: [m,k,l,a, 1,3,5,7] // listNew: [m, k, l, a, 1, 3, 5, 7]
map系列还有mapToInt、mapToLong、mapToDouble三个函数,它们以一个映射函数为入参,将流中每一个元素处理后生成一个新流。
// 输出字符串集合中每个字符串的长度 List<String> stringList = Arrays.asList("hello", "world"); stringList.stream().mapToInt(String::length).forEach(System.out::println); // +1000 List<Integer> integerList = Arrays.asList(4, 5, 2, 1, 6, 3); integerList.stream().mapToInt(x -> x + 1000).forEach(System.out::println); // 5 // 5 // 1004 // 1005 // 1002 // 1001 // 1006 // 1003
mapToInt三个函数生成的新流,可以进行很多后续操作,比如求最大最小值、求和、求平均值:
List<Double> doubleList = Arrays.asList(1.0, 2.0, 3.0, 4.0, 2.0); double average = doubleList.stream().mapToDouble(Number::doubleValue).average().orElse(0D); double sum = doubleList.stream().mapToDouble(Number::doubleValue).sum(); double max = doubleList.stream().mapToDouble(Number::doubleValue).max().getAsDouble(); System.out.println("average: " + average + " sum: " + sum + " max: " + max); // average: 2.4 sum: 12.0 max: 4.0
5.4.5 归约(reduce)
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
// 求和 乘积 最大值 List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4); Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y); Optional<Integer> sum2 = list.stream().reduce(Integer::sum); Integer sum3 = list.stream().reduce(0, Integer::sum); Optional<Integer> product = list.stream().reduce((x, y) -> x * y); Optional<Integer> max1 = list.stream().reduce((x, y) -> x > y ? x : y); Integer max2 = list.stream().reduce(100, Integer::max); System.out.println("sum: " + sum1.get() + " " + sum2.get() + " " + sum3); System.out.println("multi: " + product.get()); System.out.println("max: " + max1.get() + " " + max2); // sum: 29 29 29 // multi: 2112 // max: 11 100
// 分数之和 最大值 List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95)); add(new Person("lisa", 100)); }}; Optional<Integer> sum1 = list.stream().map(Person::getScore).reduce(Integer::sum); Integer sum2 = list.stream().reduce(0, (sum, p) -> sum + p.getScore(), (a, b) -> a + b); Integer sum3 = list.stream().reduce(0, (sum, p) -> sum + p.getScore(), Integer::sum); Integer max1 = list.stream().reduce(-1, (max, p) -> max > p.getScore() ? max : p.getScore(), (a, b) -> a > b ? a : b); Integer max2 = list.stream().reduce(-1, (max, p) -> max > p.getScore() ? max : p.getScore(), Integer::max); Integer max3 = list.stream().map(Person::getScore).reduce(Integer::max).orElse(-1); System.out.println("sum: " + sum1.get() + " " + sum2 + " " + sum3); System.out.println("max: " + max1 + " " + max2 + " " + max3); // sum: 195 195 195 // max: 100 100 100
5.4.6 收集(collect)
collect,收集,可以说是内容最繁多、功能最丰富的部分了。把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。collect主要依赖java.util.stream.Collectors类内置的静态方法。
5.4.6.1 归集(toList/toSet/toMap)
因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。
toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20); List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList()); Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet()); List<Person> personList = new ArrayList<Person>() {{ add(new Person("john", 95, 22)); add(new Person("lisa", 100, 18)); }}; Map<String, Person> map = personList.stream().filter(p -> p.getAge() > 20).collect(Collectors.toMap(Person::getName, Function.identity())); System.out.println("listNew: " + listNew); System.out.println("set: " + set); System.out.println("map: " + map); // listNew: [6, 4, 6, 6, 20] // set: [4, 20, 6] // map: {john=Person@723279cf}
5.4.6.2 统计(count/averaging)
Collectors提供了一系列用于数据统计的静态方法:- 计数:
count
- 平均值:
averagingInt、averagingLong、averagingDouble
- 最值:
maxBy、minBy
- 求和:
summingInt、summingLong、summingDouble
- 统计以上所有:
summarizingInt、summarizingLong、summarizingDouble
List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95, 22)); add(new Person("lisa", 100, 18)); }}; Long count = list.stream().collect(Collectors.counting()); Double average = list.stream().collect(Collectors.averagingDouble(Person::getAge)); Integer max = list.stream().collect(Collectors.mapping(Person::getScore, Collectors.maxBy(Integer::compare))).orElse(0); Integer sum = list.stream().collect(Collectors.summingInt(Person::getScore)); DoubleSummaryStatistics statistic = list.stream().collect(Collectors.summarizingDouble(Person::getScore)); System.out.println("count: " + count); System.out.println("average: " + average); System.out.println("max: " + max); System.out.println("sum: " + sum); System.out.println("statistic: " + statistic); // count: 2 // average: 20.0 // max: 100 // sum: 195 // statistic: DoubleSummaryStatistics{count=2, sum=195.000000, min=95.000000, average=97.500000, max=100.000000}
5.4.6.3 分组(partitioningBy/groupingBy)
- 分区:将
stream按条件分为两个MapTrue/False
- 分组:将集合分为多个Map,有单级分组和多级分组

List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95, 22)); add(new Person("lisa", 100, 18)); }}; Map<Boolean, List<Person>> part = list.stream().collect(Collectors.partitioningBy(e -> e.getAge() > 20)); Map<Integer, List<Person>> group1 = list.stream().collect(Collectors.groupingBy(Person::getAge)); Map<Integer, Map<Integer, List<Person>>> group2 = list.stream().collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy(Person::getScore))); System.out.println("part: " + part); System.out.println("group1: " + group1); System.out.println("group2: " + group2); // part: {false=[Person@10f87f48], true=[Person@b4c966a]} // group1: {18=[Person@10f87f48], 22=[Person@b4c966a]} // group2: {18={100=[Person@10f87f48]}, 22={95=[Person@b4c966a]}}
5.4.6.4 接合(joining)
joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95, 22)); add(new Person("lisa", 100, 18)); }}; String str = list.stream().map(Person::getName).collect(Collectors.joining(",")); System.out.println("str: " + str); // str: john,lisa
5.4.6.5 归约(reducing)
Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持。List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95, 22)); add(new Person("lisa", 100, 18)); }}; Integer more = list.stream().collect(Collectors.reducing(0, Person::getAge, (a, b) -> (a + b - 18))); // 求和 Integer sum = list.stream().map(Person::getAge).reduce(0, Integer::sum); System.out.println("more: " + more); System.out.println("sum: " + sum); // more: 4 // sum: 40
5.4.7 排序(sorted)
sorted,中间操作。有两种排序:
- sorted():自然排序,流中元素需实现Comparable接口
- sorted(Comparator com):Comparator排序器自定义排序
List<Person> list = new ArrayList<Person>() {{ add(new Person("john", 95, 22)); add(new Person("lisa", 100, 18)); }}; List<String> newList1 = list.stream().sorted(Comparator.comparing(Person::getScore)).map(Person::getName).collect(Collectors.toList()); List<String> newList2 = list.stream().sorted(Comparator.comparing(Person::getScore).reversed()).map(Person::getName).collect(Collectors.toList()); List<String> newList3 = list.stream().sorted(Comparator.comparing(Person::getScore).thenComparing(Person::getAge)).map(Person::getName).collect(Collectors.toList()); List<String> newList4 = list.stream().sorted((a, b) -> { if (a.getScore().equals(b.getScore())) { return b.getAge() - a.getAge(); } else { return b.getScore() - a.getScore(); } }).map(Person::getName).collect(Collectors.toList()); System.out.println("newList1: " + newList1); System.out.println("newList2: " + newList2); System.out.println("newList3: " + newList3); System.out.println("newList4: " + newList4); // newList1: [john, lisa] // newList2: [lisa, john] // newList3: [john, lisa] // newList4: [lisa, john]
5.4.8 提取/组合

String[] arr1 = { "a", "b", "c", "d" }; String[] arr2 = { "d", "e", "f", "g" }; Stream<String> stream1 = Stream.of(arr1); Stream<String> stream2 = Stream.of(arr2); // concat:合并两个流 distinct:去重 List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList()); // limit:限制从流中获得前n个数据 List<Integer> limit = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList()); // skip:跳过前n个数据 List<Integer> skip = Stream.iterate(1, x -> x + 2).skip(2).limit(5).collect(Collectors.toList()); System.out.println("newList: " + newList); System.out.println("limit: " + limit); System.out.println("skip: " + skip); // newList: [a, b, c, d, e, f, g] // limit: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] // skip: [5, 7, 9, 11, 13]