lamda表达式
1. 简介
lamda表达式是java语言中函数式编程的一种形式。
关于函数式编程,有一句话是这么介绍的,面向对象编程是对数据的抽象,而函数式编程是对行为的抽象。
反映到函数的定义上,前者传参是一个对象,后者则是一个函数(对象)。lamda表达式承载了定义函数的方式。
2. 形式
一种是直接定义,可以
(a, b) -> return a+b
这种是直接在一句话里写写完,如果需要多条语句,可以这样,加入一个大括号里,里面定义多个表达式。
(a, b)-> {return a+b;}
如果没有返回值就不加return;
另外一种,比方说有一个地方已经定义好了满足需求的函数,我们想直接引用,可以:
obj::fun,或者className::fun
前者是非static的,后者是static的。当然,严格来讲,这种的其实不是定义lamda表达式了,是定义一个函数接口。
3. 引用值
需要注意的是,如果lamda引用了当前方法中的局部变量,这个变量必须是final的或者语义是final的,语义final指的是不能对那个变量再次赋值,否则会编译不通过。
换句话说,对于局部变量,lamda表达式引用的是一个值,而不是一个变量。
这里解释下为什么。
内部类的class文件是通过构造函数入参接收这个局部变量的,所以是值传递。
4. 函数式接口
java里面一切都是有类型的,lamda表达式也不例外。
lamda表达式的背后类型其实是函数接口。函数接口是特殊的接口类型,只包含了一个方法。lamda表达式的形式由背后的函数接口里方法的类型决定。
// 无参返回一个值
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
// 内部消化一个值,没有返回值
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
// 输入一个值,输出结果
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
// 类似function,只不过返回值是bool类型
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
// 加强版function,两个输入
@FunctionalInterface
public interface BiFunction<T, U, R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);
}
// 特殊版的bifunction,参数类型一样
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
..
}
以上是java8内部提供的一些函数接口定义,当然,我们可以自定义。
4. 类型推断
这个不是lamda表达式特定的内容,而是与泛型有关的。
我们定义泛型时,不需要时时刻刻都传入完整的泛型参数,编译器可以通过上下文语境来推断。
比如:
public Integer tryParse(Function<String, Integer> function, String i) {
return function.apply(i);
}
在定义lamda表达式时,是可以推断出类型的。
比如:tryParse((s)->Integer.parseInt(s), "999");
编译器知道s是string,然后返回的是一个int。