use*_*922 5 java parallel-processing filter garbage java-8
我正在尝试将“旧方式”循环转换为基于流的方法。该循环采用一大组元素并返回一个落在给定半径内的子集。结果按距离排序,并且结果本身具有方便的计算距离(用于演示)。它以旧方式工作正常,我不需要对它进行 Java8 化。但我真的很想。:-) 如果只是为了能够在这个傻瓜上使用 .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;
}
Run Code Online (Sandbox Code Playgroud)
现在......这是一种基于愚蠢/蛮力流的方法。请注意,它执行了两次距离计算(愚蠢),但它更接近于 parallel()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());
}
Run Code Online (Sandbox Code Playgroud)
试图找出更好的方法(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());
}
Run Code Online (Sandbox Code Playgroud)
...但这会产生垃圾——大多数创建的 StationWithDistance 实例都被过滤掉了。
我错过了什么?在 Java 8 中是否有一种优雅的方法可以做到(a)避免重复计算,并且(b)不会产生不需要的垃圾?
我可以通过 forEach() 调用来做到这一点,混合新旧方法......所以我至少可以利用流,但以老派的方式“优化”计算/过滤器/添加。必须有一个很好的、简单的、优雅的解决方案。帮我看看光明...
您可以使用flatMap融合 afilter和mapstage,这允许您将计算出的距离保存在局部变量中,直到您知道创建新对象有用为止。
在这里,我将 flatmapper 提取到一个辅助方法中,因为我更喜欢这种风格,但它当然可以将其内联为语句 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());
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2980 次 |
| 最近记录: |