Lambda表达式
Lambda表达式的本质只是一个语法糖,由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。
基本语法:
(parameters -> expression)
(parameters -> {expression;})
简单例子:
//仅用三行代码完成 排序后输出列表
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(5, 6, 8, 2, 3, 4, 7, 8, 10);
Collections.sort(integers, (i1,i2) -> i1.compareTo(i2));
integers.forEach(i -> System.out.println(i));
}
为什么使用lambda
应用场景如下:根据不同的策略,选出满足策略条件的苹果进行分类,而策略经常变更。
public interface MatchInterface<T> {
public boolean match(T t);
}
public class MatchClient {
public static <T> boolean match(T t, MatchInterface<T> s) {
return s.match(t);
}
public static void main(String[] args) {
Apple apple = new Apple("red", 150);
// 匿名类实现
match(apple, new MatchInterface<Apple>() {
public boolean match(Apple apple) {
return "red".equals(apple.getColor());
}
});
// lambda表达式实现
match(apple, tmp -> "red".equals(tmp.getColor()));
match(apple, (Apple tmp) -> {
return "red".equals(tmp.getColor());
});
}
}
如上代码所示,即便使用匿名类的形式,比起lambda表达式的实现还是复杂许多。更别说定义实现类。显然可以看出lambda表达式简洁的特性。但是相较而言,无法复用也是lambda表达式对比实现类的缺陷。然后lambda本身就是针对这种较少使用的场景,因而这也不成问题。
对比匿名类和lambda表达式,很容易看出:
->
左边部分是接口抽象方法的参数,而右边是抽象方法的具体实现。
函数式接口
对于一个接口,无论定义了多少个默认方法,只要只定义了一个抽象方法,那么这个接口就是函数式接口。
lambda表达式使用在函数式接口的参数位置,现在我们再回头看示例排序迭代输出代码:
Collections.sort(integers, (i1,i2) -> i1.compareTo(i2));
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
通过lambda表达式实现Comparator
接口,达到排序的目的。
integers.forEach(i -> System.out.println(i));
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
显然这也是对列表的每个元素做accept
操作。即输出到控制台。
使用@FunctionalInterface
注解可以提前校验接口是否是函数式接口
源码中提供的几个函数式接口:
- Predicate:接受泛型T对象,返回boolean
- Consumer:接受泛型T对象,没有返回
- Function:接受泛型T对象,返回R对象
进一步简洁化
方法引用
如果一个Lambda代表的只是直接调用这个方法,那最好使用名称来调用。
构造三种方法引用:
指向静态方法的方法引用
(args) -> className.staticMethod(args) className::staticMethod
示例代码:
public class MethodInvokingClient { public static List<Integer> transformString2Integer(List<String> list, Function<String, Integer> f) { List<Integer> nums = new ArrayList<>(); for (String string : list) { nums.add(f.apply(string)); } return nums; } public static void main(String[] args) { List<String> list = Arrays.asList("1", "3", "5"); transformString2Integer(list, (String s) -> Integer.parseInt(s)); transformString2Integer(list, Integer::parseInt); } }
指向任意类型实例方法的方法引用
(arg0,rest) -> arg0.instanceMethod(rest) ClassName::instanceMethod //ClassName是arg0的类型
示例代码:
public static List<Integer> calculateStringLength(List<String> list, Function<String, Integer> f) { List<Integer> nums = new ArrayList<>(); for (String string : list) { nums.add(f.apply(string)); } nums.forEach(i -> System.out.println(i)); return nums; } public static void main(String[] args) { List<String> list = Arrays.asList("1", "3", "5"); calculateStringLength(list, s -> s.length()); calculateStringLength(list, String::length); }
指向现有对象的实例方法的方法引用
(args) -> anotherInstance.instanceMethod(args) anotherInstance::instanceMethod
示例代码:
public static int contais(List<String> list, Function<String, Boolean> f){ int count = 0; for (String string : list) { if(f.apply(string)){ count++; } } return count; } public static void main(String[] args) { List<String> list = Arrays.asList("1", "3", "5"); List<String> anotherList = Arrays.asList("1", "4", "5"); contais(list, s -> anotherList.contains(s)); contais(list, anotherList::contains); }
复合lambda
比较器复合
List<Integer> integers = Arrays.asList(5, 6, 8, 2, 3, 4, 7, 8, 10); Comparator<Integer> com = (i1,i2) -> i1.compareTo(i2); integers.sort(com.reversed());
谓词复合
Apple apple = new Apple("red", 150); Predicate<Apple> match = tmp -> "red".equals(tmp.getColor()); Predicate<Apple> match2 = match.and(tmp -> tmp.getWeight() > 200); match2.test(apple);
函数复合
Function<Integer, Integer> f = x -> x+1; Function<Integer, Integer> g = x -> x*2; Function<Integer, Integer> h = f.compose(g); int r = h.apply(1); //结果为3