关键词:
简介
Lambda表达式java 8引入的函数式编程框架。之前的文章中我们也讲过Lambda表达式的基本用法。
本文将会在之前的文章基础上更加详细的讲解Lambda表达式在实际应用中的最佳实践经验。
优先使用标准Functional接口
之前的文章我们讲到了,java在java.util.function包中定义了很多Function接口。基本上涵盖了我们能够想到的各种类型。
假如我们自定义了下面的Functional interface:
@FunctionalInterface
public interface Usage
String method(String string);
然后我们需要在一个test方法中传入该interface:
public String test(String string, Usage usage)
return usage.method(string);
上面我们定义的函数接口需要实现method方法,接收一个String,返回一个String。这样我们完全可以使用Function来代替:
public String test(String string, Function<String, String> fn)
return fn.apply(string);
使用标准接口的好处就是,不要重复造轮子。
使用@FunctionalInterface注解
虽然@FunctionalInterface不是必须的,不使用@FunctionalInterface也可以定义一个Functional Interface。
但是使用@FunctionalInterface可以在违背Functional Interface定义的时候报警。
如果是在维护一个大型项目中,加上@FunctionalInterface注解可以清楚的让其他人了解这个类的作用。
从而使代码更加规范和更加可用。
所以我们需要这样定义:
@FunctionalInterface
public interface Usage
String method(String string);
而不是:
public interface Usage
String method(String string);
在Functional Interfaces中不要滥用Default Methods
Functional Interface是指只有一个未实现的抽象方法的接口。
如果该Interface中有多个方法,则可以使用default关键字为其提供一个默认的实现。
但是我们知道Interface是可以多继承的,一个class可以实现多个Interface。 如果多个Interface中定义了相同的default方法,则会报错。
通常来说default关键字一般用在升级项目中,避免代码报错。
使用Lambda 表达式来实例化Functional Interface
还是上面的例子:
@FunctionalInterface
public interface Usage
String method(String string);
要实例化Usage,我们可以使用new关键词:
Usage usage = new Usage()
@Override
public String method(String string)
return string;
;
但是最好的办法就是用lambda表达式:
Usage usage = parameter -> parameter;
不要重写Functional Interface作为参数的方法
怎么理解呢? 我们看下面两个方法:
public class ProcessorImpl implements Processor
@Override
public String process(Callable<String> c) throws Exception
// implementation details
@Override
public String process(Supplier<String> s)
// implementation details
两个方法的方法名是一样的,只有传入的参数不同。但是两个参数都是Functional Interface,都可以用同样的lambda表达式来表示。
在调用的时候:
String result = processor.process(() -> "test");
因为区别不了到底调用的哪个方法,则会报错。
最好的办法就是将两个方法的名字修改为不同的。
Lambda表达式和内部类是不同的
虽然我们之前讲到使用lambda表达式可以替换内部类。但是两者的作用域范围是不同的。
在内部类中,会创建一个新的作用域范围,在这个作用域范围之内,你可以定义新的变量,并且可以用this引用它。
但是在Lambda表达式中,并没有定义新的作用域范围,如果在Lambda表达式中使用this,则指向的是外部类。
我们举个例子:
private String value = "Outer scope value";
public String scopeExperiment()
Usage usage = new Usage()
String value = "Inner class value";
@Override
public String method(String string)
return this.value;
;
String result = usage.method("");
Usage usageLambda = parameter ->
String value = "Lambda value";
return this.value;
;
String resultLambda = usageLambda.method("");
return "Results: result = " + result +
", resultLambda = " + resultLambda;
上面的例子将会输出“Results: result = Inner class value, resultLambda = Outer scope value”
Lambda Expression尽可能简洁
通常来说一行代码即可。如果你有非常多的逻辑,可以将这些逻辑封装成一个方法,在lambda表达式中调用该方法即可。
因为lambda表达式说到底还是一个表达式,表达式当然越短越好。
java通过类型推断来判断传入的参数类型,所以我们在lambda表达式的参数中尽量不传参数类型,像下面这样:
(a, b) -> a.toLowerCase() + b.toLowerCase();
而不是:
(String a, String b) -> a.toLowerCase() + b.toLowerCase();
如果只有一个参数的时候,不需要带括号:
a -> a.toLowerCase();
而不是:
(a) -> a.toLowerCase();
返回值不需要带return:
a -> a.toLowerCase();
而不是:
a -> return a.toLowerCase();
使用方法引用
为了让lambda表达式更加简洁,在可以使用方法引用的时候,我们可以使用方法引用:
a -> a.toLowerCase();
可以被替换为:
String::toLowerCase;
Effectively Final 变量
如果在lambda表达式中引用了non-final变量,则会报错。
effectively final是什么意思呢?这个是一个近似final的意思。只要一个变量只被赋值一次,那么编译器将会把这个变量看作是effectively final的。
String localVariable = "Local";
Usage usage = parameter ->
localVariable = parameter;
return localVariable;
;
上面的例子中localVariable被赋值了两次,从而不是一个Effectively Final 变量,会编译报错。
为什么要这样设置呢?因为lambda表达式通常会用在并行计算中,当有多个线程同时访问变量的时候Effectively Final 变量可以防止不可以预料的修改。
结论
lambda是一个非常有用的功能,希望小伙伴们能够在工作中掌握。
欢迎关注我的公众号:程序那些事,更多精彩等着您!
更多内容请访问 www.flydean.com
将 lambda 表达式用于事件处理程序的最佳实践
】将lambda表达式用于事件处理程序的最佳实践【英文标题】:Bestpracticesofusinglambdaexpressionsforeventhandlers【发布时间】:2011-03-1523:05:20【问题描述】:在发现lambda表达式及其作为匿名函数的用途后,我发现自己编写了很多更琐碎的... 查看详情
38.lambda表达式实现原理实践(代码片段)
.../自定义操作,优先级队列,智能指针删除器lambda表达式的语法:[捕获变量](形参列表)->返回值操作代码template<typenameT=void>classTestLambda01public: TestLambda01() voidoperator()()co 查看详情
38.lambda表达式实现原理实践(代码片段)
.../自定义操作,优先级队列,智能指针删除器lambda表达式的语法:[捕获变量](形参列表)->返回值操作代码template<typenameT=void>classTestLambda01public: TestLambda01() voidoperator()()co 查看详情
ansible学习笔记04(最佳实践)(代码片段)
...理变量1.1ansiblefilteransible应用变量到playbook并且使用jinja2表达式来使用变量。例如下面的J2表达式中的变量使用两个大括号括起来。J2表达式也支持filter。Filter在playbook或者模板中被用来修改或者处理要替代的变量值。一些filter使... 查看详情
jdk8函数式编程最佳实践
文章导航JDK8函数式编程最佳实践1.Lambda表达式的重要接口1.1新增的函数接口1.1无参数,无返回值类型接口1.2无参数,有返回值类型接口1.3有参数,也有返回值的类型接口2.方法引用2.1静态方法引用2.2实例方法引用2.3构... 查看详情
模拟 AWS 服务和 Lambda 最佳实践
】模拟AWS服务和Lambda最佳实践【英文标题】:MockingAWSservicesandLambdabestpractices【发布时间】:2021-01-1720:47:04【问题描述】:我正在开发一个简单的AWSlambda函数,该函数由DynamoDBStreams事件触发,并且应该将除REMOVE事件之外的所有记... 查看详情
AWS Lambda - 在 CI/CD 管道中版本控制和提升 lambda 的最佳实践是啥
】AWSLambda-在CI/CD管道中版本控制和提升lambda的最佳实践是啥【英文标题】:AWSLambda-WhatisabestpracticeforversioningandpromotinglambdasinCI/CDpipelineAWSLambda-在CI/CD管道中版本控制和提升lambda的最佳实践是什么【发布时间】:2021-01-1501:54:54【问... 查看详情
kotlin学习与实践lambda
对于语言来说Lamda表达式都是轻车熟路的,但是对于Java来说从Java8才引入Lambda,所以这里还是提一下Lambda。而且Kotlin中使用Lambda的确很赞。Lambda表达式简称lambda,本质上就是一段可以传递给其他函数的一小段代码,可以轻松的把... 查看详情
JavaFX:在 UI 屏幕之间导航的最佳实践
...最佳做法?另外,我可以为控制器中的处理程序使用lambda表达式吗?【问题讨论】:请发minimalrepro 查看详情
javascript最佳实践(代码片段)
markdowndevops最佳实践(代码片段)
textlaravel最佳实践(代码片段)
csscss最佳实践(代码片段)
markdownfirebasefirestore最佳实践(代码片段)
textrest最佳实践(代码片段)
es6+最佳入门实践(代码片段)
...s6中我们可以简写成下面的形式varobj=show()alert(1)5.2.属性名表达式属性名表达式意思就是说在es6中可以把属性写成一个表达式的形式,在es5中我们写属性名的时候,都是固定不变的varobj=name:"xiaoqiang",age:19//其中name和age是不... 查看详情