lambda
lambda可以理解为匿名函数,由参数列表 箭头 函数主体组成
语法
(parameters)->expression 或 (parameters)->{statements;}
第一种只有一句表达式,会默认返回表达式的值,所以隐藏了return。例如
(Integer x)-> x+x
第二种用于有多个表达式逻辑的代码块,必须使用return明确返回值。
(Integer x)-> {
System.out.println("start ++x");
++x;
return x;
};
函数接口
函数接口是仅有一个抽象方法的接口,例如Function接口
@FunctionalInterface
public interface Function {
R apply(T t);
}
函数接口的作用是可以让lambda表达式为函数式接口的抽象方法提供实现,用lambda直接取代内部类
比如runnable内部类接口
Runnable r2 = new Runnable(){
public void run(){
System.out.println("Hello World 1");
}
};
Runnable 的lambda方式
Runnable r1 = () -> System.out.println("Hello World 1");
这两种方式完全等价,可以说离开函数接口,lambda表达式没有任何作用,一个lambda函数始终是函数接口的实现。
类型推断
lambda表达式可以在编辑期间自动推断参数类型
例如
Function fs = (x)-> x+x;
该例子可以通过Function接口的泛型化参数推断出x是Integer类型的参数。
初学者如何写好lambda表达式
熟悉相关函数接口,明确函数接口抽象方法的结构(参数列表和返回值类型)
例如Function接口
@FunctionalInterface
public interface Function {
R apply(T t);
}
观察抽象方法 R apply(T t);可见该抽象方法定义为由一个T类型的值返回一个R类型的返回值
例如
Function fs = (x)-> {
String helloString = "hello" + x.intValue();
return helloString;
};
声明为输入参数T为Integer类型,返回值R为String类型,所以lambda的参数列表数目(lambda参数可以自动推断)和函数接口抽象方法数目一致,lambda方法体返回结果类型和函数接口返回值类型一致即可。
方法引用
ClassName::staticMethod或者ClassName::instanceMethod
静态方法的引用
public class Main {
public static void main(String[] args) {
List strings = new ArrayList<>();
strings.forEach(Main::print);
}
public static void print(String abc){
System.out.println(abc);
}
}
需要注意的是所引用的方法需要和相关的函数接口匹配(和函数接口的参数类型和返回值一致),比如这个例子的forEach方法接受的函数接口是Consumer
default void forEach(Consumer super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
Consumer是一个消费型的函数接口,接受一个T类型,无返回值
@FunctionalInterface
public interface Consumer {
void accept(T t);
}
而我们的print方法接受一个String类型的参数,无返回值,且strings被限定为String类型,所以Consumer的T类型是String类型,因此print方法能和Consumer函数接口匹配。
实例方法引用
List list = new ArrayList<>();
list.stream().sorted(String::compareTo);
静态方法引用与实例方法引用的区别
静态方法
ClassName::staticMethod ==== (x)->{statements}
实例方法引用
ClassName::staticMethod ==== (x,y)->{statements}
instanceObject::instanceMethod ===== (x)->{statements}