Java8 Lambda表达式
简介
函数式接口(Functional Interfaces)
如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。 像这样的接口,可以被隐式转换为lambda表达式。java.lang.Runnable 与 java.util.concurrent.Callable 是函数式接口最典型的两个例子。Java 8增加了一种特殊的注解@FunctionalInterface,但是这个注解通常不是必须的(某些情况建议使用),只要接口只包含一个抽象方法,虚拟机会自动判断该接口为函数式接口。一般建议在接口上使用@FunctionalInterface 注解进行声明,这样的话,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
Lambda表达式
可以让你的代码更加的简洁。Lambda无法单独出现,需要一个函数式接口来盛放,可以说lambda表达式方法体是函数式接口的实现,lambda实例化函数式接口,可以将函数作为方法参数,或者将代码作为数据对待。
主要优点:
1.代码变得更加简洁紧凑
2.可读性强,
3.并行操作大集合变得很方便,可以充分发挥多核cpu的优势,更加便于多核处理器编写代码等,
语法
Lambda语法
(parameters)->expression 或者 (parameters)->{statements;}
Lambda表达式由三部分组成
1.parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断,当只有一个推断类型时可以省略掉圆括号。
2.->:可以理解为“被用于”的意思
3.方法体:可以是表达式也可以是代码块,实现函数式接口中的方法。这个方法体可以有返回值也可以没有返回值
//不接受参数,直接返回1
()->1
//接受两个int类型的参数,返回这两个参数的和
(int x,int y )-> x+y
//接受x,y两个参数,JVM根据上下文推断参数的类型,返回两个参数的和
(x,y)->x+y
//接受一个字符串,打印该字符串,没有返回值
(String name)->System.out.println(name)
//接受一个参数,JVM根据上下文推断参数的类型,打印该参数,没有返回值,只有一个参数可以省略圆括号
name->System.out.prinln(name)
//接受两个String类型参数,分别输出,没有返回值
(String name,String age)->{System.out.println(name);System.out.println(age)}
//接受呀一个参数,返回它本身的2倍
x->2*x
作用域
访问局部变量
可以直接在 lambda 表达式中访问外部的局部变量:
final int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确:
int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
不过这里的 num 必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译:
int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
num = 3;//在lambda表达式中试图修改num同样是不允许的。
访问字段和静态变量
与局部变量相比,我们对lambda表达式中的实例字段和静态变量都有读写访问权限。 该行为和匿名对象是一致的。
class LambdaTest {
static int outerStaticNum;
int outerNum;
void testScopes() {
Converter stringConverter1 = (from) -> {
outerNum = 23;
return String.valueOf(from);
};
Converter stringConverter2 = (from) -> {
outerStaticNum = 72;
return String.valueOf(from);
};
}
}
内置函数式接口
JDK 1.8 API包含许多内置函数式接口。 其中一些借口在老版本的 Java 中是比较常见的比如: Comparator 或Runnable,这些接口都增加了@FunctionalInterface注解以便能用在 lambda 表达式上。
Predicate接口
Predicate 接口是只有一个参数的返回布尔类型值的断言型接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非):
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate {
// 该方法是接受一个传入类型,返回一个布尔值.此方法应用于判断.
boolean test(T t);
//and方法与关系型运算符"&&"相似,两边都成立才返回true
default Predicate and(Predicate other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
// 与关系运算符"!"相似,对判断进行取反
default Predicate negate() {
return (t) -> !test(t);
}
//or方法与关系型运算符"||"相似,两边只要有一个成立就返回true
default Predicate or(Predicate other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}无锡妇科医院排行 http://www.0510bhyy.com/
// 该方法接收一个Object对象,返回一个Predicate类型.此方法用于判断第一个test的方法与第二个test方法相同(equal).
static Predicate isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
//示例
Predicate predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
Predicate nonNull = Objects::nonNull;
Predicate isNull = Objects::isNull;
Predicate isEmpty = String::isEmpty;
Predicate isNotEmpty = isEmpty.negate();
Function接口
Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen)
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function {
//将Function对象应用到输入的参数上,然后返回计算结果。
R apply(T t);
//将两个Function整合,并返回一个能够执行两个Function对象功能的Function对象。
default Function compose(Function before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//
default Function andThen(Function after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static Function identity() {
return t -> t;
}
}
//示例
Function toInteger = Integer::valueOf;
Function backToString = toInteger.andThen(String::valueOf);
backToString.apply("123"); // "123"
Supplier接口
Supplier 接口产生给定泛型类型的结果。 与 Function 接口不同,Supplier 接口不接受参数。
//示例
Supplier personSupplier = Person::new;
personSupplier.get(); // new Person
Consumer接口
Consumer 接口表示要对单个输入参数执行的操作。
//示例
Consumer greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));