Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。Lambda 表达式(Lambda expression),基于数学中的λ演算得名,也可称为闭包(Closure) 。
Lambda表达式的语法
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
Lambda表达式由三部分组成:
paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
->:可理解为“被用于”的意思
方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回
函数式接口
要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。
注意:
-
如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
-
如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接
口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只
有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
@FunctionalInterface
interface NoParameterNoReturn {
//注意:只能有一个方法
void test();
}
但是这种方式也是可以的:
@FunctionalInterface
interface NoParameterNoReturn {
void test();
default void test2() {
System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
}
}
Lambda表达式的基本使用
1.无参数无返回值
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn{
//注意:函数式接口只能有一个抽象方法
void test();
}
public class lambda {
public static void main(String[] args) {
NoParameterNoReturn noParameterNoReturn = () -> System.out.println("hello");
noParameterNoReturn.test();
}
}
2.无返回值一个参数
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
public class lambda {
public static void main(String[] args) {
//参数类型只有一个可以省略还可以省略参数的括号
OneParameterNoReturn oneParameterNoReturn = (x) -> System.out.println(x + 10);
oneParameterNoReturn.test(19);
}
}
3.无返回值多个参数
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a, double b);
}
public class lambda {
public static void main(String[] args) {
//类型不可以单独省略,除非一起省略
MoreParameterNoReturn moreParameterNoReturn = (x, y) -> System.out.println(x + y);
moreParameterNoReturn.test(10, 20);
}
}
4.有返回值无参数
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
public class lambda {
public static void main(String[] args) {
// //可以省略return
// NoParameterReturn noParameterReturn=()->{return 10;};
NoParameterReturn noParameterReturn = () -> 10;
int ret = noParameterReturn.test();
System.out.println(ret);
}
}
5.有返回值一个参数
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
public class lambda {
public static void main(String[] args) {
OneParameterReturn oneParameterReturn = x -> x + 10;
int ret = oneParameterReturn.test(9);
System.out.println(ret);
}
}
6.有返回值多参数
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a, int b);
}
public class lambda {
public static void main(String[] args) {
MoreParameterReturn moreParameterReturn = (x, y) -> x * y;
int ret = moreParameterReturn.test(10, 20);
System.out.println(ret);
}
}
语法精练
参数类型可以省略,如果需要省略,每个参数的类型都要省略。
参数的小括号里面只有一个参数,那么小括号可以省略
如果方法体当中只有一句代码,那么大括号可以省略
如果方法体中只有一条语句,且是return语句,那么大括号可以省略,且去掉return关键字
变量捕获
Lambda 表达式中存在变量捕获 ,了解了变量捕获之后,我们才能更好的理解Lambda 表达式的作用域 。Java当中的匿名类中,会存在变量捕获
匿名内部类的变量捕获
class Test {
public void func(){
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
new Test(){
@Override
public void func() {
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a == "+a
+" 我是一个常量,或者是一个没有改变过值的变量!");
}
};
}
}
此时这个代码可以正常运行,而当匿名内部类中修改a的值此时就会报出错误
class Test {
public void func(){
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
new Test(){
@Override
public void func() {
a=99;
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a == "+a +" 我是一个常量,或者是一个没有改变过值的变量!");
}
};
}
}
在上述代码当中的变量a就是,捕获的变量。这个变量要么是被final修饰,如果不是被final修饰的 你要保证在使用之前,没有修改
Lambda的变量捕获
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = ()->{
// a = 99; error
System.out.println("捕获变量:"+a);
};
noParameterNoReturn.test();
}
Lambda在集合当中的使用
Collection接口
forEach() 方法演示
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("this");
list.add("day");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("==========");
list.forEach(s -> System.out.println(s));
}
List接口
sort()方法
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("this");
list.add("day");
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
list.sort((o1, o2) -> {
return o1.compareTo(o2);
});
list.forEach(s -> System.out.println(s));
}
Map接口
HashMap的forEach()
public static void main(String[] args) {
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("hello", 3);
hashMap.put("abc", 2);
hashMap.put("this", 5);
hashMap.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
System.out.println("key" + s + "vay" + integer);
}
});
hashMap.forEach((String s, Integer integer) -> System.out.println("key" + s + "vay" + integer));
}
Lambda优点和缺点
优点:
代码简洁,开发迅速
方便函数式编程
非常容易进行并行计算
Java 引入 Lambda,改善了集合操作 缺点:
代码可读性变差
在非并行计算中,很多计算未必有传统的 for 性能要高
不容易进行调试