使用Java 8流,似乎函数编程赢了,无状态和递归万岁!但是现实有点微妙:与软件编程一样,它取决于。我相信你的工具箱中的工具越多越好。
当你拥有的只是一把锤子时,一切看起来像钉子。
在函数编程中,每个函数都需要纯粹:输出仅取决于输入,并且没有副作用。
看看Stream.generate()有两种用法:
Stream.generate(Math::random);
Stream.generate(() -> "Java");
第一行是随机值产生,第二行是常量输出。
Stream.iterate()的示例:
Stream.iterate(0, i -> i + 1);
当下一项的计算很简单时,这种迭代很容易。当计算变得更复杂时,需要数据结构。
这是一个带有函数的例子,它计算索引的平方,以便之后可以求和:
Stream.iterate(new double[]{1, 1}, pair -> new double[]{pair[0] + 1, Math.pow(pair[0] + 1, 2)});
我不确定这是最易读的代码片段。为了使它更清洁,让我们创建一个专用的结构:
public class Pair { public final int index; public final double value; public Pair(int index, double value) { this.index = index; this.value = value; } } Stream.iterate(new Pair(1, 1), pair -> new Pair(pair.index + 1, Math.pow(pair.index + 1, 2)));
这只是稍微好一点,因为计算逻辑仍然在lambda中“隐藏”。一种解决方案可能是让Pair计算成为下一个值:
public class Pair { public static final Pair SEED = new Pair(1, 1); public final int index; public final double value; public Pair(int index, double value) { this.index = index; this.value = value; } public Pair next() { return new Pair(index + 1, Math.pow(index + 1, 2)); } } Stream.iterate(Pair.SEED, Pair::next);
我认为这是一个非常巧妙的解决方案。它也可以重复用于其他功能/系列/套件。
以下是阶乘函数的示例:
public class Factorial { public static final Factorial SEED = new Factorial(1, 1); public final int index; public final int value; public Factorial(int index, int value) { this.index = index; this.value = value; } public Factorial next() { return new Factorial(index + 1, value * index); } } Stream.iterate(Pair.SEED, Pair::next);
还有另一个斐波那契套件:
public class Fibonacci { public static final Fibonacci SEED = new Fibonacci(1, 1); public final int previous; public final int value; public Fibonacci(int previous, int value) { this.previous = previous; this.value = value; } public Fibonacci next() { return new Fibonacci(value, value + previous); } } Stream.iterate(Fibonacci.SEED, Fibonacci::next);
注意状态是如何引入的?状态使代码更容易阅读。
现在,让我们进一步推动事情。还记得Stream.generate()上面函数吗?使用正确的有状态Supplier,它可以替换Stream.iterate():
public class IncrementSupplier implements Supplier<Integer> { private int value; public IncrementSupplier(int seed) { this.value = seed; } @Override public Integer get() { return ++value; } } Stream.iterate(0, i -> i + 1); Stream.generate(new IncrementSupplier(0));
上面两行是同样的。
开发者更多的是激情的生物,而不是理性的生物。这不是因为Java提供了函数编程,它现在不允许状态。虽然状态是并发编程上下文中的一个问题,但它对于更易读的代码可能是一个巨大的帮助。