【问题标题】:Comparison of imperative and functional approach in Java [closed]Java中命令式和函数式方法的比较[关闭]
【发布时间】:2015-07-13 21:36:12
【问题描述】:

我有一个方法可以打印给定列表中一个人的 name,如果它具有指定的 age。此方法是使用命令式然后函数式方法实现的。

public static void printPerson(int age) {
    for(Person p: list) {
        if(p.age == age) {
            System.out.println(p.name)
        }
    }
}

功能方法:

public static void printPerson(int age) {
    list.stream()
        .filter(p -> p.age == age)
        .forEach(p -> System.out.println(p.name));
}

问题是,除了可读性之外,我们还能如何比较这两种方法,以及对这些属性中的每一个的评估是什么。 例如,哪一个具有更高的内存占用,哪一个引入的开销最小,或者具有更高的响应时间。可以讨论哪些其他属性(即非功能性需求)?

【问题讨论】:

  • 看起来像 C++,确定要使用“Java”标签吗?
  • @bakoyaro 自 Java 8 以来最后一个代码编译为 lambda expressions
  • This post 可能对这个问题感兴趣。
  • 普通循环几乎在所有方面都更好。在这个时候,Stream 肯定被滥用了,因为它是一个闪亮的新玩具。
  • 两者都是同样糟糕的混合分离与副作用匹配的元素。如果您将这些拆分为 getPersonsByAge、printPersons 并就地替换您的方法 printPersonsByAge,您会发现流版本会很小,使用更少的内存并立即开始生成输出,而在您的命令式版本中需要使用 anwer 进行集合从一个传递到另一个会导致更高的内存使用率,并且在过滤所有元素之前您不会看到输出。

标签: java functional-programming imperative-programming


【解决方案1】:

实际上,这并不重要,但函数式方法会占用更多内存和 CPU,因为与命令式方法相比,lambda 相对昂贵。 lambdas are actually just anonymous inner classes,因此您依赖 JVM 来优化方法调用,使其看起来像命令式版本。关于命令式编程要记住的一点是,它看起来很像汇编,所以它往往运行得很快,几乎不需要额外的工作。

将来,像map 这样的一些操作可以并行化,所以它有点面向未来。

但请注意:有些事情在命令式上要干净得多,但如果您过于专注于函数式编程,您可能会错过该解决方案。 Stackoverflow 上有很多关于“我如何在 Guava 中做 x”的问题,答案是“你为什么要滥用 Guava 来做你可以用 Java 的标准库在三个代码行数?

【讨论】:

  • 其实 lambdas 和匿名类是不一样的。与匿名类相比,它们的实现方式和捕获 this 的方式不同。我记得读过一个关于这个的答案,只是不记得具体在哪里。
  • 那么它们可能只是静态的,我不确定它们是预先实例化的还是每次都生成新实例,但您仍然需要处理内联。跨度>
  • 在这种打印名称列表的特殊情况下,并行性不太可能成为要求。
【解决方案2】:

很难回答,在 Java 中,函数式方法的性能会因实现而有很大差异。

通常,通过函数范式,您可以消除副作用,并且可以轻松(以数学方式)证明函数执行正确的操作。

就纯粹的性能(尤其是响应时间)而言,我认为函数式并不比命令式范式更快或不快。唯一重要的是:

  • 您的实施方式
  • 语言(在 Java 中为 JVM)的实现方式。

至少,我不建议在 Java 中使用函数式范例,lamdba 表达式对于这种语言来说还很年轻。除非你喜欢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    • 2011-03-11
    • 2016-09-03
    • 2020-05-16
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多