能够将Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个能够抛出的异常列表。java
使用Lambda的最终结果就是你的代码变得更清晰、灵活。打比方,利用Lambda表达式,能够更为简洁地自定义一个Comparator对象。app
举个例子:函数
java8以前spa
Comparator <Apple> byWeight = new Comparator<Apple>(){ public int compare(Apple a1,Apple a2){ return a1.getWeight().compareTo(a2.getWeight()); } };
使用lambda表达式code
(Apple a1,Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
lambda表达式由三个部分对象
列出lambda表达式的使用案例blog
函数式接口就是只定义一个抽象方法的接口。Lambda表达式容许你直接之内联的形式为函数式接口的抽象方法提供实现,并把整个表达式做为函数式接口的实例。 接口
Predicaterem
java.util.function.Predicate<T>接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。在须要表示一个涉及类型T的布尔表达式时,就可使用这个接口。get
@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; } Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
Consumer
java.util.function.Consumer<T>定义了一个名叫accept的抽象方法,它接受泛型T对象,没有返回(void)。
@FunctionalInterface public interface Comsumer<T> { void accept(T t); }@FunctionalInterface public interface Function<T, R> { R accept(T t); }
用这个接口建立一个方法
public static <T> void forEach(List<T> list, Predicate<T> c){ for (T i: list){ c.accept(i); } } forEach( Arrays.asList(1,2,3,4,5), (Interger i) -> System.ou.println(i) );
java.util.function.Function<T, R>定义了一个名叫apply的抽象方法,它接受一个泛型T对象,并返回一个泛型R的对象。
@FunctionalInterface public interface Function<T, R> { R accept(T t); }
public static <T, R> List<R> map(List<T> list, Function<T, R> f){ List<R> result = new ArrayList<>(); for (T s: list){ result.add(f.apply(s)); } return result; } List<Integer> l =map(Arrays.asList("lambdas","in","action"), (String s) -> s.length());
方法引用能够重复使用现有的方法定义,并像Lambda同样传递它们。
先前
invenstory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
使用方法引用和comparing
inventory.sort(comparing(Apple::getWeight));
方法引用主要有三类。
下面用图可让你更清楚地理解
1.3.2构造函数引用
能够利用现有构造函数的名称和关键字来建立它的一个引用 ClassName:new
例1:
Supplier<Apple> c1 = Apple::new; Apple a1 = c1.get();
等价于
Supplier<Apple> c1 = () -> new Apple(); Apple a1 = c1.get();
例2:若是有一个具备两个参数的构造函数Apple(String color , Integer weight),它就适合BiFunction接口的签名,能够这样写
BiFunction<String,Integer,Apple> c2 = Apple::new; Apple c3 = c3.apply("green",110);
例3:若是有三个参数的构造函数呢?Color(int , int , int),你须要本身建立一个与构造函数引用的签名匹配的函数式接口
1.4.1 比较器复合
Comparator<Apple> c = Comparator.comparing(Apple::getWeight);
1.逆序
inventory.sort(comparing(Apple::getWeight).reversed());
2.比较器链
若是两个苹果同样重怎么办,哪一个苹果应该排在前面?这时候可能须要再提供一个Comparator来进一步比较。thenComparing
就是作这个用的。它接受一个函数做为参数(与comparing方法同样),若是两个对象用第一个Comparator比较以后是同样的,就提供第二个Comparator:
inventory.sort(comparing(Apple::getWeight).reversed().thenComparing(Apple::getCountry));
谓词接口包括三个方法:negate、and和or.
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接口所表明的Lambda表达式复合起来。Function接口有两个默认方法:andThen和 compose。它们都会返回Function的一个实例。
andThen 方法会返回一个函数,它先对输入应用一个给定函数,再对输出应用另外一个函数。
好比函数f给数字加1,另外一个函数给数字乘2:
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);
在数学上意味着g(f(x))。
compose 方法先把给定的函数用做compose的参数里面给的那个函数,而后再把函数自己用于结果。
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);
在数学上意味着f(g(x))。