Lambda表达式
1、Lambda表达式初步认识
java是一个面向对象的语言,而Lambda表达式却是一个匿名函数,因此java把Lambda表达式抽象成一个匿名内部类(jdk中没有抽象出来,但是它是一个匿名内部类的实现,在下面的截图中,很明显可以看到是一个内部类的地址
为了证实如上所说,我就随手写了一个lambda表达式,来调试一下。
package com.neo.web; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; public class Test2 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("gjeiogj"); list.add("ghreeh"); list.add("ujjkk"); List<Integer> length = list.stream().map(String::length).collect(Collectors.toList()); System.out.println(length); List<String> collect = list.stream().filter(t -> t.length() > 6).collect(Collectors.toList()); System.out.println(collect); // 消费者 Consumer<Integer> c = t -> System.out.println(t.toString()); c.accept(1111); // 生产者 Supplier<String> s = () -> "qwe"; System.out.println(s.get()); // 断言类型 Predicate<Integer> p = t -> { if (t > 0) { return true; } return false; }; System.out.println(p.test(-1)); } }
在debug状态下,我们可以通过watch清楚的看到lambda表达式是一个内部类。清楚了这一点之后,我想对我们理解lambda表达式有着重要的帮助
2、基本结构
Lambda表达式分为3块,分别是参数模块,->,代码块。类似下面的形式。
//真正的表达应该是这样子的 (param1,param2,...,paramn) -> {code body }
分三块来说明一下
1)参数模块
参数模块顾名思义,就是代表着传入Lambda表达式的代码的参数。不需要传参数时,可以直接使用()即可,在参数只有1个的时候,()可以省略。同时也推荐省略。
2)代码模块
代码模块的具体作用就是处理逻辑的具体实现。 需要注意的是,在具体实现的时候,每个分之都必须满足其返回值,这也好比是函数,规定了返回值类型,如果某一个分之返回与之不合的返回值类型,那就肯定错了。
3、函数式接口
定义:只有一个抽象方法的接口。
定义十分简单,但是却有一些比较关键的字眼,我抽取其中三个词:一个,抽象,接口。
一个:只有一个抽象方法,多了不行,少了也不行。
函数式接口常见的Runnable等
@FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
函数式接口的抽象方法,与之对应的Lambda表达式的参数就是这个抽象方法的参数,返回值就是这个抽象方法的返回值。
例如:
@FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); }
Function接口的apply方法,入参类型是T,返回值类型是R
Function<String, Integer> f = item -> item.length(); Integer length = f.apply("bbbb"); System.out.println(length);
Lambda表达式的item是实参,类型是String,item.length()是返回值,且类型是Integer。
4、几种常用函数式接口
1、生产者Supplier
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
功能:不传递参数,返回一个值
生产者(可以理解为,不接受任何参数,返回一个值,究竟返回什么值由调用者决定----Lambda表达式的制造者)
Supplier<String> s = () -> "abc"; String s1 = s.get(); System.out.println(s1);
2、消费者Consumer
@FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); /** * Returns a composed {@code Consumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation * @throws NullPointerException if {@code after} is null */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
功能:传递一个参数,无返回
接收一个参数处理后,无返回值
Consumer<String> c = item -> System.out.println(item);
c.accept("hello");
3、Function (功能接口)
功能:传递1个参数,返回1个参数。
@FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); }
举例:
//输出字符串的长度 Function<String, Integer> f = item -> item.length(); Integer length = f.apply("bbbb"); System.out.println(length);
输入String类型的字符串,返回值是Integer类型的字符串长度。
在Function<T,R>函数式接口中还有着其他方法【compose】,【andThen】,【identity】,这三个方法其实可能也存在其他函数式接口中(在BiFunction这样的接口中,compose方法是不存在的),
对于这样的方法来说在每个函数接口中都是有着自己的实现,只不过我们在读取源码之后发现他在每个函数式接口中的实现都大致相似,因此在Function这个接口中进行一个分析,其他的接口中就不分析了。
1.compose方法,在javadoc中如下描述。 Returns a composed function that first applies the {@code before},其实很简单就是一个前置执行,需要注意的是它传入的是一个Function接口,返回的也是一个Function接口。
/** * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of input to the {@code before} function, and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }
举例:
import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { //接受一个值,返回一个Boolean值 Function<Integer, Integer> function1 = i -> { if (i > 2) { return 2; } else { return 3; } }; Function<Integer, Integer> function2 = i -> i * i; //在function2执行之前,先执行function1,1小于2返回3,3*3 = 9 Integer integer = function2.compose(function1).apply(1); System.out.println(integer); //在function1执行之前,先执行function2,猜测一下 1*1 = 1 ,比2小返回3 Integer integer2 = function1.compose(function2).apply(1); System.out.println(integer2); } }
2、andThen也非常好理解了,就是一个后置执行。
举例:
import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { //接受一个值,返回一个Boolean值 Function<Integer, Integer> function1 = i -> { if (i > 2) { return 2; } else { return 3; } }; Function<Integer, Integer> function2 = i -> i * i; //在function2执行后,再执行function1,1*1 = 1 ,比2小返回3 Integer integer = function2.andThen(function1).apply(1); System.out.println(integer); //在function1执行后,再执行function2,1<2,返回3 ,3*3=9 Integer integer2 = function1.andThen(function2).apply(1); System.out.println(integer2); } }
3、identity这个静态方法根据javadoc中的描述,返回的是一个function,返回自己本身。
/** * Returns a function that always returns its input argument. * * @param <T> the type of the input and output objects to the function * @return a function that always returns its input argument */ static <T> Function<T, T> identity() { return t -> t; }
举例:
将多个字符串组装成map,且key是自身,value为字符串长度
Stream<String> stream = Stream.of("hello", "world", "aaa", "c");
Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), item -> item.length()));
4、Predicate (断言接口)
功能: 传递一个参数,返回一个Boolean值。先看javadoc
@FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); }
举例:
Predicate<Integer> predicate = integer -> { if (integer > 3){ return true; } else { return false; } }; System.out.println(predicate.test(2)); Function<Integer,Boolean> function = integer -> { if (integer > 3){ return true; } else { return false; } }; System.out.println(function.apply(2));