一、Lambda——匿名函数
等效方法引用
Lambda表达式 | 等效方法引用 |
---|---|
(String s) -> System.out.println(s) | System.out::println |
((str, i) -> str.substring(i) | String::substring |
() -> Thread.currentThread().dumpStack() | Thread.currentThread()::dumpStack |
函数式接口就是只定义一个抽象方法的接口。
Lambda的基本语法是:
(parameters) -> expression
(parameters) -> { statements; }
举例:
① Lambda表达式具有一个 String 类型的参数并返回一个 int 。
Lambda没有 return 语句,因为已经隐含了 return
(String s) -> s.length()
② Lambda表达式有一个Apple 类 型 的参数并返回一个 boolean
(Apple a) -> a.getWeight() > 150
Lambda表达式具有两个 int 类型的参数而没有返回值( void 返回)。
注意Lambda表达式可以包含多行语句,这里是两行。
(int x, int y) -> {
System.out.println("Result:");
System.out.println(x+y);
}
Lambda表达式没有参数,返回一个int 。
() -> 42
Lambda表达式具有两个 Apple 类型的参数,返回一个 int :比较两个 Apple 的重量。
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
对于,对参数有修改,或者修饰,则不能使用方法引用,需要输入完成的lambda表达式
list.forEach((String s) -> System.out.println("*" + s + "*"));
list.forEach( s -> System.out.println("*" + s + "*"));
lambda表达式有个限制,不能在lambda内部修改定义在域外的变量。
List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { factor++; });//不能执行
//可以执行,lambda只能访问它,不可以改变它
primes.forEach(element -> { System.out.println(factor*element); });
二、流操作(Stream)
List 《== 转换 ==》 Stream
Stream<String> stream = list.stream();
List<String> list = stream.collect(Collectors.toList());
常用流的构建:
数组构建
int[] arr = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(arr);
空流:
Stream<Object> emptyStream = Stream.empty();
静态方法Stream.of可以显式值创建一个流。它可以接受任意数量的参数。例如,以下代码直接使用Stream.of创建了一个字符串流:
Stream<String> s = Stream.of("Java", "JavaScript", "C++", "Ruby");
List<String> list = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift");
list.stream()
.filter(s -> s.startsWith("J"))
.map(String::toUpperCase)
.forEach(System.out::println);
流的使用一般包括三件事情:
一个数据源(如集合)来执行一个查询;
一个中间操作链,形成一条流的流水线;
一个终端操作,执行流水线,并能生成结果。
下表列出了流中常见的中间操作和终端操作:
下面详细介绍这些操作的使用。除了特殊说明,默认使用下面这个集合作为演示:
List<String> list = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift", "C++", "Ruby");
常用中间操作
filter
Streams接口支持·filter方法,该方法接收一个Predicate<T>,函数描述符为T -> boolean,用于对集合进行筛选,返回所有满足的元素:
list.stream()
.filter(s -> s.contains("#"))
.forEach(System.out::println);
结果输出2 4
distinct
distinct方法用于排除流中重复的元素,类似于SQL中的distinct操作。比如筛选中集合中所有的偶数,并排除重复的结果:
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);
结果输出JavaScript。
limit
limit(n)方法返回一个长度不超过n的流,比如下面的例子将输出Java JavaScript python:
list.stream()
.limit(3)
.forEach(System.out::println);
map
map方法接收一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素。如:
list.stream()
.map(String::length)
.forEach(System.out::println);
结果输出4 10 6 3 2 6 5 3 4。
终端操作:
collect
collect方法用于收集流中的元素,并放到不同类型的结果中,比如List、Set或者Map。举个例子:
List<String> filterList = list.stream()
.filter(s -> s.startsWith("J")).collect(Collectors.toList());
如果需要以Set来替代List,只需要使用Collectors.toSet()就好了。
count
count方法用于统计流中元素的个数,比如:
list.stream().count(); // 9
forEach
forEach用于迭代流中的每个元素,最为常见的就是迭代输出,如:
list.stream().forEach(System.out::println);
anyMatch allMatch noneMatch
anyMatch方法用于判断流中是否有符合判断条件的元素,返回值为boolean类型。比如判断list中是否含有SQL元素:
list.stream()
.anyMatch(s -> "SQL".equals(s)); // false