1.3.5 Lambda 表达式中的闭包问题
什么是闭包
闭包的本质就是代码片断。所以闭包可以理解成一个代码片断的引用。在Java中匿名内部类也是闭包的一种实现方式。
在闭包中访问外部的变量时,外部变量必须是final类型,虚拟机会帮我们加上 final 修饰关键字。
二、常用函数接口
2.1 Consumer接口的使用
Consumer 接口是JDK为我们提供的一个函数式接口,该接口也被称为消费型接口。
遍历集合
我们可以调用集合的 public void forEach(Consumer<? super E> action) 方法,通过 lambda 表达式的方式遍历集合中的元素。以下是 Consumer 接口的方法以及遍历集合的操作。
实现方式一:
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; class ConsumerImpl implements Consumer { //Object就是要消费的数据。 @Override public void accept(Object o) { System.out.println(o+"O(∩_∩)O"); } } public class TestConsumer { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); /* forEach可以实现取出集合中的元素但是不知道怎么处理取出的元素。 forEach方法需要的参数是Consumer接口实现类的对象,也就是说我需要给forEach 一个能消费它遍历出来的元素的对象。*/ list.forEach(new ConsumerImpl()); } }
方式二:
如果仅仅是为了输出遍历的数据的话,这样写未免有些麻烦。我们平时使用的输出语句是System.out.println,打开API文档
我们可以发现,out实际上是System类下的静态成员变量,返回的是一个PrintStream类型的数据,该类下的println方法是个无返回值的含有一个Object类型参数的非静态方法。这和Consumer接口中的抽象方法accept的结构一毛一样,因此我们可以使用Lambda表达式将printlin方法作为accept的实现方法。
package cn.it.bz.Lambda; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; public class TestConsumer { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); //将PrintStream类下的println方法作为Consumer接口的抽象方法accept方法的实现方法。 PrintStream out = System.out; list.forEach(out::println); } }
2.2 Predicate接口的使用
Predicate 是 JDK 为我们提供的一个函数式接口,可以简化程序的编写。
删除集合中的元素
我们通过public boolean removeIf(Predicate<? super E> filter)方法来删除集合中的某个元素,
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; class PredicateImpl implements Predicate { @Override public boolean test(Object o) { return "b".equals(o); } } public class TestPredicate { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); //实例化PredicateImpl PredicateImpl predicateImpl = new PredicateImpl(); list.removeIf(predicateImpl); // //或者使用Lambda表达式 // list.removeIf((o)-> o.equals("b")); //查看集合中是否还存在b元素 Consumer consumer = (a) -> System.out.println(a); list.forEach(consumer); } }
2.3 Comparator接口的使用
Comparator是 JDK 为我们提供的一个函数式接口,该接口为比较器接口。
元素排序
之前我们若要为集合内的元素排序,就必须调用 sort 方法,传入比较器重写 compare 方法的比较器对象,现在我们还可以使用 lambda 表达式来简化代码。
排序方式一:
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.Comparator; import java.util.List; class ComparatorImpl implements Comparator<String> { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } } public class TestComparator { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("c"); list.add("d"); list.add("b"); list.add("a"); //元素排序 ComparatorImpl comparatorImpl = new ComparatorImpl(); list.sort(comparatorImpl); //输出 list.forEach(System.out::println); } }
方式二使用Lambda表达式、
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.List; public class TestComparator { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("c"); list.add("d"); list.add("b"); list.add("a"); //元素排序 list.sort((o1,o2) ->o1.compareTo(o2)); //输出 list.forEach(System.out::println); } }
三、Stream流
3.1 Stream流简介
Stream是数据渠道,用于操作数据源所生成的元素序列,它可以实现对集合的复杂操作,例如过滤、排序和映射等。Stream不会改变源对象,而是返回一个新的结果集。
Stream流的生成方式
- 生成流:通过数据源(集合、数组等)创建一个流。
- 中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用。
终结操作:一旦执行终止操作,就执行中间的链式操作,并产生结果。
collection接口中有一个Stream类型的方法,该接口下的实现类实现了该抽象方法,也就是说Collection接口下的List、set等单例集合都存在一个Stream方法返回一个对应的Streatm对象。
3.2 Stream流的常见方法
3.2.1 数据过滤
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; public class TestStream { public static void main(String[] args) { //生成Stream流对象 List<String> list = new ArrayList<>(); list.add("a"); list.add("O(∩_∩)O"); list.add("张三"); list.add("张无形"); Stream<String> stream = list.stream(); //操作流对象 //数据过滤,实现多条件and关系,以张开头三结尾的元素 List<String> collect = stream.filter(o -> o.startsWith("张")).filter(o -> o.endsWith("三")).collect(Collectors.toList()); //遍历过滤后的结合 collect.forEach(System.out::println); System.out.println("--------------------"); Stream<String> stream1 = list.stream(); //多条件的or关系 //先创建or关系 Predicate<String> predicate = (o) ->o.startsWith("张"); Predicate<String> predicate2 = (o) -> o.startsWith("O"); List<String> collect1 = stream1.filter(predicate.or(predicate2)).collect(Collectors.toList()); //遍历过滤后的结合 collect1.forEach(System.out::println); } }
3.2.2 数量限制
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class TestStream2 { public static void main(String[] args) { //生成Stream流对象 List<String> list = new ArrayList<>(); list.add("a"); list.add("O(∩_∩)O"); list.add("张三"); list.add("张无形"); Stream<String> stream = list.stream(); //获取前两个元素 List<String> collect = stream.limit(2).collect(Collectors.toList()); //遍历 collect.forEach(System.out:: println); } }
3.2.3 元素排序
package cn.it.bz.Lambda; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class TestStream3 { public static void main(String[] args) { //生成Stream流对象 List<String> list = new ArrayList<>(); list.add("a"); list.add("O(∩_∩)O"); list.add("张三"); list.add("张无形"); //按照升序排序 List<String> collect = list.stream().sorted().collect(Collectors.toList()); //遍历 collect.forEach(System.out::println); System.out.println("--------------------"); //降序 list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println); } }