一、初步了解Lambda表达式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性之一。
如果不了解python的话,初次学习Lambda表达式肯定有些难以理解。
简单来说,Lambda 表达式是一个匿名函数,即没有函数名的函数。它允许把函数a作为一个函数b的参数(函数作为参数传递到函数中),使用 Lambda 表达式可以使代码变的更加简洁紧凑。
不过往往简洁的东西都比较难理解 orz
二、Lambda表达式与匿名内部类
正式介绍Lambda表达式之前我们先用匿名内部类实现下比较两个Integer值的大小
(匿名内部类的详解见我的另一篇博客,我会写的,相信我)
@Test
public void test1(){
//匿名内部类写法
Comparator<Integer> com = new Comparator<>(){
@Override
public int compare(Integer x1,Integer x2){
//比较两个Integer值大小
return Integer.compare(x1,x2);
}
};
TreeSet<Integer> tree = new TressSet<>(com);
}
现在我们来看一下用Lambda表达式该怎么实现
@Test
public void Test2(){
//Lambda表达式写法
Comparator<Integer> com = (Integer x1,Integer x2) -> Integer.compare(x1,x2);
TreeSet<Integer> tree = new TreeSet<>(com);
}
来看一下匿名内部类和Lambda表达式的对比
由此可见Lambda表达式是由2部分组成的
- 参数列表:黄色框,相当于匿名内部类中函数的参数
- Lambda体:绿色框,相当于匿名内部类中的函数体
(值得一提的是, 红色框的内容虽然相同,但是它并不属于Lambda表达式,Lambda表达式指的是等号“ = ”右边的内容,初学者要注意一下)
这2部分用“ -> ”连接,即:
(参数列表) -> {Lambda体}
可以说Lambd表达式是匿名内部类的一种简化写法
来练习一下Lambda表达式创建线程的写法 (^ _ ^)
@Test
public void test1() {
int num = 0;//jdk1.7之前final必须显示写出来
//匿名内部类创建线程,创建Runnable接口实现类的实例,重写run方法
Runnable r = new Runnable() {
public void run() {
System.out.println("hello Runnable"+num);
};
};
r.run();
//改写成Lambda表达式的形式
Runnable r1 = () -> System.out.println("hello Lambda"+num);//无参数,无返回值
r1.run();
}
三、Lambda表达式的基本语法
刚才我们已经总结了Lambda表达式的整体构造为
(参数列表) -> {Lambda体}
这里可能有人会奇怪说前面的例子中Lambda体没有带大括号{},为什么这里加上了,别着急,往下看
因为Lambda表达式是对匿名内部类中函数的简化写法,函数的有无参、有无返回值等都会对Lambda表达式的语法产生一定的影响
“ -> ”,叫做箭头操作符或者Lambda操作符,它把“ = ”右边的表达式分成两部分
左为参数列表:
Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文可以推断出参数类型;
右为Lambda体:
表达式执行的功能,即Lambda体,Lambda体就像是函数体,里面可以写一条或多条语句。
- 无参,无返回值
//无参数,无返回值
Runnable r1 = () -> System.out.println("hello Lambda");
- 有一个参数,无返回值
当参数只有一个时,可以省略参数的括号
Consumer<String> con = (x)->System.out.println(x);
//只有1个参数可省略括号
Consumer<String> con = x -> System.out.print(x);
- 两个以上参数,有返回值,Lambda体中有多条语句
Comparator<Integer> com = (x,y)->{
System.out.println("函数式接口");
return Integer.compare(x, y);
};
当Lambda体中的语句只有一条时,大括号{}可以省去
Comparator<Integer> com = (x,y)-> Integer.compare(x, y);
我把Lambda表达式的写法总结了一副对联:
上联:左右遇一括号省
下联:左侧推断类型省
横批:省就vans
四、函数式接口
Lambda表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,成为函数式接口。
可以使用@FunctionalInterface 修饰可以检查接口是不是函数式接口
(函数式接口在这里就简单提一下,我会写另一篇博客详细介绍的)
五、Lambda表达式的方法引用
5.1 方法引用
若Lambda体中的功能,已经有方法提供了实现,可以使用方法引用
可以将方法引用理解为lambda表达式的另外一种表现形式
写法有三
- 对象引用 :: 实例方法名
@Test
public void test1() {
PrintStream ps = System.out;
//Consumer是函数式接口的一种,叫消费接口
Consumer<String> con = (str) -> ps.println(str);
con.accept("Hello world");
//改写成 对象引用::实例方法名
Consumer<String> con2 = ps::println;
con2.accept("Hello world");
}
@Test
public void test2() {
//Employee类自己随便写一个就行
Employee emp = new Employee(101, "张三", 18, 9999.99);
//Lambda表达式写法
Supplier<String> sup = () -> emp.getName();
//System.out.println(sup.get());
//改写成方法引用 对象引用::实例方法名
Supplier<String> sup2 = emp::getName;
System.out.println(sup2.get());
}
- 类名::静态方法名
@Test
public void test3() {
//Lambda表达式写法
BiFunction<Double,Double,Double> fun = (x,y) -> Math.max(x,y);
System.out.println(fun.apply(1.5, 2.5));
//方法引用 类名::静态方法名
BiFunction<Double,Double,Double> fun1 = Math::max;
System.out.println(fun.apply(1.5, 2.5));
}
@Test
public void test4() {
//Lambda表达式写法
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
//方法引用 类名::静态方法名
Comparator<Integer> com2 = Integer::compare;
}
- 类名::实例方法名
@Test
public void test5() {
//Lambda表达式写法
BiPredicate<String, String> bp = (x,y) -> x.equals(y);
System.out.println(bp.test("abcde", "abcde"));
//改写成方法引用 类名::实例方法名
BiPredicate<String, String> bp1 = String::equals;
/*——————————————————我是分割线————————————————————*/
//Lambda
Function<Employee, String> fun = (e) -> e.show();
System.out.println(fun.apply(new Employee()));
//方法引用
Function<Employee, String> fun2 = Employee::show;
System.out.println(fun2.apply(new Employee()));
/*——————————————————我是分割线————————————————————*/
Employee e = new Employee(100, "刘能", 59, 2000.34);
Supplier<String> fun3 = e::show;
}
5.2 构造器引用
构造器中的参数列表与函数式接口一致
写法:类名::new
@Test
public void test6() {
//Lambda
Supplier<Employee> sup = () -> new Employee();//Supplier接口获取一个类型,获取Employee类型
System.out.println(sup.get());
//构造器引用
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}
5.3 数组引用
写法:类型[ ] :: new
@Test
public void test7() {
//R apply(T t);
Function<Integer, String[]> fun =(args) -> new String[args];//可实现可变长数组
String[] strs = fun.apply(10);
System.out.println(strs.length);
Function<Integer, String[]> fun2 = String[]::new;
Function<Integer, Employee[]> fun3 = Employee[]::new;
System.out.println(fun2.apply(12).length);
System.out.println(fun3.apply(13).length);
}
转载:https://blog.csdn.net/becatjd/article/details/105081075