概念&语法
Lambda表达式时Java 8中提供的一个重要的新特性,它支持Java进行简单的“函数式编程”
通过函数式接口 + Lambda表达式,可以写出更简洁、更灵活的代码
Lambda表达式写法(特殊情况下,还会有些变体):
- (参数列表) -> {多条语句}
- (参数列表) -> 单条语句
- (参数列表) -> 表达式
举例如下:
// 无参,无返回值,单语句
() -> System.out.println("test")
// 有一个参数,无返回值,单语句
(x) -> System.out.println(x)
// >> 省了了小括号
x -> System.out.println(x)
// 有多个参数,且有返回值,单语句
(x,y) -> Interger.compare(x,y)
// 有多个参数,且有返回值,多语句
(x,y) -> {
System.out.println("test");
return Interger.compare(x,y);
}函数式接口:一个只有一个抽象方法(不包括object中已经定义的方法)的接口
举例说明
// 函数式接口
interface MyRunnable {
void run();
}
// 不是函数式接口。原因:方法有默认实现,不是抽象方法
interface MyRunnable {
default void run() {
System.out.println("run");
}
}
// 函数式接口
interface MyRunnable {
void run();
// 该方法已在Object中定义了
String toString();
}基本使用步骤
// 1. 定义函数式接口
interface MyRunnable {
void run();
}
// 2. 使用函数式接口
void test(MyRunnable mr){
...
mr.run();
...
}
// 3. 根据需要,传入不同的lamda表达式
test(()->System.out.println("xxx"));
test(()->{
System.out.println("xxx");
System.out.println("yyy");
});注意:定义函数式接口时,可以添加@FunctionalInterface注解(作用:编译器会强制检查该接口是否是函数式接口)
内置的函数式接口
为了更方便Lambda表达式的使用,Java内置了一些函数式接口。基本都在rt.jar的java.util.function包下。常用的函数式接口如下:
Function<T,R>
package java.util.function;
import java.util.Objects;
/**
* 表示接收一个参数并返回一个结果的函数
*
* 函数方法是R apply(T t)
* @since 1.8
*/
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
/**
* 组合Function,将另一个Function(before)的apply结果作为当前Function的apply参数
* 即先执行before的apply,并将其结果作为当前Function的apply的参数执行
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* 组合Function,将当前Function的apply结果作为另一个Function(after)的apply参数
* 即先执行当前Function的apply,并将其结果作为after的apply的参数执行
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* 总是将参数作为结果返回的Function
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}Predicate<T>
package java.util.function;
import java.util.Objects;
/**
* 表达对一个参数(T)的断言
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* 对参数进行断言,符合断言,则返回true;否则返回false
*
*/
boolean test(T t);
/**
* 增加断言,且同时满足时,才返回true
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* 断言结果取反
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* 增加断言,只要满足一个断言,就返回true
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**
* 判断两个对象是否相等的断言
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}Consumer<T>
package java.util.function;
import java.util.Objects;
/**
* 表达一个操作:接收一个参数,且没有返回值
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
/**
* 组合Consumer,在执行完当前Consumer的accept(T),接着执行after的accept(T)
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}Supplier<T>
package java.util.function;
/**
* 表达生成一个结果
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
T get();
}方法引用
如果Lambda表达式->右边要执行的表达式只是调用一个类已有的方法,那么可以使用“方法引用”来代替Lambda表达式
// ****只有一个参数,调用参数的无参方法(写法:对象::实例方法名)****
Consumer<String> sc = (x)-> System.out.println(x);
// 等效
Consumer<String> sc = System.out::println;
// ****只有一个参数,参数作为类静态方法的参数(写法:类名::静态方法名)****
Function<Integer,String> sf = (x) -> String.valueOf(x);
// 等效
Function<Integer,String> sf = String::valueOf;
// ****有多个参数,第一个参数当作方法的调用者,其他参数作为方法的参数(写法:类名::实例方法名)****
BiPredicate<String,String> sbp = (x,y) -> x.equals(y);
// 等效
BiPredicate<String,String> sbp = String::equals;
// **** 调用无参的构造方法(写法:类名::new)
Supplier<User> us = () -> new User();
// 等效
Supplier<User> us = User:new;尝试解释lambda表达式的写法演进
interface MyInterface {
String func(int i);
}
// lambda表达式的写法演进
// >> 写法1
MyInterface mi = new MyInterface() {
@Override
public String func(int i) {
return String.valueOf(i);
}
};
// >> 写法2
MyInterface mi = (i) -> {
return String.valueOf(i);
};
// >> 写法3
MyInterface mi = (i) -> String.valueOf(i);
// >> 写法4
MyInterface mi = String::valueOf;
















