能够把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个能够抛出的异常列表。java
好比说new一个Thread的传统写法以下app
Thread t = new Thread(new Runnable() { public void run(){ System.out.println("Hello world"); } });
那么利用lambda表达式的写法就是函数
Thread t = new Thread(() -> System.out.println("Hello world"));
->
左边的就是参数列表,->
右边的就是函数主体工具
查看Java8的源码,被@FunctionalInterface修饰的函数叫作函数式接口,例如Predicate
,这些类每每只有一个抽象函数,那是由于“Lambda表达式理解为简洁地表示可传递的匿名函数
”,直接使用的匿名函数的时候没有指定函数名称,因此,若是有两个及以上抽象函数的时候,虚拟机就不知道你要执行哪一个方法了,如上例中Runnable的run()方法,咱们参数列表部分只使用了(),并无声明调用的函数名。spa
JDK自带的函数式接口都在java.util.function路径下,经常使用的有线程
public interface Predicate<T>{ boolean test (T t); } public interface Consumer<T> { void accept(T t); } public interface Function<T, R> { R apply(T t); } ...
//源码部分 @FunctionalInterface public interface Predicate<T>{ boolean test(T t); } //方法构建 public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> results = new ArrayList<>(); for(T s: list){ if(p.test(s)){ results.add(s); } } return results; } //使用示例,经过filter方法,筛选出String不为空的数据 Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
其余函数式接口使用示例3d
lambda表达式主体部分除了使用参数列表的数据,还可使用lambda表达式外部的局部变量,可是这些局部变量只能声明一次,不然就会报错。code
int portNumber = 1337; //此时会报错,portNumber必须被final修饰 Runnable r = () -> System.out.println(portNumber); portNumber = 31337;
由于lambda表达式主体可看做是匿名内部类,访问外部局部变量是须要final的。从线程的角度来讲,就是局部变量是一个线程(假设叫线程A),lambda表达式主体是另一个线程(线程B),当线程A结束的时候,线程B还要访问线程A的数据,确定是不行的,因此线程B中的变量实质上不是指向线程A中的变量,而是拷贝了一份出来,因此必须保证拷贝出来的数据是不能够改变的。对象
lambda表达式还有一个很是方便的地方,就是方法引用,能够经过类名::方法名
的形式直接使用方法。blog
例如
//静态方法 Integer::parseInt //对象的普通方法 String::length //构造方法 Apple::new
lambda表达式还能够链式调用,同时拥有与或非(negate、and和or)的逻辑判断
//链式调用 inventory.sort(comparing(Apple::getWeight) .reversed() .thenComparing(Apple::getCountry)); //非 Predicate<Apple> notRedApple = redApple.negate(); //与 Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150); //或 Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150) .or(a -> "green".equals(a.getColor()));
Function函数接口提供了两个方法对数据作连续操做
,andThen和compose方法。
Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.andThen(g); int result = h.apply(1); //输出3 ==> )(1*2)+1
andThen方法至关于先执行f函数,再执行g函数。
Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.compose(g); int result = h.apply(1); //输出4 ==> (1+1)*2
compose方法至关于先执行g函数,再执行f函数。
接下来会梳理流的相关知识点、和其余(注入Optionnal、新的时间工具、默认方法等知识)。