Java 8 如何从流中获取可观测的数据流?
这几乎是同一个问题,但方向相反 我知道Java 8中没有Java 8 如何从流中获取可观测的数据流?,java-8,javafx-8,Java 8,Javafx 8,这几乎是同一个问题,但方向相反 我知道Java 8中没有FloatStream,float[]的用例也不多,但我有一个: 在JavaFX 3D中处理TriangleMesh,必须为整个网格顶点的3D坐标提供ObservableFloatArray 作为一些计算的结果,我将在列表中列出所有这些坐标,若要立即将所有坐标添加到网格中,我将使用以下方法之一调用triangleMesh.getPoints().addAll(): addAll(可观察到的流量src) addAll(浮动…元素) addA
FloatStream
,float[]的用例也不多,但我有一个:
在JavaFX 3D中处理TriangleMesh
,必须为整个网格顶点的3D坐标提供ObservableFloatArray
作为一些计算的结果,我将在列表中列出所有这些坐标
,若要立即将所有坐标添加到网格中,我将使用以下方法之一调用triangleMesh.getPoints().addAll()
:
- addAll(可观察到的流量src)
- addAll(浮动…元素)
- addAll(Observalefloatarray src、int-srcdex、int-length)
- addAll(float[]src,int-srcdex,int-length)
FXCollections.ObservableFloatArray()
,FXCollections.ObservableFloatArray(ObservableFloatArray数组)
或FXCollections.ObservableFloatArray(float…value)
创建
假设每个顶点都有一个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};
}
}
在执行了一些计算之后,我列出了列表顶点。我需要生成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);
但据我所知,没有办法使用流
提前感谢您提供涉及流的任何可能的解决方案。我认为没有任何方法可以绕过这样一个事实:您必须创建一个数据结构(例如,一个双[]
或一个列表
),然后将其映射到浮点[]
。(但也许我遗漏了什么。)
如果要使用类似于API的流执行此操作,可以使用收集器
在末尾执行映射:
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};
}
}
}
import java.util.List;
导入java.util.ListIterator;
导入java.util.Random;
导入java.util.stream.Collector;
导入java.util.stream.collector;
导入java.util.stream.IntStream;
导入java.util.stream.stream;
导入javafx.scene.shape.TriangleMesh;
公共类FloatsTest{
公共静态void main(字符串[]args){
//以下声明适用于Eclipse4.4
//但是,它不会从命令行编译:
//托福雷收集器=
//这一宣言的作用是:
托福雷收集器=
Collectors.collectionAndThen(Collectors.toList(),floatList->{
float[]数组=新的float[floatList.size()];
for(ListIterator迭代器=floatList.ListIterator();迭代器.hasNext();){
数组[iterator.nextIndex()]=iterator.next();
}
返回数组;
});
//用于演示目的的随机顶点列表:
随机rng=新随机();
列表顶点=IntStream.range(0,100)
.mapToObj(i->新顶点(rng.nextFloat(),rng.nextFloat(),rng.nextFloat())
.collect(Collectors.toList());
float[]vertexArray=顶点。stream()
.flatMap(v->Stream.of(v.getX(),v.getY(),v.getZ())
.收集(toFloatArray);
三角形网格=新三角形网格();
mesh.getPoints().addListener(obs->System.out.println(“mesh无效”));
mesh.getPoints().addListener((数组,sizeChanged,from,to)->System.out.println(“mesh已更改”);
mesh.getPoints().addAll(vertexArray);
}
公共静态类顶点{
私人最终浮动x;
私人最终浮动;
私人最终浮动z;
公共顶点(浮动x、浮动y、浮动z){
这个.x=x;
这个。y=y;
这个。z=z;
}
公共浮点getX(){
返回x;
}
公共浮球{
返回y;
}
公共浮动getZ(){
返回z;
}
公共浮点[]getCoordinates(){
返回新的浮点[]{x,y,z};
}
}
}
请记住,流定义的是操作,而不是存储。因此,对于大多数操作,当使用CPU寄存器时,使用浮点
仅比双倍
值提供很少的好处。对于可以使用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;
}
}
这支持并行处理,但是,对于仅包含数据复制的操作,并行处理没有任何好处。谢谢,@James\u D,我已经让它工作了。唯一的问题是我不能使用收集器
。它说“收集的类型(收集器,函数)是错误的”。但这是有效的收集器
。(使用NetBeans 8.0.1、JDK8u25、Windows7 64位)很有趣。这在我的IDE(Eclipse4.4;JDK8U40,MacOSX10.9.5)中编译并运行良好-但是。。。它不会从命令行编译,除非我在您的注释中做了更改。(如果我使用Eclipse来编译它,它可以从命令行运行,这并不奇怪。)我想我应该更新从命令行编译的内容的答案,尽管我很想知道差异来自何处。(看起来它应该能够正确推断供应商类型,就像在Eclips中一样