函数式接口
Predicate
@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只有一个需要显示实现的方法,所以可以用@FunctionalInterface,它是一个函数式接口。
示例
public class Bear { private String color; public Bear(String color) { this.color = color; } public static List<Bear> filter(List<Bear> bears, Predicate<Bear> predicate) { List<Bear> bears1 = new ArrayList<>(); for (Bear bear : bears) { if (predicate.test(bear)) { bears1.add(bear); } } return bears1; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public static void main(String[] args) { filter(List.of(new Bear("green"), new Bear("red")), (Bear b) -> b.getColor().equals("red")); } }
Consumer
@FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); ... }
Consumer翻译就是消费者了,所以可以理解为这个接口的作用是消费对象,因此可以看到它是void的
示例
public class Bear { private String color; public Bear(String color) { this.color = color; } public static List<Bear> forEach(List<Bear> bears, Consumer<Bear> consumer) { List<Bear> bears1 = new ArrayList<>(); for (Bear bear : bears) { consumer.accept(bear); } return bears1; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public static void main(String[] args) { forEach(List.of(new Bear("green"), new Bear("red")), (Bear bear) -> System.out.println(bear.getColor())); } }
Function
@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); ... }
这个接口就是接受一个T类型的对象,映射返回一个R类型的对象。
示例
public class Bear { public static <T, R> List<R> map(List<T> bears, Function<T, R> function) { List<R> list = new ArrayList<>(); for (T t : bears) { list.add(function.apply(t)); } return list; } public static void main(String[] args) { List<Integer> list = map(List.of("aa", "aas", "sssss"), (String s) -> s.length()); list.stream().forEach((s) -> System.out.println(s.intValue())); } }
以上是三个标准的泛型化接口,为什么要设计成引用类型呢,因为泛型不允许和原始类型一块使用。当然这个问题也不是这么简单的解释。
类型推断
list.stream().forEach(s -> System.out.println(s.intValue()));
这行代码并没有定义s的类型,但是它是会进行上下文判断的。
使用局部变量
int num = 22; Runnable r = () -> System.out.println(num); ok
int num = 22; Runnable r = () -> System.out.println(num++); error
int num = 22; Runnable r = () -> System.out.println(num); error num++;
lambda中是不允许修改其引用值的。
实际上我之前研究过,此处就是单纯的copy by value, not copy by reference.对比其它的语言,这无疑是一大败笔,当然会改善,但是不知道什么时候,希望尽快,它是个灾难。
lambda可以没有限制的捕获实例变量或者静态变量,但是局部变量必须显示的声明为final,或者不声明但是实际上是final,lambda捕获的局部变量必须是最后一次赋值完成的。
方法引用
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
inventory.sort(comparing(Apple::getWeight));
方法引用的三类:
指向静态方法的引用:Integer中的parseInt方法,写作Integer::parseInt
指向任意类型实例方法的方法引用:String::length
指向现有对象的实例方法引用:下面分析
第二种就是你在引用对象的方法,比如,(String s) -> s.toUpperCase()就可以写成 String::toUpperCase
第三种就是调用外部对象的方法,比如 () -> expenseiveTransaction.getValue() 就可以写成 expensiveTransaction::getValue, 这种也是较为常用的
举个常用的例子,比如你要对List<String>进行排序,可以这样:
List<String> list = Arrays.asList("a", "v", "c");
list.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
也可以只方法引用:
list.sort(String::compareToIgnoreCase);
构造函数引用
Supplier<Apple> c1 = () -> new Apple(); Apple apple = c1.get();
等效于:
Supplier<Apple> c1 = Apple::new; Apple apple = c1.get();
多参数的构造器
BiFunction<String, Integer, Apple> c1 = (color, weight) -> new Apple(color, weight); 这里一个细节就是你需要将要创建的对象放在泛型的尾部 BiFunction<String, Integer, Apple> c2 = Apple::new;
一个示例应用,大概就是根据苹果类型和重量新建苹果对象
public Apple(int weight) { this.weight = weight; } static Map<String, Function<Integer, Apple>> map = new HashMap<>(); static { map.put("apple1", Apple::new); map.put("apple2", Apple::new); } public static Apple giveMeApple(String appleType, Integer weight) { return map.get(appleType.toLowerCase()).apply(20); }
复合Lambda表达式
比较器复合
逆序
apples.sort(Comparator.comparing(Apple::getWeight).reversed());
比较器链
apples.sort(Comparator.comparing(Apple::getWeight)
.reversed()
.thenComparing(Apple::getColor) // 如果两个Apple一样重,那么再比较颜色,当然这里用颜色比较是不合适的
);
谓词复合
函数复合
public static void main(String[] args) { Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.andThen(g); System.out.println(h.apply(1)); }
输出4
andThen实际上是 g(f(x))
public static void main(String[] args) { Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.compose(g); System.out.println(h.apply(1)); } 输出3
compose实际上是f(g(x))
这种函数复合有什么用呢?
小结
《Java8实战》