由于开发使用的是jdk8,lamaba表达式作为jdk8一项重要的特性。实际团队项目开发中,发现有不少地方使用了lamaba表达式,所以,特地了解了一下。
一、什么是Lambda 表达式
Lambda 表达式简单的说就是匿名函数,即它是没有申明的方法,没有访问修饰符、没有方法名、没有返回值。
二、函数式接口
1.函数式接口(functional interface):简单来说,函数式接口是只包含一个抽象方法的接口。比如Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。java 8提供 @FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口),虚拟机会自动判断,但最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。
可以看到Runnable接口中只有一个抽象方法:
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
2.常见的函数式接口有:
接口 | 参数 | 返回类型 | 示例 |
---|---|---|---|
Predicate | T | boolean | 这张唱片已经发行了吗 |
Consumer | T | void | 输出一个值 |
Function | T | R | 获得 Artist 对象的名字 |
Supplier | None | T | 工厂方法 |
UnaryOperator | T | T 逻辑非 (!) | |
BinaryOperator | (T, T) | T | 求两个数的乘积 |
可能有人会说Predicate接口里面有多个方法啊,怎么也是函数式接口?注意函数式接口的定义:只包含一个抽象方法的接口。
Predicate接口里面除了有一个test抽象接口以外,还有其它几个接口,不过这几个接口都是default和static类型。这是java8中所特有的类型。JAVA8中可以在接口中定义默认的行为、以及静态方法的实现。并且它们不属于抽象方法,所以Predicate任然是一个函数式接口。
@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);
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);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
三、函数式接口与lamaba表达式的关系
之所以会讲函数式接口是因为:Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口方法的实现。
四、lamaba表达式语法
格式:
参数 -> 方法体
lamaba表达式语法非常简洁,由三部分组成,参数、->、方法体。
参数:是函数式接口方法的参数,可以有多个,由小括号包围,多个参数以逗号隔开,(x,y)
()->2 无参
(x)-> x>2 单个参数,也可以写成 x-> x>2
(x,y) -> x+y 多个参数
方法体:方法体是函数式接口里面方法的实现,如果是代码块,则必须用{}来包裹起来,且需要一个return 返回值,但有个例外,若函数式接口里面方法返回值是void,则无需{}
(x,y) -> x+y 方法
(x,y) -> {x++;return x+y;} 代码块
简单实现:
new Thread(() ->System.out.println(“lamaba”)).start();
五、lamaba性能
lamaba表达式虽然简洁,但是性能的话却不及传统的方式,拿for循环迭代来说:
long count = 0;
long t1 = System.currentTimeMillis();
for (Integer i : list) {
if (i > 4999) {
count++;
}
}
System.out.println("count:" + count +",for each耗时1:" + (System.currentTimeMillis() - t1));
t1 = System.currentTimeMillis();
count = list.stream().filter(i-> i>4999).count();
System.out.println("count:" + count + ",lamaba耗时2:" + (System.currentTimeMillis() - t1));
执行结果:
count:95000,for each耗时1:7
count:95000,lamaba耗时2:83
这是一个比较常见的例子,传统的iterator和for-each循环性能是比lamaba快5倍的,这个大家可以去测试一下,也比较简单。