使用Java 8流,似乎函数式编程已成功。 万岁无状态和递归! 现实有些微妙:与软件编程一样, 它取决于 。 我相信工具带中的工具越多越好。
当您只有一把锤子时,一切看起来都像钉子。
在函数式编程中,每个函数都必须是纯函数:输出仅取决于输入,并且没有副作用。 因此,不使用Java方法来创建无限流(很多吗?)。
以Stream.generate()
为例。 我只看到两种用法:
Stream.generate(Math::random); (1)
Stream.generate(()->"Java"); (2)
- 随机值生成
- 恒定值生成
同样,以下代码段是Stream.iterate()
的最常见示例:
Stream.iterate(0,i->i+1);
当下一项的计算简单时,迭代很容易。 当计算变得更加复杂时,就需要一个数据结构。
这是一个具有计算索引平方的函数的示例,以便可以对其求和( 例如 1 2 + 2 2 + 3 2 +…n 2 ):
Stream.iterate(newdouble[]{1,1},
pair->newdouble[]{pair[0]+1,Math.pow(pair[0]+1,2)});
我不确定这是最易读的代码段。 为了使它更整洁,让我们创建一个专用的结构:
publicclassPair{
publicfinalintindex;
publicfinaldoublevalue;
publicPair(intindex,doublevalue){
this.index=index;
this.value=value;
}
}
Stream.iterate(newPair(1,1),
pair->newPair(pair.index+1,Math.pow(pair.index+1,2)));
这只是稍微好一点,因为计算逻辑仍被“隐藏”在lambda中。 一种解决方案是让Pair
计算下一个值:
publicclassPair{
publicstaticfinalPairSEED=newPair(1,1);
publicfinalintindex;
publicfinaldoublevalue;
publicPair(intindex,doublevalue){
this.index=index;
this.value=value;
}
publicPairnext(){
returnnewPair(index+1,Math.pow(index+1,2));
}
}
Stream.iterate(Pair.SEED,Pair::next);
我认为这是一个很好的解决方案。 也可以将其重新用于其他功能/系列/套件。
这是阶乘函数的示例:
publicclassFactorial{
publicstaticfinalFactorialSEED=newFactorial(1,1);
publicfinalintindex;
publicfinalintvalue;
publicFactorial(intindex,intvalue){
this.index=index;
this.value=value;
}
publicFactorialnext(){
returnnewFactorial(index+1,value*index);
}
}
Stream.iterate(Pair.SEED,Pair::next);
另一个斐波那契套件:
publicclassFibonacci{
publicstaticfinalFibonacciSEED=newFibonacci(1,1);
publicfinalintprevious;
publicfinalintvalue;
publicFibonacci(intprevious,intvalue){
this.previous=previous;
this.value=value;
}
publicFibonaccinext(){
returnnewFibonacci(value,value+previous);
}
}
Stream.iterate(Fibonacci.SEED,Fibonacci::next);
注意状态是如何引入的? 它使代码更易于阅读。
现在,让我们更进一步。 还记得上面的Stream.generate()
函数吗? 使用正确的有状态Supplier
,它可以替换Stream.iterate()
:
publicclassIncrementSupplierimplementsSupplier<Integer>{
privateintvalue;
publicIncrementSupplier(intseed){ (1)
this.value=seed;
}
@Override
publicIntegerget(){
return++value; (2)
}
}
Stream.iterate(0,i->i+1); (3)
Stream.generate(newIncrementSupplier(0)); (3)
- 种子成为
Supplier
一部分 - 增加值并返回
- 那些是等效的
与理性相比,开发者更多是激情的创造者。 不是因为Java提供了函数式编程,它现在不允许状态。 虽然状态在并发编程上下文中是一个问题,但它对于更易读的代码可能有巨大的帮助。