Java基础、中级、高级、架构面试资料

3个丑陋的函数式编程工具方法,干掉了项目里80%的if-else

JAVA herman 15浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog2,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云

Java 8 发布至今已经超过 10 年(2014 年),Lambda 表达式和 Stream API 也早被吹上天,但一个尴尬的现实是:真正熟练掌握并广泛应用函数式编程的 Java 开发者,在企业中仍然是少数派

刚好近一段时间以来,我在 CodeReview 代码的时候,突然脑袋里闪了一下火花,代码中咋有这么多 if 呢?为什么函数式编程还是这么少见呢?

于是呀,我就在想,能不能封装一个函数式编程的工具,来减少 if else 等分支代码。

说干就干,我就尝试着封装了一个简陋的工具类,同事们觉得还挺心仪。所以,本文就简单的来展示一下,我丑陋的封装工具吧。

isBlankAccept

这个是案例一,看下面这个代码。

public void test(User user) {
  // ...
  if(isBlank(user.getName())){
    // doSomething
    wrapper.innerJoin(Order.class, on -> on.eq(Order::getUserId, User::getId)
            .eq(Order::getState, 10));
        wrapper.and(p -> p.like(Order::getAddress, n)
            .or().like(Order::getCode, n)
            .or().like(User::getName, n));
     // doSomething       
  }
  // ... 
}

这里只是举例哈,类似的业务还有很多。比如:自动生成用户名,拼接 SQL 等等。

这样的场景,我觉得可以使用函数式编程来过滤掉外层业务中的一些 if 编码。

FunUtil.isBlankAccept(user.getName, n -> {
  // doSomething
  wrapper.innerJoin(Order.class, on -> on.eq(Order::getUserId, User::getId)
        .eq(Order::getState, 10));
    wrapper.and(p -> p.like(Order::getAddress, n)
        .or().like(Order::getCode, n)
        .or().like(User::getName, n));
  // doSomething    
});

这样业务代码中就少了一个 if,多了一个函数式编程。我们把这个 if 移动到了 FunUtil 工具类了。

public static void isBlankAccept(final CharSequence cs, Consumer<CharSequence> action) {
    if (isBlank(cs)) {
        action.accept(cs);
    }
}

这个工具里的 isBlank 方法,来自于 SpringUtils 或者其它 util,也或者自己实现。isNotBlankAccept 就是反过来而已,如法炮制即可,我就不多讲了。

isTrueRun

这个算案例二。

上面这个方法,从名字就可以看出,它有 isBlank 的特征。如果不是字符串 Blank 判断呢,所以再来一个 isTrueRun、isFalseRun 的方法。

public static void isTrueRun(final boolean flag, Runnable action) {
    if (flag) {
        action.run();
    }
}

如果需要执行的函数需要参数,则调用下面这个方法。

public static <T> void isTrueRun(boolean flag, T t, Consumer<T> action) {
    if (flag) {
        action.accept(t);
    }
}

String name = "业余草";
isTrueRun(FunUtil.isNotBlank(name), name, t -> {
    System.out.println("Processing: " + t);
    // 业务逻辑
});

如果需要两个参数,则可以使用 BiConsumer。

public static <T, U> void isTrueRun(boolean flag, T t, U u, BiConsumer<T, U> action) {
    if (flag) {
        action.accept(t, u);
    }
}

isTrueRun(true, name, wrapper, (t, w) -> {
    w.like(..., t);
});

isTrueRunGet

这个算案例三。

如果是无参数,但需要返回值,则可以使用Supplier<T>

public static <T> T isTrueRunGet(final boolean flag, Supplier<T> action) {
    if (flag) {
        // 执行并返回结果
        return action.get();  
    }
    // 或抛异常,或返回默认值
    return null; 
}

String result = isTrueRunGet(
    FunUtil.isNotBlank(name),
    () -> "Processed: " + name.toUpperCase()
);

如果需要支持默认值,则使用下面这个即可。

public static <T> T isTrueRunGet(final boolean flag, Supplier<T> action, T defaultValue) {
    if (flag) {
        return action.get();
    }
    return defaultValue;
}

String result = isTrueRunGet(
    FunUtil.isNotBlank(name),
    () -> processName(name),
    "默认是业余草"
);

如果需要参数 + 返回值,则可以使用Function<T, R>

public static <T, R> R isTrueRunGet(final boolean flag, T input, Function<T, R> action, R defaultValue) {
    if (flag) {
        return action.apply(input);
    }
    return defaultValue;
}

String result = isTrueRunGet(
    FunUtil.isNotBlank(name),
    name,
    t -> t.trim().toUpperCase(),
    "#业余草"
);

也或者,不要返回 null 而不说明,容易导致 NPE。那么,我建议提供 defaultValue,或者使用 Optional。

public static <T> Optional<T> isTrueRunGet(final boolean flag, Supplier<T> action) {
    if (flag) {
        return Optional.ofNullable(action.get());
    }
    return Optional.empty();
}

// 使用
Optional<String> result = isTrueRunGet(
    FunUtil.isNotBlank(name),
    () -> processName(name)
);
result.ifPresent(System.out::println);

可能有些人会挑刺,你这 isTrueRunGet 等方法里,不还是有 if 吗?

对,我这里重点不是 if,而是函数式编程,如果你真和 if else 过不去了,可以看看我的这篇文章《https://mp.weixin.qq.com/s/SlcV57hHlxs9eF3N9NcS-g》。也或者你使用三元判断,看如下代码。

public static <T> T isTrueRunGet(boolean flag, Supplier<T> action, T defaultValue) {
    return flag ? action.get() : defaultValue;
}

这样大面积使用函数式编程后,代码就更像诗(“屎”)了。

总结

代码是写给人看的,顺便让机器执行。

我这里的重点也不算是移除 if、else,算是函数式编程的推广使用吧。我在使用 AI 的过程中也发现,函数式使用的比例也不高,除非是让 AI 写代码之前进行特殊要求。

我想这可能是因为,函数式编程是一种思维,可不是学几个语法糖就能彻底掌握的

上面只是封装的冰山一角,大家多去动手实践吧。

参考资料

  • https://mp.weixin.qq.com/s/F3JkBdhtqqY5JaCmgSRFZg
  • https://mp.weixin.qq.com/s/eKMXFP5nmDFcN1Bn7-gDCQ
  • https://book.douban.com/subject/25728485
  • https://mp.weixin.qq.com/s/c_aSFyrTwPLeTyLcbA17xQ
  • https://book.douban.com/subject/25912747
  • https://mp.weixin.qq.com/s/PzWIuC4Amy4cxXR0NMF9pw
  • https://mp.weixin.qq.com/s/SlcV57hHlxs9eF3N9NcS-g

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » 3个丑陋的函数式编程工具方法,干掉了项目里80%的if-else