Lambda简介
Lambda
可定义为一种简洁、可传递的匿名函数,它是推动Java 8发布的最重要新特性Lambda
本质上是一个函数,虽然它不属于某个特定的类,但具备参数列表、函数主体、返回类型,甚至能够抛出异常Lambda
是匿名的,它没有具体的函数名称Lambda
允许把函数作为一个方法的参数(函数作为参数传递进方法中)Lambda
可以使代码变的更加简洁
Lambda基本语法
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
- parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数。
- ->:可以理解为被用于
- 方法体:可以是表达式,也可以是代码,是函数式接口里方法的实现。
代码示例:
// 返回给定字符串的长度(隐含return语句)
(String str) -> str.length()
// 始终返回233的无参方法(隐含return语句)
() -> 233
// 返回当前用户是否年龄大于20岁,返回一个boolean值(隐含return语句)
(User user) -> user.getAge() > 20
// 包含多行表达式,需用花括号括起来,并使用return关键字返回
(int x, int y) -> {
int z = x * y;
return x + z;
}
使用Lambda与传统写法对比
public class testMain {
//执行Runnable方法
public static void process(Runnable r){
r.run();
}
public static void main(String[] args) {
//使用Lambda
Runnable r1=()-> System.out.println("Hello Lambda");
//传统匿名类
Runnable r2 = new Runnable(){
public void run(){
System.out.println("Hello World 2");
}
};
//打印 "Hello World 1"
process(r1);
//打印 "Hello World 2"
process(r2);
//利用直接传递的 Lambda 打印 "Hello World 3"
process(() -> System.out.println("Hello World 3"));
}
}
Lambda表达式的基本使用
@FunctionalInterface
interface NoParameterNoReturn {
//注意:只能有一个抽象方法
void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(String a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a, int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
String test(String a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a, int b);
}
具体使用见以下示例代码
//没有参数没有返回值
NoParameterNoReturn noParameterNoReturn=()-> System.out.println("noParameterNoReturn");
noParameterNoReturn.test();
//没有参数但是有返回值
NoParameterReturn noParameterReturn=()->40;
System.out.println("noParameterReturn: "+ noParameterReturn.test());
//一个参数没有返回值
OneParameterNoReturn oneParameterNoReturn=(name)-> System.out.println("Hello :" +name);
oneParameterNoReturn.test("张三");
//一个参数和返回值
OneParameterReturn oneParameterReturn=(name)-> "Hello: "+name;
System.out.println("oneParameterReturn : "+ oneParameterReturn.test("李四") );
//多参数没有返回值
MoreParameterNoReturn moreParameterNoReturn=(a,b)-> System.out.println("a+b= "+(a+b));
moreParameterNoReturn.test(10,20);
//多参数和返回值
MoreParameterReturn moreParameterReturn=(a,b)-> a+b;
System.out.println("moreParameterReturn: "+ moreParameterReturn.test(20,40));
输出结果如下:
Lambda 受检异常处理
简介
Lambda
表达式利用函数式编程提供精简的方式表达行为。- 然而,JDK函数式接口没有很好地处理异常,使得处理异常代码非常臃肿和麻烦。
- 接下来我们探讨
Lambda
表达式中处理异常的解决方案
代码示例
以一个简单代码为例,将10与List中每个元素相除并打印出结果
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
integers.forEach(i -> System.out.println(50 / i));
这样看是不会有问题的,代码简洁。但是如果List中包含元素0
,那么就会抛出异常:ArithmeticException: / by zero
有经验的小伙伴可能会立马给出解决方案,使用传统的try-catch来处理异常,代码如下:
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 0);
integers.forEach(i -> {
try {
System.out.println(10 / i);
} catch (ArithmeticException e) {
System.err.println( "Arithmetic Exception occured : " + e.getMessage());
}
});
使用try-catch解决了问题,但是失去了lambda表达式的精简,代码变得臃肿,想必并不是完美的解决方案。对于一些强迫症老哥来说,这种代码是绝对不能存活的,所以我们需要如下的解决方案。
解决方案
我们将会对抛出异常的函数进行包装,使其不抛出受检异常如果一个FunctionInterface
的方法会抛出受检异常(比如Exception
),那么该FunctionInterface
便可以作为会抛出受检异常的 Lambda 的目标类型。我们定义如下一个FunctionInterface
:
@FunctionalInterface
interface UncheckedFunction<T, R> {
R apply(T t) throws Exception;
}
首先我们定义一个Try
类,它的consumerWrapper方法:
public class Try {
public static <T, E extends Exception> Consumer<T> consumerWrapper(Consumer<T> consumer, Class<E> clazz) {
return i -> {
try {
consumer.accept(i);
} catch (Exception ex) {
try {
E exCast = clazz.cast(ex);
System.err.println(
"Exception occured : " + exCast.getMessage());
} catch (ClassCastException ccEx) {
throw ex;
}
}
};
}
}
然后在原先的代码中,我们使用Try.consumerWrapper
方法来对会抛出受检异常的 Lambda 进行包装:
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 0);
integers.forEach(
Try.consumerWrapper(
i -> System.out.println(50 / i),
ArithmeticException.class));
此时,我们便可以选择是否去捕获异常(RuntimeException
)。这种解决方法下,我们一般不关心抛出异常的情况 。比如自己写的小例子,抛出了异常程序就该终止;或者你知道这个 Lambda 确实 100% 不会抛出异常。