Java是否可以进行函数式编程?[关闭]


42

我浏览了Amazon.com书店,发现了“ Java开发人员的功能编程”一书

我知道一些非常基本的函数式编程,并且已经使用Java编程了3年。

我想知道在Java中甚至可以进行函数式编程吗?


2
给定Java的语法,这种样式是可能的,但是它的冗长程度可能太过分了:functionaljava.org
Yuriy Zubarev

7
@nCdy为什么要检查JRuby?请提供更多说明。
Chiron

1
check groovy :-)
Ant的

6
我认为这是引起Java语言和Java平台之间区别的一种问题。
Thomas Owens

2
@ThorbjørnRavnAndersen:是什么让您认为“函数式编程”是由“惰性评估”定义的?这似乎是一个奇怪的例子……
约翰·巴塞洛缪

Answers:


70

这取决于“功能编程”和“可能”的含义。

显然,您可以按照功能范例来实现事情。但是Java语言没有为其提供语法糖,因此某些事情充其量是乏味的,而另一些则极其神秘。

同样,您可以很好地用公认的非OO语言(例如C)编写面向对象的代码。

Java库

有一些库可以帮助您做到这一点,它们已经为您完成了繁琐的工作并隐藏了神秘的事物:

这些将使您能够使用功能更强大的方法以及可能更熟悉的语法和语义来编写Java代码,这正是FP功能语言所期望的。在合理的范围内。

JVM语言

显然,您可以在Java之上实现一种功能语言。这样您就可以将其用作FP语言。这是比您所要求的更高的抽象级别,但相对而言是在上下文中进行的(尽管我在这里作弊了,理所当然)。

例如,签出:

或多或少的功能性JVM语言

尽管它们可能并不是您真正想要的,但还有许多其他语言已移植到Java平台,这些语言可能使您摆脱Java相对不那么有趣的(是的,是双关语)的本质,并且已经为您提供了更多灵活性。诸如JRubyJythonRhino(分别针对RubyPythonJavaScript / ECMAScript)的著名竞争者也为函数式编程提供了有趣的潜力,尽管它们在本质上并不是真正的函数式编程语言。JetBrains的科特林,虽然清楚地承认它不是一种功能语言,但它确实支持某些功能构造,也值得一看。

进一步阅读

您可能还想阅读或观看以下文章或视频:


2
Clojure源代码现在托管在Github上github.com/clojure/clojure
Chiron

@ 1982年的传奇:我比您的评论要快,我已经更改了指向clojure.org官方网站的链接:)但是,感谢您如此快地被接受!很高兴看到人们反应迅速。
Haylem 2011年

也有ABCLcommon-lisp.net/project/armedbear),但我不知道它在成熟/不成熟的范围内是什么,它是Common Lisp的实现。
Vatine 2012年

@Vatine:有趣,绝对没听说过。快速浏览并添加它。
Haylem 2012年

1
我喜欢Alan Perlis的“ Turing Tarpit”一词,因为它试图做一种语言可以做的事情(因为它已经完成了),但是只有这样的痛苦和复杂性,我们不应该尝试。
itsbruce 2012年

11

我正在读你提到的书。BTW真的很好。

是的,可以在Java中起作用。我不知道可以达到什么程度,但是可以实现许多功能编程习惯用法。

最重要的事情之一就是尝试以“不要改变状态”的心态进行编码。

例如,您使用final关键字来实现不变性。如果要使用数据结构,则应使用不可变的数据结构进行编码。Google Guava库已在执行此操作。

同样对于并发编程,您可以依赖Akka框架(参与者模型)。

值得一提的是,JVM字节码不支持(至少还不支持)尾调用优化,这对于函数式编程语言而言是非常重要的功能。


“值得一提的是,JVM字节码不(至少还)不支持尾部调用优化,这对于函数式编程语言而言是非常重要的功能。”:您的意思是?Scala具有TCO。
乔治(Giorgio)2012年

@ Giorgio:Scala在编译时执行TCO。
scrwtp

@scrwtp:是否因此而导致性能下降?还是编译时TCO的缺点是什么?
Giorgio 2013年

@Giorgio:我的意思是Java字节码本身不支持它,就像Chiron最初所说的那样。功能性语言可以解决此问题,将尾递归调用编译到循环中,但这是language-> bytecode编译器(而非JVM)的功能。
scrwtp

@scrwtp:Chiron的回答指出:“值得一提的是,JVM字节码不支持(至少到目前为止)尾部调用优化,这对函数式编程语言来说是非常重要的功能。” 这听起来像是在JVM上对功能语言的实现受到了惩罚,但是(我们似乎对此表示同意)并非如此,因为可以在编译后的代码中模拟尾部调用优化。因此,我同意Chiron的说法,但我觉得这有点误导。
Giorgio

6

是的,绝对有可能,就像在任何图灵完整的语言/执行环境组合中一样。如果您知道自己在做什么,甚至可以使其表现良好。

不知道这有多明智。特别要注意的是,它并不是特别习惯(例如,它看起来很奇怪,您将不得不做一些非常规的事情,并使习惯于常规Java的人感到困惑)

您将得到一些看起来很奇怪的代码,例如,定义一个新函数:

