您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

浅析Java中函数式编程、匿名函数和泛型

时间:2023-09-10 12:03:44  来源:  作者:Java学研大本营

使用函数式编程可以减少代码重复,使代码更易于理解。

JAVA编程语言以其面向对象的特性而闻名,但也因其冗长和繁琐的异常处理机制而而广受批评。当Java语言在1.8版本引入函数式编程能力时,人们并没有马上理解到这如何给程序员提供帮助。

图片

本文给大家讲解一个示例,以说明函数式编程如何提高代码的重用性和可读性。

1 问题

为了实现功能,第三方编写的通信客户端使用了依赖注入和注释。然而,该客户端存在一些问题,例如抛出已检查异常、缺乏日志记录和重试能力。因此,我们需要对该客户端的功能进行封装,以添加重试功能、日志记录和良好的异常处理。

如果没有函数式编程,那么程序需要创建一个外观,将每个客户端功能都包装在委托中,并添加日志记录、异常处理和通信重试的逻辑。客户端共有50个需要封装的函数,这将导致几乎完全相同的50个副本的代码,仅有调用的客户端函数和传递的数据类型有所不同。这样会带来大量的重复代码问题。

为了解决这个问题,要使用函数式编程的方式对该客户端功能进行封装,以实现重试能力、日志记录和良好的异常处理。

2 使用函数式编程解决问题

解决方案是添加1或2个专门用于处理异常、执行日志记录和实现重试循环的方法。但是,它们需要调用通信客户端中的特定函数。

使用函数式编程,方法可以将函数作为其参数接收。该方法不需要在设计时知道哪个函数。Java(因为这与其他编程语言不同)所要求的是函数具有预期的签名。

在我们的情况下,我们需要2种变体:BiFunction签名和BiConsumer签名。区别在于BiFunction返回一个值,而BiConsumer则不返回。

2.1 示例代码:委托

public final ActionResult<List<Order>>
    downloadOrders() {
    return get(
      ".downloadOrders()",
      (
        client,
        apiKey
      ) -> client.downloadOrders(apiKey.toString())
    );
  }

上面的示例没有显示错误处理、日志记录和重试循环。这是由get(String, BiFunction)方法执行的。因此,我们不需要50个重复的错误处理、日志记录和重试循环,而是有50个易于理解的委托。

get(String, BiFunction)方法回调传入的BiFunction,我们在上面看到了这一点:

(    
  client,
  apiKey
) -> client.downloadOrders(apiKey.toString())

我们可能会从JavaScript中认识到这一点。语法是一个BiFunction的lambda表示法:它接受2个参数,可能做一些事情,并返回一些东西。它是一个回调函数,根据需要即时创建,并且因为它没有名称,所以它保持匿名(并由编译器分配标识)。它的参数client和apiKey在方法get(String, BiFunction)内生成,并在运行时传回回调函数中。它看起来像这样:

2.2 示例代码:接受函数作为参数的包装器

private final <T>
    ActionResult<T>
    get(
      final String caller,
      final BiFunction<
        Client,
        ApiKey,
        T
      > callback
    ) {
    final Client client = Client.newInstance(caller);
    final ApiKey key = this.getKey();
    final MutableList<Exception> errors = Lists.mutable.empty();
    boolean mustRetry = true;
    for (
      int retryCount = 0;
      mustRetry && retryCount < MAX_RETRIES;
      retryCount += 1
    ) {
      try {
        return new ActionResult<T>(
          callback.Apply(
            client,
            apiKey
          )
        ).with(errors);
      } catch (Exception ex) {
        mustRetry = mustRetry(ex);
        if (mustRetry) {
          try {
            TimeUnit.SECONDS.wAIt(1 << (retryCount + 1));
          } catch (InterruptedException ie) {
            errors.add(ie);
          }
        } else {
          errors.add(ex);
        }
      }
    }
    return ActionResult.<T>empty()
      .with(errors);
  }

在那段代码中,BiFunction通过声明进行回调:

callback.apply(
  client,
  apiKey
)

