1、概述
Java8中引入了一个新的操作符"->” 该操作符称为箭头操作符或Lambda 操作符。
箭头操作符将Lambda表达式拆分成两部分:
左侧: Lambda表达式的参数列表;
右侧: Lambda表达式中所需执行的功能,即Lambda体。
2、语法举栗
2.1 无参数,无返回值
@Test
public void test(){
int num=3;
Runnable runnable=()->System.out.println("Hello Lambda"+num);
runnable.run();
}
2.2 有一个参数,无返回值
此时只有一个参数,参数(x) 的括号可以省略不写
@Test
public void test1(){
List<String> list=new ArrayList<>();
// 参数(x) 的括号省略不写
// Consumer<String> consumer=(x) ->list.add(x);
Consumer<String> consumer=x ->list.add(x);
consumer.accept("aaa");
consumer.accept("bbb");
list.forEach(System.out::println);
}
2.3 有两个以上的参数,有返回值,并且Lambda体中有多条语句
@Test
public void test2(){
Comparator<Integer> comparator=(x,y)->{
System.out.println("x为:"+x);
System.out.println("y为:"+y);
return Integer.compare(x,y);
};
System.out.println(comparator.compare(1,2));
}
2.4 Lambda体中只有一条语句,return 和大括号都可以省略不写
Lambda表达式的参数列表的数据类型是可以省略不写的。因为JVM编译器可以通过上下文推断出数据类型,也就是’类型推断’。
@Test
public void test3(){
// 参数类型可省略
// Comparator<Integer> comparator=(Integer x,Integer y)->Integer.compare(x,y);
Comparator<Integer> comparator=(x,y)->Integer.compare(x,y);
System.out.println(comparator.compare(1,2));
}
3、函数式接口
3.1 说明
Lambda 表达式需要"函数式接口“的支持。什么是函数式接口?即接口中只有一个抽象方法的接口,可以使用注解@FunctionalInterface进行修饰。注解 @FuncitonalInterface 会限定该接口为函数式接口,即必须有且只有一个抽象方法,否则将无法通过编译。
举个栗子:
自定义函数式接口
@FunctionalInterface
public interface MyCompare<T> {
int compare(T o1,T o2);
}
实现方法再进行调用
public int compareImpl(Integer num1, Integer num2, MyCompare<Integer> myCompare){
return myCompare.compare(num1,num2);
}
@Test
public void testMyCompare(){
int num=compareImpl(11,2,(x,y)-> Integer.compare(x,y));
System.out.println(num);
}
3.2 四大内置核心函数式接口
消费型接口
Consumer<T>
void accept(T t);
举个栗子
public void consume(Integer integer,Consumer<Integer> consumer){
consumer.accept(integer);
}
@Test
public void testConsumer(){
consume(100,(x)->System.out.println(x));
}
供给型接口
Supplier<T>
T get();
举个栗子
public List<Integer> integerList(int n, Supplier<Integer> supplier){
List<Integer> numList=new ArrayList<>();
for(int i=0;i<n;i++){
numList.add(supplier.get());
}
return numList;
}
@Test
public void testSupplier(){
List<Integer> numList=integerList(5,()->(int)(Math.random()*100));
for(Integer integer:numList){
System.out.println(integer);
}
}
函数型接口
Function<T, R>
R app1y(T t);
举个栗子
public String strHandler(String str, Function<String,String> function){
return function.apply(str);
}
@Test
public void testFunction(){
String str=strHandler("hello world!",x->x);
System.out.println(str);
}
断言型接口
Predicate<T>
boolean test(T t);
举个栗子
public List<String> strFilter(List<String> strList, Predicate<String> predicate){
List<String> list=new ArrayList<>();
for(String s:strList){
if(predicate.test(s)){
list.add(s);
}
}
return list;
}
@Test
public void testPredicate(){
List<String> strList=new ArrayList<>();
List<String> list=strFilter(strList,x->x.length()>5);
System.out.println(list);
}
4、方法引用和对象引用
“::”为方法引用运算符,它所在的表达式称为方法的引用。Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName :: method。
方法引用的三种语法格式:
对象: :实例方法名
@Test
public void test5(){
Consumer<String> consumer=(x)->System.out.println(x);
consumer.accept("hello world!");
Consumer<String> consumer1=System.out::println;
consumer.accept("hello China!");
}
类: :静态方法名
@Test
public void test6(){
Comparator<Integer> comparator=(x,y)->Integer.compare(x,y);
System.out.println(comparator.compare(1,2));
Comparator<Integer> comparator1=Integer::compareTo;
System.out.println(comparator1.compare(1,2));
}
类: :实例方法名
@Test
public void test7(){
BiPredicate<String,String> biPredicate=(x,y)->x.equals(y);
System.out.println(biPredicate.test("1","2"));
BiPredicate<String,String> biPredicate1=String :: equals;
System.out.println(biPredicate1.test("1","2"));
}
构造器引用
需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致。下面举个栗子:
public class Cat {
int age;
String name;
public Cat(){
}
public Cat(int age){
this.age=age;
}
}
@Test
public void test8(){
// 无参构造
Supplier<Cat> cat=Cat::new;
// 有参构造,参数列表一致
Function<Integer,Cat> catFunction=Cat::new;
}