目录
一、Lambda表达式
语法格式:
格式一:无参数,无返回值。
格式二:要参数,无返回值。
格式三:数据类型可以省略,可以由编译器进行类型推断。
格式四:只有一个参数时,参数的小括号可以省略。
格式五:有两个及以上的参数,有多条执行语句,并且有返回值。
格式六:当l方法体只有一条语句时,大括号{}可以省略。如果只有一条return语句,则大括号{}和return一并省略。
函数式接口(FunctionalInterface)
四个基本的函数式接口:
Lambda表达式的总结:
二、方法引用
具体使用情况:
情况1:对象 :: 实例方法
情况2:类 :: 类方法(静态方法)
情况3:类 :: 实例方法
三、构造器引用:
四、数组引用:
-> :lambda操作符或箭头操作符->左边的内容:lambda形参列表(对应着要重写的接口中的抽象方法中的形参列表)->右边的内容:lambda体(对应着接口的实现类要重写的方法的方法体)
Runnable r1 = new Runnable()
{
@Override
public void run()
{
System.out.println("I love China");
}
};
等同于:
Runnable r2 = () -> {
System.out.println("I love China");
};
以Consumer接口为例:
Consumer con1 = new Consumer()
{
@Override
public void accept(String s)
{
System.out.println(s);
}
};
等同于:
Consumer con2 = (String s) -> {
System.out.println(s);
};
还是以Consumer接口为例:
Consumer con1 = new Consumer()
{
@Override
public void accept(String s)
{
System.out.println(s);
}
};
等同于:
Consumer con2 = (s) -> {
System.out.println(s);
};
还是以Consumer接口为例:
Consumer con1 = new Consumer()
{
@Override
public void accept(String s)
{
System.out.println(s);
}
};
等同于:
Consumer con2 = s -> {
System.out.println(s);
};
以Comparator接口为例:
Comparator com1 = new Comparator()
{
@Override
public int compare(Integer o1, Integer o2)
{
System.out.println(o1);
System.out.println(o2);
return Integer.compare(o1,o2);
}
};
等同于:
Comparator com2 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return Integer.compare(o1,o2);
};
还是以Comparator接口为例:
Comparator com1 = new Comparator()
{
@Override
public int compare(Integer o1, Integer o2)
{
return Integer.compare(o1,o2);
}
};
等同于:
Comparator com2 = (o1,o2) -> Integer.compare(o1,o2);
Lambda表达式的本质:一方面,Lambda表达式作为接口的实现类的对象。另一方面,Lambda表达式是一个匿名方法。
如果接口中只有一个抽象方法,则此接口就称为函数式接口。
只有给函数式接口提供实现类的对象时,我们才可以使用Lambda表达式。
API中函数式接口所在的包:java.util.function
函数式接口 |
称谓 |
参数类型 |
用途 |
Consumer |
消费型接口 |
T |
对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier |
供给型接口 |
无 |
返回类型为T的对象,包含方法:T get() |
Function |
函数型接口 |
T |
对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(Tt) |
Predicate |
判断型接口 |
T |
确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t) |
->的左边:lambda形参列表,参数的类型都可以省略。如果形参只有一个,则括号( )也可以省略。
->的右边:lambda体,对应着重写的方法体。当方法体只有一条语句时,大括号{}可以省略。如果只有一条return语句,则大括号{}和return一并省略。
使用举例:
以Comparable接口为例:
Comparator com1 = new Comparator()
{
@Override
public int compare(Integer o1, Integer o2)
{
return Integer.compare(o1,o2);
}
};
等同于:
Comparator com3 = Integer :: compare;
方法引用可以看作是基于lambda表达式的进一步刻画。当需要提供一个函数式接口的实例时,可以使用Lambda表达式。当满足一定条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。
方法引用作为了函数式接口的实例。
格式:类(或对象):: 方法名
函数式接口中的抽象方法A,其匿名内部类的匿名对象的实现方法中,调用了某个对象O的某个方法B(非静态)的形参列表与返回值类型与抽象方法A的形参列表与返回值类型一致(可以满足自动装箱和自动拆箱,或满足多态性),可以用方法B对方法A替换、覆盖,便可以直接表示为 对象(对象O) :: 实例方法(方法B)。此替换覆盖即为方法引用。
以Consumer接口为例:(注:System.out是一个对象)
//匿名内部类的格式
Consumer con1 = new Consumer()
{
@Override
public void accept(String s)
{
System.out.println(s);
}
};
//Lambda表达式的格式
Consumer con2 = s -> System.out.println(s);
//方法引用的格式
Consumer con3 = System.out::println;
以Supplier接口为例:
Person pp = new Person(12,"Tom");
//匿名内部类的格式
Supplier sup1 = new Supplier()
{
@Override
public String get()
{
return pp.getName();
}
};
//Lambda表达式的格式
Supplier sup2 = () -> pp.getName();
//方法引用的格式
Supplier sup3 = pp :: getName;
函数式接口中的抽象方法A,其匿名内部类的匿名对象的实现方法中,调用了某个类C的某个类方法B(静态方法)的形参列表与返回值类型与抽象方法A的形参列表与返回值类型一致(可以满足自动装箱和自动拆箱,或满足多态性),可以用方法B对方法A替换、覆盖,便可以直接表示为 类(类C) :: 实例方法(方法B)。
以Comparable接口为例:
//匿名内部类的格式
Comparator com1 = new Comparator()
{
@Override
public int compare(Integer o1, Integer o2)
{
return Integer.compare(o1,o2);
}
};
//Lambda表达式的格式
Comparator com2 = (o1, o2) -> Integer.compare(o1,o2);
//方法引用的格式
Comparator com3 = Integer :: compare;
以Function接口为例:
//匿名内部类的格式
Function fun1 = new Function()
{
@Override
public Long apply(Double aDouble)
{
return Math.round(aDouble);
}
};
//Lambda表达式的格式
Function fun2 = aDouble -> Math.round(aDouble);
//方法引用的格式
Function fun3 = Math :: round;
函数式接口中的抽象方法A,其匿名内部类的匿名对象的实现方法中,调用了某个对象O的某个方法B(非静态)的返回值类型与抽象方法A的返回值类型一致(可以满足自动装箱和自动拆箱,或满足多态性)。
同时,方法A中有n个参数,方法B中有n-1个参数,且抽象方法A的第一个参数作为方法B的调用者(即对象O),方法B的n-1个参数与方法A的第一个参数之后的n-1个参数一致(可以满足自动装箱和自动拆箱,或满足多态性),可以用方法B对方法A替换、覆盖,便可以直接表示为 类(对象O所在的类) :: 实例方法(方法B)。此替换覆盖即为方法引用。
比如,若A方法的参数依次为H、I、J、K类型的,B方法的参数依次应该为I、J、K类型的(或满足自动装箱和自动拆箱,或满足多态性)。
以Comparator接口为例:
//匿名内部类的格式
Comparator com1 = new Comparator()
{
@Override
public int compare(String s1, String s2)
{
return s1.compareTo(s2);
}
};
//Lambda表达式的格式
Comparator com2 = (s1,s2) -> s1.compareTo(s2);
//方法引用
Comparator com3 = String :: compareTo;
以BiPredicate接口为例:
//匿名内部类的格式
BiPredicate biPre1 = new BiPredicate()
{
@Override
public boolean test(String s1, String s2)
{
return s1.equals(s2);
}
};
//Lambda表达式的格式
BiPredicate biPre2 = (s1,s2) -> s1.equals(s2);
//方法引用
BiPredicate biPre3 = String :: equals;
格式:类名 :: new
以Suppiler为例:
//匿名内部类的格式
Supplier sup1 = new Supplier()
{
@Override
public Person get()
{
return new Person();
}
};
System.out.println(sup1.get());
//Lambda表达式的格式
Supplier sup2 = () -> new Person();
//构造器引用的格式
Supplier sup3 = Person :: new;
说明:
·调用了类名对应的类中的某一个确定的构造器
·具体调用的是与函数式接口中的抽象方法的形参列表一致(可以满足自动装箱和自动拆箱,或满足多态性)的形参列表的构造器。
以Function接口和BiFunction接口为例:
//匿名内部类的格式
Function func1 = new Function()
{
@Override
public Person apply(Integer integer)
{
return new Person(integer);
}
};
//Lambda表达式的格式
Function func2 = integer -> new Person(integer);
//构造器引用
Function func3 = Person :: new;//调用的是参数为Integer类型的,由于自动拆箱,调用的是int类型的构造器
//匿名内部类的格式
BiFunction biF1 = new BiFunction()
{
@Override
public Person apply(Integer integer, String s)
{
return new Person(integer,s);
}
};
//Lambda表达式的格式
BiFunction biF2 = (integer,s) -> new Person(integer,s);
//构造器引用的格式
BiFunction biF3 = Person :: new;
格式:数组名[ ] :: new
说明:数组引用里的数组的长度由方法的参数决定。
例:
//匿名内部类的格式
Function fu1 = new Function()
{
@Override
public Person[] apply(Integer integer)
{
return new Person[integer];
}
};
//Lambda表达式的格式
Function fu2 = integer -> new Person[integer];
//构造器引用的格式
Function fu3 = Person[] :: new;