我正在尝试将“旧方式”循环转换为基于流的方法。循环采用一大组元素并返回属于给定半径的子集。结果按距离排序,结果本身具有方便的计算距离(用于演示)。它以旧的方式运行良好,我不需要到Java8-ify它。但我真的很想。 :-)如果只能在这个吸盘上去.parallel()。
捕获是...我的filter()使用计算值(距离),然后我需要在后续map()步骤中(构造“with distance”实例)。假设距离计算很昂贵。这是Java 7方式...向下滚动以查看getNearestStations()方法:
public interface Coordinate {
double distanceTo(Coordinate other);
}
public class Station {
private final String name;
private final Coordinate coordinate;
public Station(String name, Coordinate coordinate) {
this.name = name;
this.coordinate = coordinate;
}
public String getName() {
return name;
}
public Coordinate getCoordinate() {
return coordinate;
}
}
public class StationWithDistance extends Station implements Comparable<StationWithDistance> {
private final double distance;
public StationWithDistance(Station station, double distance) {
super(station.getName(), station.getCoordinate());
this.distance = distance;
}
public double getDistance() {
return distance;
}
public int compareTo(StationWithDistance s2) {
return Double.compare(this.distance, s2.distance);
}
}
// Assume this contains many entries
private final List<Station> allStations = new ArrayList<>();
public List<StationWithDistance> getNearbyStations(Coordinate origin, double radius) {
List<StationWithDistance> nearbyStations = new ArrayList<>();
for (Station station : allStations) {
double distance = origin.distanceTo(station.getCoordinate());
if (distance <= radius) {
nearbyStations.add(new StationWithDistance(station, distance));
}
}
Collections.sort(nearbyStations);
return nearbyStations;
}
现在......这是一种基于愚蠢/蛮力流的方法。请注意,它执行两次距离计算(stoopid),但它更接近并行()ized:
public List<StationWithDistance> getNearbyStationsNewWay(Coordinate origin, double radius) {
return allStations.stream()
.parallel()
.filter(s -> origin.distanceTo(s.getCoordinate()) <= radius)
.map(s -> new StationWithDistance(s, origin.distanceTo(s.getCoordinate())))
.sorted()
.collect(Collectors.toList());
}
试图找出一个更好的方式(tm),这是我到目前为止所提出的所有内容,以避免重复计算:
public List<StationWithDistance> getNearbyStationsNewWay(Coordinate origin, double radius) {
return allStations.stream()
.parallel()
.map(s -> new StationWithDistance(s, origin.distanceTo(s.getCoordinate())))
.filter(s -> s.getDistance() <= radius)
.sorted()
.collect(Collectors.toList());
}
...但是会产生垃圾 - 大多数创建的StationWithDistance实例都会被过滤掉。
我错过了什么?在Java 8中是否有一种优雅的方法可以避免重复计算,(b)不会产生不必要的垃圾?
我可以通过forEach()调用,混合旧的&amp;新的方法......所以我至少可以利用流,但以老派的方式“优化”计算/过滤/添加。这将是一个很好,简单,优雅的解决方案。帮我看看光......
答案 0 :(得分:1)
您可以使用flatMap
融合filter
和map
阶段,这样您就可以将计算出的距离保存在局部变量中,直到您知道创建新对象有用为止
在这里,我已经将flatmapper提取为一个helper方法,因为我更喜欢这种风格,但它当然可能将它内联为语句lambda(甚至是使用? :
三元运算符的表达式lambda)
Stream<StationWithDistance> nearbyStation(Station s, Coordinate origin, double radius) {
double distance = origin.distanceTo(s.getCoordinate());
if (distance <= radius) {
return Stream.of(new StationWithDistance(s, distance));
} else {
return Stream.empty();
}
}
public List<StationWithDistance> getNearbyStationsNewerWay(Coordinate origin, double radius) {
return allStations.stream()
.parallel()
.flatMap(s -> nearbyStation(s, origin, radius))
.sorted()
.collect(Collectors.toList());
}
答案 1 :(得分:1)
我实际上没有测试它是否有效,但我认为您可以根据距离计算map
阶段的距离,返回StationWithDistance
或null
,以及然后filter
null
s。{/ p>
public List<StationWithDistance> getNearbyStationsNewWay(Coordinate origin, double radius) {
return allStations.stream()
.parallel()
.map(s -> {
double dist = origin.distanceTo(s.getCoordinate());
return (dist <= radius)?(new StationWithDistance(s, dist)):null;
})
.filter(s -> s != null)
.sorted()
.collect(Collectors.toList());
}