【问题标题】:static methods make Java a pseudo functional language?静态方法使 Java 成为一种伪函数语言?
【发布时间】:2010-10-09 18:14:26
【问题描述】:

我一直在考虑 Misko Hevery 的 post,即 Java 中的静态方法是可测试性的死亡。我不想讨论可测试性问题,而是更多关于静态方法的概念。为什么人们这么讨厌它?

确实,我们没有闭包(但我们有一个有点尴尬的匿名函数)、lambdas 和函数作为第一类对象。在某种程度上,我认为静态方法可以用来模仿函数作为第一类对象。

【问题讨论】:

  • 我认为您将功能与程序混淆了。一个常见错误。
  • Java 没有匿名函数,你可能会想到匿名类。事实上,Java 根本没有函数……只有方法 ;-)

标签: java closures functional-programming


【解决方案1】:

静态方法使测试变得困难,因为它们无法被替换,就这么简单。

静态方法如何“模仿”类对象的功能1?可以说,他们在这方面比其他任何事情都要糟糕。您可以通过创建单方法接口将函数“模仿”为第一类对象,实际上 Google 的 Java 集合在许多地方(用于谓词、投影等)都做到了这一点。这不能用静态方法来完成——没有办法(除了反射)来传递“当你想应用一个函数时,使用 this 方法。

不,我看不出静态方法在这里有什么帮助。它们不鼓励状态更改(因为唯一可用的状态是全局状态和通过参数传入的任何可变状态),但它们在“作为第一类对象的功能”方面没有帮助。

C# 对此有更好的 支持(使用 lambda 表达式和委托),但即使这样也没有想象中的那么普遍。 (例如,将其与 F# 进行比较。)


1 从 Java 8 开始,方法引用将允许将方法转换为适当的单方法接口的实例,这将使所有这些更加相关。不过,早在 2009 年,那还很遥远……

【讨论】:

  • 您为什么要替换测试方法?我想测试方法而不是替代方法!
  • 如果该方法发送到对面 hemishpere 的网络服务器,而您并不真正想要这样,因为您最好使用静态模拟数据。
  • +1 对安东的评论。如果您无法替换您的依赖项,您的“单元”测试将测试这些依赖项以及它们真正尝试测试的方法。
【解决方案2】:

函数式编程的一个特点是数据的不变性。 static 确实暗示您不需要表示状态的对象(实例),所以这不是一个糟糕的开始。但是,您确实在班级级别上有状态,但是您可以将其设为final。由于(静态)方法根本不是一等函数,您仍然需要像匿名类这样丑陋的构造来处理 Java 中某种风格的函数式编程。

FP 最好用函数式语言完成,因为它具有必要的语言支持,例如高阶函数、不变性、引用透明性等。

但是,这并不意味着您不能使用 Java 等命令式语言以函数式风格进行编程。也可以给出其他示例。不是因为你在用 Java 编程,所以你在做 OOP。您可以使用 C++ 等结构化语言使用全局数据和非结构化控制流 (goto) 进行编程。我可以用像 Scheme 这样的函数式语言来做 OOP。等等。

Steve McConnell 提到了在 Code Complete 中编程与将语言编程的区别(也是关于 SO 的一个非常流行的参考资料)。

所以,简而言之,如果你说“静态方法模仿一流的函数”,我不同意。

但是,如果我认为这更符合您想要表达的观点,您会说“静态方法有助于在 Java 中进行函数式编程”,我同意。

【讨论】:

    【解决方案3】:

    Functional != function,为了记录,我将声明一个方法!= function...

    Java 是一种静态类型的面向对象的语言。 Java 也以这种方式保持了相对的纯洁性,但它与函数式语言相去甚远。

    虽然您确实可以使用命令式编程来模仿函数式编程的行为,但您永远无法获得 lambda 演算所需的整洁语法。在某种程度上,如果该语言不支持正确的 lambda 演算,它就不是一种函数式编程语言。

    C++ 有函数,但 C++ 也有类。因此,C++ 有两种类型的函数,成员函数和函数。当您说方法时,您的意思是成员函数。因为该方法是在对象的实例上调用的。但是当你说静态方法时,你的意思只是函数(在 C/C++ 意义上)。这只是一个用于引用代码元素的词汇表。并且在Java代码中不能存在于类之外,方法会暗示它属于某个类,即类型。

    到目前为止,我所说的与函数式编程无关,但我认为你明白了你错的地方。

    我建议您查看纯函数式编程语言,例如 Haskell 或 Erlang。因为函数式编程语言通常也没有关闭器。

    您声称可以使用静态方法将函数模拟为一流的对象,这对我来说听起来很奇怪。这听起来更像是一种动态编程语言,而不是函数式编程。

    【讨论】:

      【解决方案4】:

      我对静态方法的最大反对意见是它们不是多态的,并且它们不是以面向对象的方式使用的,而是必须让您使用类(而不是对象)来访问它们。

      【讨论】:

        【解决方案5】:

        如果您只使用静态方法,那么您就是在以程序化、非面向对象的风格进行编程。

        但是,我能想到的唯一可行的情况是在引入面向对象之前的第一堂编程课程中。

        【讨论】:

          【解决方案6】:

          在 Java 中,您不能将一个函数作为另一个函数的参数。

          在函数式语言中,如果你有一个函数

          def addOne(i) = i + 1
          

          您可以将其传递给另一个函数,例如将其应用于列表的所有元素。

          在 Java 中,使用

          public static int addOne(int i) { return i + 1; }
          

          没有办法做到这一点。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-01-17
            • 2010-09-13
            • 2011-04-11
            • 2021-12-27
            • 2014-11-04
            • 2011-01-04
            • 1970-01-01
            相关资源
            最近更新 更多