请注意,get(String, BiFunction)不知道回调返回的数据类型。在像Java这样的强类型和显式类型编程语言中,通常不可能。直到泛型引入Java编程语言之前,这是不可能的。这就是为什么代码中存在:它是回调返回的数据类型的占位符。

请注意,调用站点也没有指定返回值的数据类型。相反,它由客户端函数的返回值和委托上指定的返回数据类型隐含。如果它们不匹配,编译器将发出警告,保持数据类型良好且检查过。

3 总结

  • 坏的抽象是面向对象编程中许多问题的根源。我们希望将目前的两个异常处理和重试循环包装器减少到一个包装器,但是由于一个接受BiFunction回调,另一个接受BiConsumer回调,还没有找到合适的方法。因为从概念上讲,它们执行不同的操作:发送和接收。使用相同的包装器可能会破坏这种概念上的区别。总之,对于现在来说值得高兴的是避免了重复使用50个包装器的情况。

  • 当然,有些优秀的编译器可能会检测到代码重复,并采取一些技巧将它们减少为具有不同回调的单个包装器。然而,这并非我们当前关注的重点。我们的目标是消除重复代码并提高代码的可读性。

  • 从理论上讲,使用这个包装器和函数委托可能会导致程序变慢。然而,根据经验,由于与远程通信伙伴进行通信时遇到的网络延迟,潜在的几毫秒延迟相对微不足道。尽管如此,如果在您的环境中这导致了明显的性能下降,请测量吞吐量并进行相应的调整。

  • 静态代码分析工具若能提供有关消除重复代码的建议,将对代码优化非常有益。这样的工具可以帮助开发人员识别和消除重复的代码段,从而提高代码的可读性、可维护性和性能。



