Thread thread = new Thread(() -> {
System.out.println("HelloWorld");
});
thread.start();
复制代码
“Lambda表达式
理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它 有参数列表、函数主体、返回类型,可能还有一个能够抛出的异常列表”(参考Java8实战)java
Lambda表达式包含3部分:express
参数列表使用括号()来表示,其中参数能够声明参数类型,也能够不声明参数类型(编译器会根据上下文推断)。bash
Lambda表达式的函数体,既能够是代码块
,也能够是表达式
。 代码块:和普通方法的方法主体一致; 表达式:表达式会被执行并返回结果,其本质上是一种return语句的简写(省略了return和{})app
Lambda不只能够省略参数类型、用表达式表示方法体,其实还能够直接使用方法引用
来替代Lambda表达式,例如以下三种方式是等价的:dom
Consumer<String> consumer1 = (String str) -> {
System.out.println(str);
};
Consumer<String> consumer2 = (str) -> {
System.out.println(str);
};
Consumer<String> consumer3 = System.out::println;
复制代码
Lambda表达式拥有以下特色:ide
Lambda表达式
用来为某个抽象方法提供实现,我的能够粗略地讲其理解为一种匿名内部类
更加通俗易懂,但二者并不彻底相同。函数
二者有以下相同点:ui
final String word = "Hello";
Runnable runnable = () -> {
// 不能够在Lambda表达式中修改外部变量,不然会提示Variable used in lambda expression should be final or effectively final
// word = "HelloWorld";
function1();
System.out.println(word);
};
runnable.run();
Runnable runnable1 = new Runnable() {
@Override
public void run() {
function1();
// 不能够在内部类中修改外部变量,不然会提示Variable is accessed within inner class. Needs to be final or effectively final
// word = "HelloWorld";
System.out.println(word);
}
};
runnable1.run();
复制代码
this
指的是外部类的对象,而内部类中this
指的是内部类对象。见做用域示例1。 (2)Lamda表达式中调用的方法也都是外部类的,但内部类中调用的方法是优先内部的。public class HelloLambda {
Runnable r1 = () -> {
System.out.println("Lambda, 1: " + this);
System.out.println("Lambda, 2: " + toString());
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("Inner class, 1: " + this);
System.out.println("Inner class, 2: " + toString());
}
};
@Override
public String toString() {
return "Hello, lambda!";
}
public static void main(String[] args) {
new HelloLambda().r1.run();
new HelloLambda().r2.run();
}
}
复制代码
输出:this
Lambda表达式r1因为外部类中没有run()方法,因此报错;但r2因为内部类中有run()方法,全部能够经过编译,实际上就是循环调用了。 编码
函数式接口
就是有且仅有一个抽象方法的接口。
Lambda表达式容许直接之内联的形式为函数式接口的抽象方法提供实现,并把整个表达式做为函数式接口的实例。(其实能够将Lambda表达式看作匿名内部类,该匿名内部类实现了函数式接口)。
接下来介绍几种常见函数式接口。
Runnable接口源码
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
复制代码
观察Runnable源码,能够发现该接口中只有一个抽象方法run(),故能够使用Lambda表达式来做为该函数式接口的实例,并提供抽象方法的实现。
Runnable runnable = () -> {
System.out.println("Hello world!");
};
复制代码
Callable接口源码:
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
复制代码
Callable接口的Lambda表达式示例:
Callable<String> callable = () -> {
return "HelloWorld";
};
复制代码
Callable接口有返回值,Lambda主体能够直接使用表达式替代return语句,以下:
Callable<String> callable = () -> "HelloWorld";
复制代码
@FunctionalInterface
public interface Comparator<T> {
// 抽象方法
int compare(T o1, T o2);
// 重写Obejct类public方法的抽象方法,不进行计数
boolean equals(Object obj);
// 非抽象方法
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
}
复制代码
观察源码,能够发现Comparator实现类:(1)须要声明泛型;(2)须要实现compare方法,且参数列表有两个,参数类型与泛型类上声明一致。
Comparator<Integer> comparator = (o1, o2) -> o1.compareTo(o2);
复制代码
List<Integer> numbers = Lists.newArrayList(1, 2, 3);
numbers.sort((x1, x2) -> x2.compareTo(x1));
numbers.forEach((x) -> {
System.out.println(x);
});
复制代码
输出:
按user年龄倒序排序:
List<User> users = Lists.newArrayList(new User(18), new User(22), new User(24));
users.sort((u1, u2) -> u2.age.compareTo(u1.age));
users.forEach((u) -> {
System.out.println(u.age);
});
复制代码
输出:
Consumer接口是一种有参无返回值的消费型接口。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
复制代码
Consume接口能够理解为一种通用消费型接口(能够接收参数,但不能返回),经过lambda表达式定义好要执行的动做,经过调用accept方法执行。
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("Hello world1!");
复制代码
拿其与Runable接口比较更好理解,Runnable接口也能够直接执行run方法(就没有线程特性了),可是没法接受传入的参数。比较
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("Hello world1!");
Runnable runnable = () -> {
System.out.println("Hello world2!");
};
runnable.run();
复制代码
我的理解,Consumer接口最多见的用途是做为回调。
以下所示,function1接收参数list、以及回调函数consumer,function1自己不关心如何处理、直接执行consumer.accept(),具体的处理由传入的consumer变量(lambda表达式、回调函数)决定,能够经过修改传入的consumer变量来修改函数的实现。
public static void function1(List<Integer> list, Consumer<List<Integer>> consumer) {
consumer.accept(list);
}
public static void main(String[] args) {
// 存储lambda表达式
Consumer<List<Integer>> consumer1 = list -> {
list.sort((x1, x2) -> x2.compareTo(x1));
};
Consumer<List<Integer>> consumer2 = list -> {
list.sort((x1, x2) -> x1.compareTo(x2));
};
List<Integer> numbers = Lists.newArrayList(1, 2, 3);
// 传递lambda表达式
function1(numbers, consumer1);
numbers.forEach((x) -> {
System.out.println(x);
});
function1(numbers, consumer2);
numbers.forEach((x) -> {
System.out.println(x);
});
}
复制代码
BiConsumer接口则是Consumer接口升级版,能够接受两个参数:
BiConsumer<String, Integer> biConsumer = (str, num) -> {
System.out.println(str + num);
};
biConsumer.accept("Hello, ", 123);
复制代码
还有其余消费型接口,好比IntConsumer。
Supplier
接口是一种无参有返回值的供给型接口。能够理解为一个容器,能够生成、存储对象,供其它方法调用其中get()
方法获取对象。
@FunctionalInterface
public interface Supplier<T> {
T get();
}
复制代码
Supplier<User> supplier = () -> {
return new User(123);
};
User user = supplier.get();
System.out.println(user.age);
复制代码
以下所示,getId方法用于返回一个int型整数,但不一样的地方可能使用不一样的生成策略,因此使用Supplier接口做为参数,将id生成策略回调出去。
public static Integer getId(Supplier<Integer> supplier) {
return supplier.get();
}
public static void main(String[] args) {
Supplier<Integer> supplier1 = () -> (new Random()).nextInt(10);
Supplier<Integer> supplier2 = () -> (new Random()).nextInt(100);
System.out.println(getId(supplier1));
System.out.println(getId(supplier2));
}
复制代码
可是我的理解上Supplier接口意义很低,不能接受参数、直接return,即使做为回调也难以有太多实际使用场景。
Predicate接口一种有参数返回值类型为布尔型的断言型接口。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
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);
}
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);
}
}
复制代码
观察源码能够发现,须要实现test()方法,而且还支持and/or联合判断条件。
Predicate<Integer> predicate = (x) -> x < 100;
Predicate<Integer> predicate1 = (x) -> x > 0;
System.out.println(predicate.test(1));
System.out.println(predicate.and(predicate1).test(-1));
复制代码
输出结果:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
复制代码
观察源码获得须要实现其中apply()
方法,而lambda表达式的参数<T, R>,其中T表明函数的参数类型,R表明返回类型(第一个是参数,第二个是返回值)。
Function
接口使用的场景较多Consumer/Predicate/Supplier接口能实现的功能用Function接口也均可以实现。
Function<Integer, String> function = (x) -> {
if (x < 0) {
return "小于0";
} else {
return "大于等于0";
}
};
System.out.println(function.apply(3));
复制代码
Function
接口一样也有用来接收两个参数的BiFunction
接口。
BiFunction<Integer, Integer, String> function = (x1, x2) -> {
return new StringBuilder("Receive x1=").append(x1).append(", x2=").append(x2).toString();
};
复制代码
Java8新增了一个接口java.util.Stream,能够将Collection、List、Set、Map等使用流进行处理,编码更加方便快捷。Stream接口依赖于Lambda表达式。 详见:。。。。。。。。。