一、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