Lambda表达式 Lambda是一个匿名函数 ,我们可以把Lambda表达式理解为是一段可以传递的代码 (将代码像数据一样进行传递)。使用它可以写出更简洁,灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
Lambda表达式的格式 1.标准格式: (参数列表) -> {代码}
2.格式说明: - 小括内的语法与传统方法参数列表一致,没有参数就留空,有多个参数就用逗号分隔
- 【->】 是新引入的语法格式,代表指向动作
- 大括号内的语法与传统方法体要求一致
3.案例说明 第一个线程案例
1 2 3 4 5 6 7 8 9 10 11 12 13 Thread thread1 = new Thread (new Runnable () { @Override public void run () { System.out.println("线程需要执行的任务代码1" ); } }); thread1.start(); Thread t2 = new Thread (()->{ System.out.println("线程需要执行的任务代码2" ); }); t2.start();
第二个比较器案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 List<Integer > list = new ArrayList<>(); Collections.addAll(list,11 ,22 ,33 ,44 ,55 );System .out .println("排序之前的集合:" + list); // 比较器的正常书写格式 Collections.sort(list, new Comparator<Integer >() { @Override public int compare (Integer o1, Integer o2) { return o2-o1; } }); // Lambda表达式 Collections.sort(list,(Integer o1, Integer o2)->{return o2-o1;}); //或者 list.sort((o1,o2)->(o1-o2));System .out .println("排序之后的集合:" + list);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class sortTest { public static void main(String [] args) { int[][] arr ={{2 ,6 },{1 ,3 },{8 ,10 },{15 ,18 }}; Arrays.sort(arr,(x,y)->(x[0 ]-y[0 ])) ; for (int[] ints : arr) { for (int anInt : ints) { System .out .print (anInt+" " ) ; } System .out .println () ; } } } 输出: 1 3 2 6 8 10 15 18 排序成功!
Lambda表达式的使用条件
Lambda表达式不是万能的,他需要函数式接口的支持;
什么是函数式接口: 函数式接口的定义是: 只包含一个抽象方法的接口,称为函数式接口; 其实我们的Lambda表达式就是对函数式接口的一种简写方式,所以只有是函数式接口,我们才能用Lambda表达式;再换句话说,Lambda表达式需要函数式接口的支持,那函数式接口我们可以自己定义,当然JDK1.8也给我们提供了一些现成的函数式接口;
首先,都是接口; 其次,接口中有且只有一个接口,才可以使用lambda表达式
1.接口中只有一个抽象方法的接口,叫做函数式接口
2.如果是函数式接口,那么就可以用@FunctionalInterface注解标识
方法引用 先来看一下什么是方法引用:
方法引用其实是Lambda表达式的另一种写法,当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用;
注意: 实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致! 方法引用:使用操作符::将方法名和对象或类的名字分隔开来,三种主要使用情况为:
对象::实例方法 类::静态方法 类::实例方法
对象::实例方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.util .function .Consumer ;public class MyTest { public static void main (String [] args ) { Consumer <String > consumer = new Consumer <String >() { @Override public void accept (String s ) { System .out .println (s); } }; consumer.accept ("aaaaaaaaaaaaaa" ); Consumer <String > consumer1 = (String s) -> { System .out .println (s); }; consumer1.accept ("abc" ); Consumer <String > consumer2 = (s) -> System .out .println (s); consumer2.accept ("bcd" ); Consumer <String > consumer3 = System .out ::println; consumer3.accept ("abc" ); } }
类::静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.function .BinaryOperator;public class MyTest1 { public static void main(String[] args) { BinaryOperator<Double > operator = new BinaryOperator<Double >(){ @Override public Double apply(Double o, Double o2) { return Math.max(o,o2); } }; System .out .println(operator .apply(2.13 , 3.12 ));//3.12 BinaryOperator<Double > operator2 = (o, o2) -> Math.max(o,o2); System .out .println(operator2.apply(2.13 , 3.12 ));//3.12 BinaryOperator<Double > operator3 = Math::max; Double max = operator3.apply(5.0 , 20.0 ); System .out .println(max);//20.0 } }
因为Math.max()所需要的参数以及返回值与重写的accpet()一样,因此可以简写为类::静态方法;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.Comparator;public class MyTest2 { public static void main(String[] args) { Comparator<Integer > comparator = new Comparator<Integer >() { @Override public int compare(Integer o1, Integer o2) { return Integer .compare(o1,o2); } }; System .out .println(comparator.compare(20 , 12 ));//1 Comparator<Integer > comparator1 = Integer ::compareTo; System .out .println(comparator1.compare(20 , 12 ));//1 } }
类::实例方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util .Comparator ;public class MyTest2 { public static void main (String [] args ) { Comparator <String > comparator = new Comparator <String >() { @Override public int compare (String o1, String o2 ) { return o1.compareTo (o2); } }; System .out .println (comparator.compare ("20" , "12" )); Comparator <String > comparator1 = String ::compareTo; System .out .println (comparator1.compare ("20" , "12" )); } }
为什么可以这样写?、 传递过来的两个参数,一个作为调用者,一个作为参数,这时候,使用类::实例方法简写
Stream流 现有一个需求:
将list集合中姓张的元素过滤到一个新的集合中
然后将过滤出来的姓张的元素中,再过滤出来长度为3的元素,存储到一个新的集合中
1.用常规方法解决需求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 List<String> list1 = new ArrayList <>(); list1.add("张老三" ); list1.add("张小三" ); list1.add("李四" ); list1.add("赵五" ); list1.add("张六" ); list1.add("王八" ); ArrayList<String> list2 = new ArrayList <>();for (String name : list1){ if (name.startsWith("张" )){ list2.add(name); } }ArrayList list3 = new ArrayList ();for (String name : list2) { if (name.length() == 3 ){ list3.add(name); } } System.out.println(list3); 输出结果: [张老三, 张小三]
2.用Stream流操作集合,获取流,过滤操作,打印输出
1 2 3 list1.stream().filter((String name)->name.startsWith("张" )).filter((String name)->name.length()==3 ).forEach((String name)->{ System.out.println("符合条件的姓名:" + name); });
( 看不懂没关系,下面会讲到该方法,这里只是用来引入的)
Stream流的格式 1 2 3 4 5 Stream<T> filter (Predicate<? super T> predicate) ; -----> 参数:public interface Predicate <T> (函数式接口) ----> 抽象方法:boolean test (T t) ; -----> 参数:public interface Consumer <T> (函数式接口) ----> 抽象方法:boolean test (T t) ;
获取流 Collection接口中有一个stream()方法,可以获取流
1 default Stream<E> stream ()
代码演示
1.根据List集合获取流
1 2 3 4 5 6 7 8 9 10 // 创建List集合 List<String> list = new ArrayList<>() list.add("张老三" ) list.add("张小三" ) list.add("李四" ) list.add("赵五" ) list.add("张六" ) list.add("王八" ) Stream<String> stream1 = list.stream()
2.根据Set集合获取流
1 2 3 4 5 6 7 8 9 // 创建List集合 Set<String> set = new HashSet<>() list.add("张老三" ) list.add("张小三" ) list.add("李四" ) list.add("赵五" ) list.add("张六" ) list.add("王八" ) Stream<String> stream2 = set.stream()
3.根据Map集合获取流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Map <Integer ,String > map = new HashMap<>();map .put(1 ,"张老三" );map .put(2 ,"张小三" );map .put(3 ,"李四" );map .put(4 ,"赵五" );map .put(5 ,"张六" );map .put(6 ,"王八" ); Set <Integer > map1 = map .keySet(); Stream<Integer > stream3 = map1.stream(); Collection<String > map2 = map .values(); Stream<String > stream4 = map2.stream();Set <Map .Entry<Integer , String >> map3 = map .entrySet(); Stream<Map .Entry<Integer , String >> stream5 = map3.stream();
4.根据数组获取流
1 2 3 String [] arr = {"张颜宇" ,"张三" ,"李四" ,"赵五" ,"刘六" ,"王七" };Stream <String > stream6 = Stream .of (arr);
Stream流的常用方法 终结方法 :返回值类型不再是Stream接口本身类型的方法,例如:forEach方法和count方法
非终结方法/延迟方法 :返回值类型仍然是Stream接口自身类型的方法,除了终结方法都是延迟方法。例如:filter,limit,skip,map,conat
方法名称
方法作用
方法种类
是否支持链式调用
count
统计个数
终结方法
否
forEach
逐一处理
终结方法
否
filter
过滤
函数拼接
是
limit
取用前几个
函数拼接
是
skip
跳过前几个
函数拼接
是
map
映射
函数拼接
是
concat
组合
函数拼接
是
方法演示 1.count方法 :long count (); 统计流中的元素,返回long类型数据
1 2 3 4 5 6 7 8 9 10 11 List<String> list = new ArrayList<>(); list.add ("张老三" ); list.add ("张小三" ); list.add ("李四" ); list.add ("赵五" ); list.add ("张六" ); list.add ("王八" ); long count = list.stream().count(); System.out.println("集合中的元素个数是:" + count); 输出结果: 集合中的元素个数是:6
2.filter方法
Stream filter(Predicate super ?> predicate); 过滤出满足条件的元素
参数Predicate:函数式接口,抽象方法:boolean test (T t)
Predicate接口:是一个判断接口
// 获取stream流
Stream<String> stream = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");
// 需求:过去出姓张的元素
stream.filter((String name)->{
return name.startsWith("张");
}).forEach((String name)->{
System.out.println("流中的元素" + name);
});
(上面引入Stream流时,就用到了这个方法)
3.forEach方法
void forEach(Consumer<? super T> action):逐一处理流中的元素 参数 Consumer<? super T> action:函数式接口,只有一个抽象方法:void accept(T t);
注意: 1.此方法并不保证元素的逐一消费动作在流中是有序进行的(元素可能丢失) 2.Consumer是一个消费接口(可以获取流中的元素进行遍历操作,输出出去),可以使用Lambda表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 List<String> list = new ArrayList<>(); list.add ("张老三"); list.add ("张小三"); list.add ("李四"); list.add ("赵五"); list.add ("张六"); list.add ("王八"); // 函数模型:获取流 list.stream().forEach ((String name )->{ System .out .println(name ); }); 输出结果: 张老三 张小三 李四 赵五 张六
4.limit方法
Stream limit(long maxSize); 取用前几个元素
注意:参数是一个long 类型,如果流的长度大于参数,则进行截取;否则不进行操作
1 2 3 4 5 6 7 8 9 10 Stream <String > stream1 = Stream .of ("张老三" , "张小三" , "李四" , "赵五" , "刘六" , "王七" ); stream1.limit (3 ).forEach((String name)->{ System.out.println ("流中的前三个元素是:" + name); });D 输出结果: 流中的前三个元素是:张老三 流中的前三个元素是:张小三 流中的前三个元素是:李四
5.map方法
Stream map(Function<? super T,? exception R> mapper; 参数Function<T,R>:函数式接口,抽象方法:R apply(T t); Function<T,R>:其实就是一个类型转换接口(T和R的类型可以一致,也可以不一致)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 获取Stream流 Stream<String > stream1 = Stream.of ("11" ,"22" ,"33" ,"44" ,"55" );// 需求:把stream1流中的元素转换为int类型 stream1.map((String s) -> { return Integer.parseInt (s); // 将String 类型的s进行转换为Integer类型的元素,并返回 }).forEach((Integer i) -> { System.out.println(i); // 将转换后的int类型的元素逐一输出 }); 输出结果: 11 22 33 44 55
6.skip方法
Stream skip(long n); 跳过前几个元素 注意: 如果流的当前长度大于n,则跳过前n个,否则将会得到一个长度为0的空流
1 2 3 4 5 6 7 8 9 10 11 Stream <String > stream = Stream .of ("张老三" , "张小三" , "李四" , "赵五" , "刘六" , "王七" ); stream.skip (3 ).forEach((String name)->{ System.out.println ("跳过前三个,打印剩下的" + name); }); 输出结果: 跳过前三个,打印剩下的赵五 跳过前三个,打印剩下的刘六 跳过前三个,打印剩下的王七
7.concat方法
public static Stream concat(Stream<? extends T> a, Stream<? extends T> b) –> 合并两个流
1 2 3 4 5 6 7 8 Stream <String > stream1 = Stream .of ("11" ,"22" ,"33" ,"44" ,"55" );Stream <String > stream2 = Stream .of ("张颜宇" , "张三" , "李四" , "赵五" , "刘六" , "王七" ); Stream <String > stream = Stream .concat (stream1,stream2); stream.forEach((String name)->{ System.out.print (name); 输出结果:1122334455 张颜宇张三李四赵五刘六王七
收集Stream流
<R, A> R collect(Collector<? super T, A, R> collector); 把流中的数据收集到单列集合中 返回值类型是R。R指定为什么类型,就是手机到什么类型的集合 参数Collector<? super T, A, R>中的R类型,决定把流中的元素收集到哪个集合中 参数Collector如何得到 ?,可以使用 java.util.stream.Collectors工具类中的静态方法:
- public static <T> Collector<T, ?, List<T>> toList():转换为List集合
- public static <T> Collector<T, ?, Set<T>> toSet() :转换为Set集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 List<String> list2 = new ArrayList<>(); list2.add ("张老三"); list2.add ("张小三"); list2.add ("李四"); list2.add ("赵五"); list2.add ("张六"); list2.add ("王八"); // 需求:过滤出姓张的并且长度为3 的元素 Stream<String> stream = list2.stream().filter ((String name ) -> { return name .startsWith("张"); }).filter ((String name ) -> { return name .length() == 3 ; }); // stream 收集到单列集合中 List<String> list = stream.collect(Collectors.toList());System .out .println(list); // stream 手机到单列集合中Set <String> set = stream.collect(Collectors.toSet());System .out .println(set );