Function twoStrings=new Function() {
  public Object apply(Object param1) {
    // do something to param1 and return a result
  }
}

要进行函数式编程,通常需要:

  • 一流的函数 -通过定义代表您的“函数”的抽象类或接口并具有将函数应用于一个或多个参数的“应用”方法,可以轻松地用Java创建。
  • 闭包 -使用存储在final字段中的闭包值在上方创建函数对象的实例。您可以为此使用匿名内部类。
  • 标准的高阶函数库 -这比较棘手,但是您仍然可以编写自己的代码,以在几个小时内引导一种简单的函数式语言。如果您需要更高级的工具,可以查看人们使用Java内置的其他功能库。

因此,有可能将其作为一项练习,甚至是一个有趣的爱好项目。但是,您真的想做认真的函数式编程,同时又要保持JVM的优势/访问Java库,那么我认为Clojure是迄今为止最好的选择。

ps因为Clojure的核心实际上是用Java编写的,所以它实际上是一个非常有趣的案例示例,说明了如何在Java中进行函数式编程,同时又将复杂的细节隐藏在一种不错的新现代语言语法后面。感兴趣的人可以在GitHub上找到Clojure源代码


有趣的是,我注意到IntelliJ IDEA的最新版本会将这些匿名的折叠成更紧凑的形式,以便在编辑器中显示。做一个漂亮的工作来隐藏多余的东西。当然,这一切都无关紧要来的Java 8
本·哈迪

4

在Java中可能有些功能。这样做非常痛苦。代替

myList.each { doSomething(it); }

你有类似的东西:

myList.each(new Function() { public void do(Object arg) { something(); }})

而且,如果您要使用闭包和函数作为一流的对象进行真正的函数式编程,请选择另一种语言。Scala,Clojure,Groovy都在JVM上运行,并且可以与旧版Java类进行交互。。


函数式编程与使用块而不是匿名类无关。Java 8将具有块,因此您发布的代码将看起来更优雅,但不会成为函数式编程。
凯龙(Chiron)

@Legend:我理解这一点,但是显然并不能很好地解释它。
凯文·克莱恩

这是监督/监督。使用任何语言,您都必须实际定义函数SOMEWHERE,您不能跳过该部分。因此,Java几乎是简明扼要的,您所要做的就是使Function对象匿名。您可以这样做:Function f = new Function(){public void do(){}}; ....然后...调用该函数。...myMethodToCallAFunction(Function f){f.do()} ...就是这样,兄弟和布朗尼。处理它。
2014年

3

答案是肯定的,当然,但是在我看来,许多功能语言中最重要的功能之一就是出色的类型系统。您将永远无法用Java自己管理它。

如果您想编写功能性程序但仍然使用JVM,我可以建议通常的嫌疑人Scala和Clojure查看一下Frege。Frege的语法和类型系统与Haskell非常相似,但是程序直接转换为Java代码,并且可以与其他Java代码进行交互。


2

好吧,各种各样的事情都是可能的。可以用C语言进行面向对象的编程。这不是一个好主意。

Java不是为FP设计的,因此,如果您尝试以纯FP样式进行所有操作,都会遇到问题。您将与语言作斗争,而不是使用语言。不仅是语言,还有所有精彩的免费Java库。因此,不要选择纯FP。采纳FP背后的一些想法并将它们集成到您的Java代码中,但要了解您不能对所有想法做到这一点。


0

OpenJDK团队鼓励您下载其最新的OpenJDK 8二进制文件,并试用Collections API中引入的新lambda表达式和新功能惯用法(以及其他功能)。您可以采用清晰的功能样式进行编程。请参见“使用Java进行功能编程?” 与以前的Java8库(例如Guava,FunctionalJava和LambdaJ)进行JDK8 Collections比较。


-3

似乎有可能,但它不是纯函数式编程。这可能会导致命令式编程。

毫无疑问,他为什么要提到海勒姆提到的可能的函数式编程。这里是:

这取决于“功能编程”和“可能”的含义。

函数式编程虽然有很多解释,但不能有不同的定义或含义。
像OOP一样,我们可以问“ OOP是什么意思?”。
肯定会有很多解释,但这仅涉及一个目标,即OOP的目标。
同样适用于函数式编程

当我们说功能含义时,程序就是由功能组成的。
函数的作用是返回一个评估的参数/参数(参数是变量是调用函数时出现的表达式,而参数是函数声明中的一部分)。

当传递相同的参数时,函数也将始终返回相同的结果。这样,更容易避免错误或调试将来的错误。通过函数式编程,我们可以避免诸如修改全局变量之类的副作用。

JavaScript中的示例:

function increment(lis){
    return lis.map(
        function (x){
            return x+2;
        }
    );
}

var myList = [4, 7, 2, 3];
console.log(increment(myList));
console.log(myList);

函数增量将1值添加到对象内部的每个元素并返回结果。myList的值没有改变,但是当我们调用函数时,我们看到了该对象元素的附加值。

作为我对Java中可能进行函数式编程的回应,我相信不可能在Java中进行真正的功能编程。因为java实际上被设计为OOP,所以它在其中扩展了命令式编程并为可维护性进行了改进。当对象,变量等的状态发生变化时,这已经是必须进行的编程了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.