Java lambda表达式除了保存代码行之外还有其他用途吗?
lambda表达式除了保存代码行之外还有其他用途吗 lambdas是否提供了解决不容易解决的问题的特殊功能?我看到的典型用法是,不写以下内容:Java lambda表达式除了保存代码行之外还有其他用途吗?,java,lambda,java-8,Java,Lambda,Java 8,lambda表达式除了保存代码行之外还有其他用途吗 lambdas是否提供了解决不容易解决的问题的特殊功能?我看到的典型用法是,不写以下内容: Comparator<Developer> byName = new Comparator<Developer>() { @Override public int compare(Developer o1, Developer o2) { return o1.getName().compareTo(o2.getNa
Comparator<Developer> byName = new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
};
比较器byName=新比较器(){
@凌驾
公共整数比较(开发者o1、开发者o2){
返回o1.getName().compareTo(o2.getName());
}
};
我们可以使用lambda表达式来缩短代码:
Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());
比较器名称=
(开发者o1,开发者o2)->o1.getName().compareTo(o2.getName());
是的,有很多优点
- 不需要定义整个类,我们可以将函数的实现传递给它本身作为参考。
- 类的内部创建将创建.class文件,而如果使用lambda,则编译器将避免创建类,因为在lambda中传递的是函数实现而不是类
- 代码可重用性比以前更高
- 正如您所说,代码比正常实现要短
Stream
管道的可读性将大大降低
例如,想象一下,如果用匿名类实例替换每个lambda表达式,下面的流管道会是什么样子
List<String> names =
people.stream()
.filter(p -> p.getAge() > 21)
.map(p -> p.getName())
.sorted((n1,n2) -> n1.compareToIgnoreCase(n2))
.collect(Collectors.toList());
列出名称=
people.stream()
.filter(p->p.getAge()>21)
.map(p->p.getName())
.已排序((n1,n2)->n1.比较信号案例(n2))
.collect(Collectors.toList());
它将是:
List<String> names =
people.stream()
.filter(new Predicate<Person>() {
@Override
public boolean test(Person p) {
return p.getAge() > 21;
}
})
.map(new Function<Person,String>() {
@Override
public String apply(Person p) {
return p.getName();
}
})
.sorted(new Comparator<String>() {
@Override
public int compare(String n1, String n2) {
return n1.compareToIgnoreCase(n2);
}
})
.collect(Collectors.toList());
列出名称=
people.stream()
.filter(新谓词(){
@凌驾
公共布尔测试(p人){
返回p.getAge()>21;
}
})
.map(新函数(){
@凌驾
公共字符串应用(个人p){
返回p.getName();
}
})
.sorted(新的比较器(){
@凌驾
公共整数比较(字符串n1、字符串n2){
返回n1.比较信号案例(n2);
}
})
.collect(Collectors.toList());
这比使用lambda表达式的版本更难编写,而且更容易出错。这也更难理解
这是一条相对较短的管道
要使其在没有lambda表达式和方法引用的情况下可读,您必须定义包含此处使用的各种函数接口实例的变量,这将分割管道的逻辑,使其更难理解。lambda只是匿名类的语法糖
在lambdas之前,匿名类可以用来实现同样的功能。每个lambda表达式都可以转换为匿名类
如果您使用IntelliJ IDEA,它可以为您进行转换:
- 将光标放在lambda中
- 按alt/option+enter
内部迭代
在迭代Java集合时,大多数开发人员倾向于获取一个元素,然后处理它。也就是说,取出该项,然后使用它,或者重新插入它,等等。对于8之前版本的Java,您可以实现一个内部类并执行以下操作:
numbers.forEach(new Consumer<Integer>() {
public void accept(Integer value) {
System.out.println(value);
}
});
或者更好
numbers.forEach(System.out::println);
作为论据的行为
猜猜下面的例子:
public int sumAllEven(List<Integer> numbers) {
int total = 0;
for (int number : numbers) {
if (number % 2 == 0) {
total += number;
}
}
return total;
}
来源:为了回答您的问题,事实上,lambdas不允许您做在java-8之前无法做的事情,相反,它可以让您编写更简洁的代码。这样做的好处是,您的代码将更清晰、更灵活。Lambda表达式不会改变您通常可以用Java解决的问题集,但肯定会使解决某些问题更容易,这与我们不再使用汇编语言编程的原因相同。从程序员的工作中删除多余的任务会使生活变得更轻松,并允许您做一些您甚至不会去做的事情,只需要您(手动)生成的代码量即可
但是lambda表达式不仅仅是保存代码行。Lambda表达式允许您定义函数,在此之前,您可以使用匿名内部类作为解决方法,这就是为什么在这些情况下可以替换匿名内部类,但通常不能
最值得注意的是,lambda表达式是独立于它们将被转换到的函数接口定义的,因此它们没有可以访问的继承成员,而且,它们不能访问实现函数接口的类型的实例。在lambda表达式中,this
和super
与周围上下文中的含义相同,另请参见。此外,您不能创建新的局部变量来隐藏周围上下文的局部变量。对于定义函数的预期任务,这将删除许多错误源,但也意味着对于其他用例,可能存在无法转换为lambda表达式的匿名内部类,即使实现函数接口也是如此
此外,构造new Type(){…}
保证生成一个新的不同实例(就像new
总是做的那样)。如果在非
静态
上下文中创建,匿名内部类实例始终保留对其外部实例的引用。相反,lambda表达式仅在需要时捕获对此
的引用,即如果它们访问此
或非静态
成员。它们还生成故意未指定标识的实例,这允许实现决定
public int sumAllEven(List<Integer> numbers) {
int total = 0;
for (int number : numbers) {
if (number % 2 == 0) {
total += number;
}
}
return total;
}
public int sumAll(List<Integer> numbers, Predicate<Integer> p) {
int total = 0;
for (int number : numbers) {
if (p.test(number)) {
total += number;
}
}
return total;
}
sumAll(numbers, n -> n % 2 == 0);
// v--- create the lambda locally.
Consumer<Integer> action = (Consumer<Integer> & Serializable) it -> {/*TODO*/};
Function<IntUnaryOperator, IntUnaryOperator> twice = f -> f.andThen(f);
IntUnaryOperator plusThree = i -> i + 3;
var g = twice.apply(plusThree);
System.out.println(g.applyAsInt(7))
Predicate<String> startsWithA = (text) -> text.startsWith("A");
Predicate<String> endsWithX = (text) -> text.endsWith("x");
Predicate<String> startsWithAAndEndsWithX =
(text) -> startsWithA.test(text) && endsWithX.test(text);
String input = "A hardworking person must relax";
boolean result = startsWithAAndEndsWithX.test(input);
System.out.println(result);