软件开发人员有时就像孩子一样,当看到闪亮的新事物时,就会立刻被吸引。 这是正常的,总的来说,甚至对我们的工作都有益......但是....
当Java从JDK5开始提供注解时,人们开始大量使用它,甚至在不需要的时候任然使用它。 因为它是新功能,使用新功能总是好的。 但是,当某些东西被滥用时,就会带来巨大的问题 - 所以有些开发人员完全对注解不感兴趣,即使有时它确实很有用。
不幸的是,我们还没来得及思考滥用注解给我们带来的副作用,很多公司已经迁移到Java 8,开始大量的使用lambdas:
List<Person> persons = ...;
persons.stream().filter(p -> {
if (p.getGender() == Gender.MALE) {
return true;
}
LocalDate now = LocalDate.now();
Duration age = Duration.between(p.getBirthDate(), now);
Duration adult = Duration.of(18, ChronoUnit.YEARS);
if (age.compareTo(adult) > 0) {
return true;
}
return false;
}).map(p -> p.getFirstName() + " " + p.getLastName())
.collect(Collectors.toList());
这只是一个愚蠢的例子,看到这样的代码让我忍不住想改进它。
首先是将不同的功能封装成方法,并且给方法取一个合适的名字。
public class Person {
// ...
public boolean isMale() {
return getGender() == Gender.MALE;
}
public boolean isAdult(LocalDate when) {
Duration age = Duration.between(birthDate, when);
Duration adult = Duration.of(18, ChronoUnit.YEARS);
return age.compareTo(adult) > 0;
}
}
这个小的重构已经提高了lambda的可读性:
persons.stream().filter(p -> {
if (p.isMale()) {
return true;
}
LocalDate now = LocalDate.now();
if (p.isAdult(now)) {
return true;
}
return false;
}).map(p -> p.getFirstName() + " " + p.getLastName())
.collect(Collectors.toList());
但它还有改进空间。 关于lambda有一个有趣的偏见:他们必须是匿名的。 网上几乎所有的例子都使用匿名的lambdas。 但事实并非如此!
让我们命名我们的lambdas:
// Implementation details
Predicate<Person> isMaleOrAdult = p -> {
if (p.isMale()) {
return true;
}
LocalDate now = LocalDate.now();
if (p.isAdult(now)) {
return true;
}
return false;
};
Function<Person, String> concatenateFirstAndLastName = p -> p.getFirstName() + " " + p.getLastName();
// Core
persons.stream().filter(isMaleOrAdult).map(concatenateFirstAndLastName)
没有什么特别的,只是给我们的lambdas取了一个名字。 然而代码的可读性更强了,而不是隐藏在具体的实现中,通过名字,你可以一眼看出他要实现的功能。
工具仅仅是工具,Lambda只是Java开发人员工具箱中的一个,如何正确的使用工具才是应该永远关注的话题。