Tags:函数式编程   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除。
▌相关推荐
使用函数式编程可以减少代码重复,使代码更易于理解。Java编程语言以其面向对象的特性而闻名,但也因其冗长和繁琐的异常处理机制而而广受批评。当Java语言在1.8版本引入函数式...【详细内容】
2023-09-10  Tags: 函数式编程  点击:(0)  评论:(0)  加入收藏
概述背景函数式编程的理论基础是阿隆佐&middot;丘奇(Alonzo Church)于1930 年代提出的 &lambda; 演算(Lambda Calculus)。&lambda; 演算是一种形式系统,用于研究函数定义、函数应...【详细内容】
2023-04-06  Tags: 函数式编程  点击:(150)  评论:(0)  加入收藏
开始切入正题之前,有必要告知大家一下,这篇文章可能有一些深度,初学者可能理解会有些吃力。我会尽量把复杂问题简单化,争取让每个阅读的童鞋们都能看得懂。希望你对element-ui,vu...【详细内容】
2022-03-16  Tags: 函数式编程  点击:(265)  评论:(0)  加入收藏
函数式编程已经存在了60多年,但是到目前为止,它一直都很小众。只有像Google这样的改变游戏规则的企业才会依赖函数式编程,普通程序员对此几乎一无所知。 这种情况很快就要被改...【详细内容】
2020-11-05  Tags: 函数式编程  点击:(157)  评论:(0)  加入收藏
JavaScript是一种发展迅速的语言。这篇文章,我想展示一些有关如何在JavaScript中应用函数式编程的示例。JavaScript中的函数式编程即使函数式编程可以极大地改善应用程序的代...【详细内容】
2020-06-09  Tags: 函数式编程  点击:(172)  评论:(0)  加入收藏
函数式编程或者函数程序设计,又称泛函数编程,是一种编程范式。在Python中,函数编程主要有以下4个函数的使用构成:lambda()、map()、reduce()、filter(),下面我们来一一讲解这些...【详细内容】
2020-04-16  Tags: 函数式编程  点击:(223)  评论:(0)  加入收藏
为什么函数式编程正在上升 编程范例是一个术语,用于描述编写命令的方法。 语言的真正思想是建立在其编程范例之上的。 最著名的三种范例是面向对象的程序设计,命令式程序设计...【详细内容】
2020-03-11  Tags: 函数式编程  点击:(440)  评论:(0)  加入收藏
函数式编程在前端已经成为了一个非常热门的话题。在最近几年里,我们看到非常多的应用程序代码库里大量使用着函数式编程思想。...【详细内容】
2019-09-24  Tags: 函数式编程  点击:(479)  评论:(0)  加入收藏
前置内容为了更容易理解闭包,在说闭包之前,讲一下两个概念:作用域和嵌套函数。 作用域作用域是变量能被访问的范围,定义在函数内的变量是局部变量,局部变量的作用范围只能在函数...【详细内容】
2019-07-17  Tags: 函数式编程  点击:(740)  评论:(0)  加入收藏
▌简易百科推荐
使用函数式编程可以减少代码重复,使代码更易于理解。Java编程语言以其面向对象的特性而闻名,但也因其冗长和繁琐的异常处理机制而而广受批评。当Java语言在1.8版本引入函数式...【详细内容】
2023-09-10  Java学研大本营    Tags:函数式编程   点击:(0)  评论:(0)  加入收藏
本文翻译自国外论坛 medium,原文地址:https://medium.com/@AlexanderObregon/maven-best-practices-tips-and-tricks-for-java-developers-438eca03f72bMaven 简介Maven 是一...【详细内容】
2023-09-09  waynblog  微信公众号  Tags:Maven   点击:(3)  评论:(0)  加入收藏
在数据处理和分析过程中,数据去重是一个常见的需求。Java开发者可以使用MySQL数据库提供的丰富功能和优化技术来实现高效的数据去重。下面将介绍Java开发者如何利用MySQL数据...【详细内容】
2023-09-07  编程技术汇  今日头条  Tags:MySQL   点击:(8)  评论:(0)  加入收藏
优雅处理Java与MySQL的并发访问冲突是开发分布式系统时需要考虑的重要问题。在多个线程或多个应用同时对MySQL数据库进行读写操作时,可能会出现数据一致性问题和性能问题。为...【详细内容】
2023-09-07  编程技术汇  今日头条  Tags:Java   点击:(8)  评论:(0)  加入收藏
Java Reflection 是一种强大的机制,允许开发人员在运行时动态地操作和扩展对象。它提供了许多功能,如获取类的信息、创建对象、调用方法、获取和设置字段的值等。在某些场景下...【详细内容】
2023-09-06  编程技术汇  今日头条  Tags:Java Reflection   点击:(21)  评论:(0)  加入收藏
来源 | OSCHINA 社区作者 | 抽刀断水-鹰影原文链接:https://my.oschina.net/u/3276866/blog/10091251背景在 java 开发中我们经常会遇到这样的场景,代码需要在服务器上(测试或...【详细内容】
2023-09-06  OSC开源社区    Tags:Java   点击:(9)  评论:(0)  加入收藏
aviator本来是一个轻量级、高性能的基于JVM的表达式引擎。不过从5.0.0版本开始,aviator升级成为了aviatorScript,成为一个高性能、轻量级寄宿于 JVM (包括 Android 平台)之上的...【详细内容】
2023-09-05  码猿技术专栏  微信公众号  Tags:Java   点击:(29)  评论:(0)  加入收藏
我们知道对于 Java 应用可以通过 OpenTelemetry 提供的 Java agent 来实现自动埋点功能,在大多数场景下也完全足够了,但是有时候我们需要更加精细的控制,这时候我们就需要使用...【详细内容】
2023-09-05  k8s技术圈  微信公众号  Tags:Java   点击:(24)  评论:(0)  加入收藏
作者 | 蔡柱梁审校 | 重楼一、前言很多 Java 开发一般都是做中台较多,并发编程使用的不多。因此,对 ThreadLocal 不太熟悉,所以笔者这里想让大家了解它,知道它是用来干什么的。...【详细内容】
2023-09-04    51CTO  Tags:ThreadLocal   点击:(26)  评论:(0)  加入收藏
在Java编程中,条件判断是必不可少的一部分。为了实现简洁而高效的条件判断,Java提供了三元表达式(Ternary Expression)。下面将详细介绍Java三元表达式的语法、用法以及优势,并...【详细内容】
2023-09-03  编程技术汇  今日头条  Tags:Java   点击:(20)  评论:(0)  加入收藏
站内最新
站内热门
站内头条