这与one几乎相同,但方向相反。
我知道Java 8中没有FloatStream
,并且float []没有很多用例,但我有一个:
在JavaFX 3D中处理TriangleMesh
,您必须为整个网格的顶点的3D坐标提供ObservableFloatArray
。
作为一些计算的结果,我将在List
中拥有所有这些坐标,并将所有这些坐标一次性添加到网格中,我将使用其中一个来调用triangleMesh.getPoints().addAll()
以下方法:
可以使用ObservableFloatArray
,FXCollections.observableFloatArray()
或FXCollections.observableFloatArray(ObservableFloatArray array)
创建FXCollections.observableFloatArray(float... values)
。
假设我为每个顶点都有这个pojo:
private class Vertex {
private final float x;
private final float y;
private final float z;
public Vertex(float x, float y, float z){
this.x=x; this.y=y; this.z=z;
}
public float[] getCoordenates(){
return new float[]{x,y,z};
}
}
在执行一些计算后,我有List<Vertex> listVertices
。我需要生成float[] arrayVertices
才能最终调用triangleMesh.getPoints().addAll(arrayVertices);
。
现在这就是我正在做的事情:
listVertices.forEach(vertex->triangleMesh.getPoints().addAll(vertex.getCoordenates()));
但是这会在添加到可观察数组的每个新顶点上触发关联的侦听器,对于大量顶点,这会影响性能。
如果FloatStream
和flatMapToFloat()
存在,我会做这样的事情:
float[] arrayVertices = listVertices.stream()
.map(vertex->FloatStream.of(vertex.getCoordenates()))
.flatMapToFloat(f->f).toArray();
triangleMesh.getPoints().addAll(arrayVertices);
就像我实际使用面部索引的int []列表一样:
int[] arrayFaces = listFaces.stream()
.map(face->IntStream.of(face.getFaceIndices()))
.flatMapToInt(i->i).toArray();
triangleMesh.getFaces().addAll(arrayFaces);
但据我所知,没有办法使用溪流。
提前感谢任何可能涉及流的解决方案。
答案 0 :(得分:6)
请记住,Stream
定义操作而不是存储。因此,对于大多数操作,当使用CPU寄存器时,使用float
仅比double
值提供的好处很少。对于可以使用SSE或GPU加速的操作,可能会有理论上的改进,但这与此无关。
因此,您可以使用DoubleStream
进行该操作,您唯一需要的是能够将DoubleStream
收集到float[]
数组中的收集器:
float[] arrayVertices = listVertices.stream()
.flatMapToDouble(vertex->DoubleStream.of(vertex.x, vertex.y, vertex.z))
.collect(FaCollector::new, FaCollector::add, FaCollector::join)
.toArray();
static class FaCollector {
float[] curr=new float[64];
int size;
void add(double d) {
if(curr.length==size) curr=Arrays.copyOf(curr, size*2);
curr[size++]=(float)d;
}
void join(FaCollector other) {
if(size+other.size > curr.length)
curr=Arrays.copyOf(curr, size+other.size);
System.arraycopy(other.curr, 0, curr, size, other.size);
size+=other.size;
}
float[] toArray() {
if(size!=curr.length) curr=Arrays.copyOf(curr, size);
return curr;
}
}
这支持并行处理,但是,对于仅包含数据复制的操作,并行处理没有任何好处。
答案 1 :(得分:2)
我认为您不得不创建一个数据结构(例如double[]
或List<Float>
)然后将其映射到float[]
这一事实。 (但也许我错过了一些东西。)
如果您想使用类似Stream
的API执行此操作,可以使用Collector
在最后执行映射:
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javafx.scene.shape.TriangleMesh;
public class StreamFloatsTest {
public static void main(String[] args) {
// The following declaration works in Eclipse 4.4
// however it won't compile from the command line:
// Collector<Float, List<Float>, float[]> toFloatArray =
// This declaration works:
Collector<Float, ?, float[]> toFloatArray =
Collectors.collectingAndThen(Collectors.toList(), floatList -> {
float[] array = new float[floatList.size()];
for (ListIterator<Float> iterator = floatList.listIterator(); iterator.hasNext();) {
array[iterator.nextIndex()] = iterator.next();
}
return array ;
});
// Random vertex list for demo purposes:
Random rng = new Random();
List<Vertex> vertices = IntStream.range(0, 100)
.mapToObj(i -> new Vertex(rng.nextFloat(), rng.nextFloat(), rng.nextFloat()))
.collect(Collectors.toList());
float[] vertexArray = vertices.stream()
.flatMap(v -> Stream.of(v.getX(), v.getY(), v.getZ()))
.collect(toFloatArray);
TriangleMesh mesh = new TriangleMesh();
mesh.getPoints().addListener(obs -> System.out.println("mesh invalidated"));
mesh.getPoints().addListener((array, sizeChanged, from, to) -> System.out.println("mesh changed"));
mesh.getPoints().addAll(vertexArray);
}
public static class Vertex {
private final float x ;
private final float y ;
private final float z ;
public Vertex(float x, float y, float z) {
this.x = x ;
this.y = y ;
this.z = z ;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
public float[] getCoordinates() {
return new float[] {x, y, z};
}
}
}