Java8极简手册-02

系列文章链接:

Java8极简手册-01
Java8极简手册-02
Java8极简手册-03
Java8极简手册-04

Lambda的作用域

lambda表达式访问作用域之外变量的方式与匿名对象非常相似。 您可以访问局部方法的外部作用域的final变量,以及实例字段和static变量。

访问局部变量

我们可以访问lambda表达式作用域之外的final局部变量:

1
2
3
4
5
final int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);

stringConverter.convert(2); // 3

需要注意的是,lambda表达式比匿名函数更友好一些,比如,变量num在lambda表达式的应用中就不一定非要声明为final,以下代码依然是有效的:

1
2
3
4
5
int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);

stringConverter.convert(2); // 3

然而变量num必须是隐式的final(即在代码的上下文中,变量num没有给重新赋值,那就意味着和使用final修饰符是一样的效果的),这样代码才能编译, 下面的代码不能编译:

1
2
3
4
int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
num = 3;

在lambda表达式中给num重新赋值也是禁止的。

访问实例字段和static变量

与局部变量相比,我们既可以对lambda表达式中的实例字段和static变量的进行读写访问,这种方式在匿名对象中我们就已经熟知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Lambda4 {
static int outerStaticNum;
int outerNum;

void testScopes() {
Converter<Integer, String> stringConverter1 = (from) -> {
outerNum = 23;
return String.valueOf(from);
};

Converter<Integer, String> stringConverter2 = (from) -> {
outerStaticNum = 72;
return String.valueOf(from);
};
}
}

访问接口的默认方法

还记的01中的方法示例吗? 我们在接口Formula中定义了一个默认方法sqrt,可以从每个Formula的实例中访问它,包括匿名对象。但这方式却不适用于lambda表达式。

默认方法不能在lambda表达式内部被访问(译者:存疑默认方法应该是可以在lambda表达式里面使用的,不知道原作者的意思是怎么样的,原句是:Default methods cannot be accessed from within lambda expressions.),下面的代码是无法通过编译的:

1
Formula formula = (a) -> sqrt(a * 100);

内置函数式接口

JDK 1.8 API包含许多内置的函数式接口,它们中的一些在较早版本的Java中已经被人熟知了,如ComparatorRunnable。 这些现有接口通过@FunctionalInterface注释已被扩展为支持Lambda。

但Java 8 API也引入了一些全新的函数式接口,让我们的码农生涯能更加轻松。 这些新接口中的一些在Google Guava库中是众所周知的, 即使您熟悉这个库,您也应该密切关注这些接口在Java8中的一些用法上的扩展。

Predicates

Predicates是一个判断参数布尔值的函数,该接口包含各种默认方法,用于将谓词组合为复杂的逻辑术语(and,or还有negate)

1
2
3
4
5
6
7
8
9
10
Predicate<String> predicate = (s) -> s.length() > 0;

predicate.test("foo"); // true
predicate.negate().test("foo"); // false

Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;

Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();

Functions

Functions接受一个参数并产生一个结果。 可以使用默认方法将多个函数链接在一起(撰写和然后)。

1
2
3
4
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);

backToString.apply("123"); // "123"

Suppliers

Suppliers提供了一个给定通用类型的结果。 与Functions不同,Suppliers不接受参数。

1
2
Supplier<Person> personSupplier = Person::new;
personSupplier.get(); // new Person

Consumers

Consumers表示要对单个输入参数执行的操作。

1
2
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));

Comparators

Comparators从早期版本的Java中众所周知。 Java 8为接口添加了各种默认方法。

1
2
3
4
5
6
7
Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

comparator.compare(p1, p2); // > 0
comparator.reversed().compare(p1, p2); // < 0