lambda表达式出现之前,我们一般使用匿名内部类来实现。
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("内部类写法");
}
}).start();
出现lambda之后的写法:
new Thread(() -> System.out.println("lambda写法")).start();
更加的简洁和优雅。
1、语法使用
(paramters) -> {statements;}
展开如:
(Type1 param1, Type2 param2, Type2 param2, ...) -> {
statement1;
statement2;
statement3;
...
return statementX;
}
2、语法特征
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
//入参为空
Demo dome = () -> "no param";
Demo dome2 = () -> { return "no param"; };
System.out.println(dome.hi());
//单个参数
Demo2 dome21 = p -> p;
Demo2 param22 = p -> { return p;};
System.out.println(dome21.hei("hello word"));
//多个参数
Demo3 more1 = (String hello, String name) -> hello + " " + name;
//一条返回语句,可以省略大括号和return
Demo3 more2 = (hello, name) -> hello + name;
//多条处理语句,需要大括号和return
Demo3 more3 = (hello, name) -> {
System.out.println("come...");
return hello + name;
};
System.out.println(more1.greet("hello", "lambda"));
3、方法引用
3.1 对象::实例方法,将lambda的参数当做方法的参数使用
object::method
例子:
Consumer<String> sc = System.out::println;
//等效
Consumer<String> sc2 = (x) -> System.out.println(x);
sc.accept("618, 狂欢happy");
3.2 类::静态方法,将lambda的参数当做方法的参数使用
Class::staticMethod
例子:
//ClassName::staticMethod 类的静态方法:把表达式的参数值作为staticMethod方法的参数
Function<Integer, String> sf = String::valueOf;
//等效
Function<Integer, String> sf2 = (x) -> String.valueOf(x);
String apply1 = sf.apply(61888);
3.3 类::实例方法,将lambda的第一个参数当做方法的调用者,其他的参数作为方法的参数。开发中尽量少些此类写法,减少后续维护成本。
Class::instanceMethod
例子:
//ClassName::instanceMethod 类的实例方法:把表达式的第一个参数当成instanceMethod的调用者,其他参数作为该方法的参数
BiPredicate<String, String> sbp = String::equals;
//等效
BiPredicate<String, String> sbp2 = (x, y) -> x.equals(y);
boolean test = sbp.test("a", "A");
4、构造函数
类::实例方法
无参例子:
Supplier<User> us = User::new;
//等效
Supplier<User> us2 = () -> new User();
//获取对象
User user = us.get();
有参例子:
//一个参数,参数类型不同则会编译出错
Function<Integer, User> uf = id -> new User(id);
//或加括号
Function<Integer, User> uf2 = (id) -> new User(id);
//等效
Function<Integer, User> uf3 = (Integer id) -> new User(id);
User apply = uf.apply(61888);
//两个参数
BiFunction<Integer, String, User> ubf = (id, name) -> new User(id, name);
User 狂欢happy = ubf.apply(618, "狂欢happy");
5、例子
package lambda;
import org.junit.Test;
public class LambdaTest {
@Test
public void domeTest() {
testVoid(() -> System.out.println("OK"));//传lambda表达式 一个匿名函数对应一个方法
testReturn(Math::random);
testVoid(TestLambda::test);//双冒号 即直接传方法参数 方法必须为静态方法
System.out.println(this.get().invoke(1));
System.out.println(this.get2().invoke(2));
System.out.println(this.get3().invoke(3));
}
private void testVoid(VoidTest voidTest) {
voidTest.test();
}
private void testReturn(ReturnTest returnTest) {
System.out.println(returnTest.test());
}
private Int2String get() {
return Object::toString;
}
private Int2String get2() {
return integer -> {
if (integer % 2 == 0)
return integer + "是偶数";
else
return integer + "是奇数";
};
}
private Int2String get3() {
return this::i2s;
}
private String i2s(Integer s) {
return "i2s: " + s;
}
}
class TestLambda {
static void test() {
System.out.println("a.f");
}
}
@FunctionalInterface
interface ReturnTest{
double test();
}
interface VoidTest {
void test();
}
@FunctionalInterface
public interface Int2String {
String invoke(Integer integer);
}
6、什么式函数式接口
- 只包含一个抽象方法的接口,称为函数式接口
- 可以在任意函数式接口上使用@FunctionalInterface注解,这样可以检查是否是函数式接口,同时javadoc也会包含一条声明,说明这个接口是函数式接口
自定义函数式接口
@FunctionalInterface
public interface CheckMsgNumber4Biz {
OpenApiResult<List<MsgNumber>> check(List<MsgNumber> msgNumberList);
}
7、应用场景
函数接口
/**
* 检查接入号的函数接口
*/
@FunctionalInterface
public interface CheckMsgNumber4Biz {
OpenApiResult<List<MsgNumber>> check(List<MsgNumber> msgNumberList);
}
/**
* 检查接入号,不存在就创建
*
* @param msgNumberInfos 传入的接入号对象集合
* @param customer 租户
* @param checkMsgNumber4Biz 校验接入号函数,根据不同的业务传入不同函数
* @return 可用的号码集合,和不可用的错误信息
*/
public OpenApiResult<List<String>> checkAndSaveMsg(List<MsgNumberInfo> msgNumberInfos,
Customer customer, CheckMsgNumber4Biz checkMsgNumber4Biz) {
//可用号码集合
List<String> usableNumberList = Lists.newArrayList();
//错误信息
List<String> errorMsgList = Lists.newArrayList();
//校验存在
MsgNumberPacker msgNumberPacker = this.groupMsgNumber(msgNumberInfos);
//对存在的接入号做校验
if (CollectionUtils.isNotEmpty(msgNumberPacker.getExistedList())) {
//校验租户是否匹配
OpenApiResult<List<MsgNumber>> matchResult =
this.matchMsgNumberAndCustomer(msgNumberPacker.getExistedList(), customer);
OpenApiResult.appendErrorMsg(errorMsgList, matchResult.getErrorMsg()); //追加错误信息
if (OpenApiResult.isSuccessAndDataNotNull(matchResult)) {
//校验业务合法性
OpenApiResult<List<MsgNumber>> checkMsgNumberResult =
//***********函数是接口校验***********
checkMsgNumber4Biz.check(msgNumberPacker.getExistedList());
//***********函数是接口校验***********
OpenApiResult.appendErrorMsg(errorMsgList, checkMsgNumberResult.getErrorMsg()); //追加错误信息
if (OpenApiResult.isSuccessAndDataNotNull(checkMsgNumberResult)) {
//添加可用号码
usableNumberList.addAll(
checkMsgNumberResult.getData().stream()
.map(MsgNumber::getMsgNumber).collect(Collectors.toList())
);
}
}
}
//创建不存在的接入号
if (CollectionUtils.isNotEmpty(msgNumberPacker.getNeedCreateList())) {
//批量创建
this.saveMsgNumber(msgNumberPacker.getNeedCreateList(), customer);
//添加可用号码
usableNumberList.addAll(msgNumberPacker.getNeedCreateList().stream()
.map(MsgNumberInfo::getMsgNumber).collect(Collectors.toList()));
}
//返回
if (CollectionUtils.isEmpty(usableNumberList)) {
return OpenApiResult.fail(OpenApiResult.Enum.NO_HAVE_USABLE_NUMBER, errorMsgList);
} else {
return OpenApiResult.success(usableNumberList, errorMsgList);
}
}
业务场景1:
@Resource(name = "openApiMsgNumberService")
private OpenApiMsgNumberService openApiMsgNumberService;
/**
* 保存
*
* @param openOrgQO 保存机构入参对象
* @param flag 新增标记
* @return OrgInfo
*/
@Transactional
public OpenApiResult<OrgInfo> save(OpenOrgQO openOrgQO, String flag) {
//检查租户
OpenApiResult<Customer> checkCustomerResult = openApiCustomerService.checkCustomer(openOrgQO.getCustomerId());
if (OpenApiResult.isFail(checkCustomerResult)) {
return OpenApiResult.fail(checkCustomerResult);
}
Customer customer = checkCustomerResult.getData();
//校验机构合法性
OpenApiResult<?> checkOrgBeforeSave = this.checkOrgBeforeSave(openOrgQO);
if (OpenApiResult.isSuccess(checkOrgBeforeSave)) {
//检查、保存接入号
OpenApiResult<List<String>> checkAndSaveMsgResult =
openApiMsgNumberService.checkAndSaveMsg(
openOrgQO.getMsgNumberInfos(), customer,
//*********此为本业务场景函数接口具体逻辑*********
this.getCheckMsgNumber4Biz());
//*********此为本业务场景函数接口具体逻辑*********
if (OpenApiResult.isSuccessAndDataNotNull(checkAndSaveMsgResult)) {
//封装返回
return this.saveOrg(openOrgQO, customer, checkAndSaveMsgResult.getData(), flag)
//追加errorMsg
.appendErrorMsg(checkAndSaveMsgResult.getErrorMsg());
} else {
//失败返回
return OpenApiResult.fail(checkAndSaveMsgResult);
}
} else {
//不合法
return OpenApiResult.fail(checkOrgBeforeSave);
}
}
/**
* 获取校验接入号函数接口实现
* ps:单独抽取出来,以后可能复用。
*
* @return CheckMsgFunction
*/
private CheckMsgNumber4Biz getCheckMsgNumber4Biz() {
return msgNumbers -> {
List<MsgNumber> usableMsgNumberList = Lists.newArrayList(); //可用接入号
List<String> errorMsg = Lists.newArrayList(); //错误信息
for (MsgNumber msgNumber : msgNumbers) {
//是否存在机构
if (msgNumber.getOrgInfo() == null)
//不存在机构,可用
usableMsgNumberList.add(msgNumber);
else
//存在机构,不可用,加入错误信息
errorMsg.add("接入号【" + msgNumber.getMsgNumber() + "】: 已经存在机构,名称【"
+ msgNumber.getOrgInfo().getOrgName() + "】");
}
return OpenApiResult.success(usableMsgNumberList, errorMsg);
};
}
业务场景2:
@Resource(name = "openApiMsgNumberService")
private OpenApiMsgNumberService openApiMsgNumberService;
/**
* 保存菜单
*
* @param openMenuQO 入参对象
* @param flag 操作标记
* @return Menu
*/
private OpenApiResult<Menu> checkAndSaveMenu(OpenMenuQO openMenuQO, String flag) {
//校验租户
OpenApiResult<Customer> checkCustomerResult =
openApiCustomerService.checkCustomer(openMenuQO.getCustomerId());
if (OpenApiResult.isFail(checkCustomerResult)) {
return OpenApiResult.fail(checkCustomerResult);
}
Customer customer = checkCustomerResult.getData();
//校验菜单
OpenApiResult<?> checkMenuBeforeSaveResult = this.checkMenuBeforeSave(openMenuQO);
if (OpenApiResult.isSuccess(checkMenuBeforeSaveResult)) {
//校验、保存接入号
OpenApiResult<List<String>> checkAndSaveMsgResult =
openApiMsgNumberService.checkAndSaveMsg(
openMenuQO.getMsgNumberInfos(), customer,
//*********此为本业务场景函数接口具体逻辑*********
this.getCheckMsgFunction());
//*********此为本业务场景函数接口具体逻辑*********
if (OpenApiResult.isSuccessAndDataNotNull(checkAndSaveMsgResult)) {
//封装返回
return this.saveMenu(openMenuQO, customer, checkAndSaveMsgResult.getData(), flag)
//需要追加的errorMsg
.appendErrorMsg(checkAndSaveMsgResult.getErrorMsg());
} else {
//失败返回
return OpenApiResult.fail(checkAndSaveMsgResult);
}
} else {
return OpenApiResult.fail(checkMenuBeforeSaveResult);
}
}
/**
* 接入号校验函数实现
*
* @return CheckMsgFunction
*/
private CheckMsgNumber4Biz getCheckMsgFunction() {
//后续需要可以添加控制
return OpenApiResult::success;
}
根据以上可以看出,因为在checkAndSaveMsg方法中有检验,但是不同的业务场景的逻辑校验不同,所以可以使用函数式接口。在各自的业务中不同的实现,这样在组件统一调用时会根据不同的业务场景,传入不同的逻辑代码,实现不同的业务逻辑,更加方便快捷。