类似于Python ML与numpy数组的操作;他们通过向量化而不是使用for
循环来加速处理。
如果您对向量化感兴趣,则Stream API并不适合您。
自Java 16以来,我们拥有向量API作为孵化特性(这意味着它不是API的最终状态,它只是用于测试和收集反馈,您不应该在生产中使用它)。
为了在Java中使用孵化特性,您需要做一些额外的工作,以获取从孵化模块导入的文件。
确保导入jdk.incubator.vector
包中的类的方法之一是创建一个模块,以明确指定它需要此包。
考虑一个具有以下文件夹结构的简单测试项目:
- [src]
- [main]
- [java]
- module-info.java
- [vectorization.test]
- Main.java
- resources
// other things
module-info.java
- 在这里我们请求 Vector API 的文件:
module vectorization.test {
requires jdk.incubator.vector;
}
Main.java
package vectorization.test;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.VectorSpecies;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
double[] margins = {1.0, 2.0, 3.0, 4.0, 5.0};
double[] quantity = {1, 2, 3, 4, 5};
double[] result = new double[margins.length];
multiply(margins, quantity, result);
System.out.println(Arrays.toString(result));
}
public static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_PREFERRED;
public static void multiply(double[] margins, double[] quantity, double[] result) {
int i = 0;
for (; i < SPECIES.loopBound(margins.length); i += SPECIES.length()) {
DoubleVector marginsVector = DoubleVector.fromArray(SPECIES, margins, i);
DoubleVector quantityVector = DoubleVector.fromArray(SPECIES, quantity, i);
DoubleVector resultVector = marginsVector.mul(quantityVector);
resultVector.intoArray(result, i);
}
for (; i < margins.length; i++) {
result[i] = margins[i] * quantity[i];
}
}
}
输出:
[1.0, 4.0, 9.0, 16.0, 25.0]
想了解有关 Vector API 的更多信息,请查看JEP 426。
说到 Streams,它们并不比普通循环更高效(在顺序流的情况下),事实上它们更慢,因为流需要创建额外的对象来执行迭代、转换和累加结果。这里没有什么魔法。
并行流可能更快,但这是一个需要谨慎使用的工具,因为你也可能得到相反的效果。你需要让你的任务可以并行化,有空闲的 CPU 核心让你的线程完成工作,并且数据量应该足够大,以使使用并行流变得合理(还需要测量性能,找出是否在你的情况下有所不同)。
引入 Java 中的函数式编程特性的主要目标之一是提供一种简洁而易于阅读的代码结构方式。
例如,您可以使用
Arrays.setAll()
来填充产品的结果数组:
Arrays.setAll(result, i -> margins[i] * quantity[i]);
for
循环更“快速且资源消耗更少”?(顺便说一句,我不知道哪种方式更好 - 我认为任何试图微基准测试结果的尝试都可能具有挑战性)。 - andrewJamesList.of
。 - Basil Bourque