函数式接口
@FunctionalInterface 用这个注解标注的接口就是函数式接口
特点
除了default方法和静态方法外,接口中只有一个方法
分类
- 有参数有返回值 功能型
public interface Function<T, R> {
R apply(T t);
}
- 有参数无返回值 消费型
public interface Consumer<T> {
void accept(T t);
}
- 无参数有返回值 供给型
public interface Supplier<T> {
T get();
}
- 有参数返回布尔类型 断言型
public interface Predicate<T> {
boolean test(T t);
}
lambda表达式
我们看一个简单的例子来感受下lambda相比于过去写法的便捷
List<String> stringList = Arrays.asList("123", "121", "119", "134");
//采用匿名内部类的形式
stringList.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
//采用lambda的形式
stringList.sort((s1, s2) -> s1.compareTo(s2));
写法
(args) -> {args相关具体操作}
说明 : args是接口中对应的参数(可以省略类型不写),多个可以用逗号隔开,如果只有一个参数()可以省略。具体操作部分如果只有一条语句{}可以省略。如果是有返回值的接口,并且操作只有一条语句{return}都可以省略
函数式接口用来为 Lambda 定义类型的
- 例子
Comparator<Apple> byColor2 = (o1, o2) -> o1.getColor().compareTo(o2.getColor());
Function<String, Integer> flambda = s -> s.length();
Predicate<Apple> p = (Apple a) -> a.getColor().equals("green");
Predicate<Apple> p2 = a -> {return a.getColor().equals("red");}
method-references方法推导
看一个简单的例子
public static <T> void run(Consumer<T> consumer, T t) {
consumer.accept(t);
}
public static void main(String[] args) {
//lambda Consumer接口,有一个参数无返回值,只是输出
run(x -> System.out.println(x), "hello");
//method-references
run(System.out::println, "world");
//看一下println源码,也是有一个参数无返回值,这时候就可以使用method-references
/**
* Prints a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>String</code> to be printed.
*/
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
}
再看一个方法推导的便捷例子
List<Apple> apples = Arrays.asList(new Apple("red", 213), new Apple("green", 110)
, new Apple("blue", 122));
//采用lambda表达式 写法1
apples.sort((a1,a2) -> a1.getColor().compareTo(a2.getColor()));
// 写法2
apples.sort(Comparator.comparing(x->x.getColor()));
//使用method-references
apples.sort(Comparator.comparing(Apple::getColor));
写法
类或者对象::方法名
//1。通过一个类的静态方法进行推导
int value = Integer.parseInt("456");
Function<String, Integer> function = Integer::parseInt;
Integer apply = function.apply("456");
System.out.println(value == apply);
//2.通过类的成员方法进行推导
BiFunction<String, Integer, Character> function1 = String::charAt;
Character character = function1.apply("hello", 1);
System.out.println(character);
//3.通过对象的普通方法进行推导
String str = new String("world");
Function<Integer, Character> function2 = str::charAt;
Character character1 = function2.apply(2);
System.out.println(character1);
我们回过头看下上面例子中Comparator.comparing的源码
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
可以发现它的入参是一个Function接口,值得注意的是虽然我public String getColor()是个无参有返回值的接口,但是采用类::普通方法这种形式写的时候,相当于传入一个类的对象,所以用Function来接收
Function<Apple, String> getColor = Apple::getColor;
如果我采用对象::方法,就可以用Supplier接口来接收了
Apple apple = new Apple("red", 213);
Supplier<String> supplier = apple::getColor;