定义个接口Calc1,接口中有个求和方法add,按照之前的匿名内部类来new一个接口对象:
以上使用Lambda则是:
匿名内部类被改成了:
Cal c1=(int a,int b) ->{return a+b;};
以上还是未简化的Lambda表达式,还能再简略。
Lambda表达式本质上是一个函数(匿名函数),正常定义一个函数或者方法是这样的:返回类型、方法名、参数列表、方法体都有。
int add(int a, int b){
return a+b;
}
而Lambda表达式则 只留参数列表和方法体
。即:
(参数列表) -> { 方法体 }
其中:
interface A1{
/**
* 无参数无返回值
*/
void test();
}
A1 a1 = () -> {
System.out.println("无参数无返回值");
};
interface A2{
/**
* 单个参数无返回值
* @param a
*/
void test(int a);
}
A2 a2 = (int a) -> {
System.out.println("单个参数无返回值 a = :" + a);
};
interface A3{
/**
* 两个参数无返回值
* @param a
* @param b
*/
void test(int a,int b);
}
A3 a3 = (int a,int b) -> {
System.out.println("两个参数无返回值 a+b="+(a+b));
};
interface A4{
/**
* 无参数有返回值
* @return
*/
int test();
}
A4 a4 = () -> {
System.out.println("无参数有返回值:"+ 1);
return 1;
};
interface A5{
/**
* 单个参数有返回值
* @param a
* @return
*/
int test(int a);
}
A5 a5 = (int a) -> {
System.out.println("单个参数有返回值:"+ a);
return a;
};
interface A6{
/**
* 多个参数有返回值
* @param a
* @param b
* @return
*/
int test(int a,int b);
}
A6 a6 = (int a, int b) -> {
System.out.println("多个参数有返回值");
return a+b;
};
a6.test(); //看下效果
根据这几条省略规则,上面的lambda表达式可以精简为:
//无参数无返回值
A1 a1 = () -> System.out.println("无参数无返回值");
//单个参数无返回值
A2 a2 = a -> System.out.println("单个参数无返回值 a = :" + a);
//两个参数无返回值
A3 a3 = (a, b) -> System.out.println("两个参数无返回值 a+b="+(a+b));
接下来是有返回值的,去掉System.out.println这行无用的demo语句:
//无参数有返回值
A4 a4 = () -> {
System.out.println("无参数有返回值:"+ 1);
return 1;
};
//去掉System.out.println这行
A4 a4 = () -> 1;
//单个参数有返回值
A5 a5 = a -> a;
//多个参数有返回值
A6 a6 = (a, b) -> a+b;
这个注解用在接口上,标识一个接口为函数式接口,又叫SAM接口,即Single Abstract Method interfaces,即:
这种类型的接口,搭配上面的Lambda表达式来创建该接口的对象就很方便。另外,这个注解不是必须的,当一个接口符合函数式接口的定义,那有没有加这个注解都一样,相反,如果不符合却加了这个注解,则编译器报错。
// 正确的函数式接口
@FunctionalInterface
public interface TestInterface {
// 抽象方法
public void sub();
// java.lang.Object中的public方法
public boolean equals(Object var1);
// 默认方法
public default void defaultMethod(){
}
// 静态方法
public static void staticMethod(){
}
}
// 错误的函数式接口(有多个抽象方法)
@FunctionalInterface
public interface TestInterface2 {
void add();
void sub();
}
JDK内置了一系列函数式接口,在java.util.function包下:
英文格式双冒号
::
,double colon。双冒号(::)运算符在Java 8中被用作方法引用
(method reference),方法引用是与lambda表达式相关的一个重要特性。
lambda表达式会创建匿名方法,但有时lambda表达式的方法体中除了调用一个现有方法外什么都不做,此时可以直接使用双冒号方法引用。举个栗子:
person -> person.getAge()
方法体就是调用下Person类的get方法,此时可以优化为:
Person::getAge
再比如:
() -> new HashMap<>()
优化为:
HashMap::new
这一点在搭配Stream流写代码时最常用,比如常有把对象通过map转为某一个属性后收集:
dtoList.stream()
.map(Dto::getId)
.collect(Collectors.toList());
关于双冒号的六种场景:(注意只是方法名,别加括号)
场景 | 语法 | 举例 |
---|---|---|
引用静态方法 | 类名::静态方法名 | Integer::parseInt |
引用特定对象的实例方法 | 对象::实例方法名 | System.out::println |
引用特定类型的任意对象的实例方法 | 类名::实例方法名 | String::compareToIgnoreCase |
引用父类的实例方法 | super::方法名 | |
引用类的构造方法 |
类名::new |
Person::new |
引用数组的构造方法 | 数组类型[ ]::new | String[ ]::new |