在Java中存储唯一排序值的最有效方式(最佳性能和最小gc)是什么?
目前我使用HashMap获取一组唯一值,然后将HashMap值复制到ArrayList中,然后使用Collections.sort()对值进行排序,因为我的对象实现了Comparable,最终给出了一个唯一的排序值。代码将每秒运行数千次,因此我想要最好的方法。任何人都可以提出更好的选择吗?
/代码只能在一个线程中运行。
我的代码如下:
public class LapRanking {
private final Map<String, Car> carsInRace = new HashMap<String,Car>();
public List<Car> processLap(Car car){
carsInRace.put(car.driverName, car);
List<Car> lapTimeRankings = new ArrayList<Car>(carsInRace.values());
Collections.sort(lapTimeRankings);
return lapTimeRankings;
}
public static void main(String[] args) {
Car one = new Car("DriverOne");
Car two = new Car("DriverTwo");
Car three = new Car("DriverThree");
LapRanking lapRanking = new LapRanking();
for (int i = 0; i < 100; i++) {
one = one.setLapTime();
two = two.setLapTime();
three = three.setLapTime();
lapRanking.processLap(one);
lapRanking.processLap(two);
lapRanking.processLap(three);
}
}
}
public class Car implements Comparable<Car> {
private static final Random randomTestTimes = new Random();
public final String driverName;
public final double lapTime;
public final double firstQuarterTime;
public Car(String driverName) {
this.driverName = driverName;
this.lapTime = Double.MAX_VALUE;
this.firstQuarterTime = Double.MAX_VALUE;
}
public Car(String driverName, double lapTime, double firstQuarterTime) {
this.driverName = driverName;
this.lapTime = lapTime;
this.firstQuarterTime = firstQuarterTime;
}
public Car setLapTime(){
return new Car(driverName,randomTestTimes.nextDouble(), randomTestTimes.nextDouble());
}
@Override
public int compareTo(Car o) {
int i = Double.compare(lapTime, o.lapTime);
if(i !=0)
return i;
return Double.compare(firstQuarterTime, o.firstQuarterTime);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Car {driverName='").append(driverName).append('\'');
sb.append(", lapTime=").append(lapTime);
sb.append(", firstQuarterTime=").append(firstQuarterTime).append('}');
return sb.toString();
}
}
答案 0 :(得分:1)
据我所知,对于所写的应用程序,地图实际上没有用处。 IMO,性能最高的解决方案是用预先分配并在启动时填充的适当大小的Car[]
替换地图。然后使用Arrays.sort()
每圈进行一次就地排序。
满足您的要求。它存储唯一的对象(Car
对象)并保持它们的排序。
应该在启动后没有生成垃圾,除了(可能)由sort(...)
方法本身创建的垃圾......以及输出排名。
这样的事情:
Car[] cars = new Car[] {one, two, three};
for (int i = 0; i < 100; i++) {
one.setLapTime();
two.setLapTime();
three.setLapTime();
// Sort the cars based on their `compareTo` method; i.e. lap time.
Arrays.sort(cars);
// Output the cars, ranked by lap time
for (Car car in cars) {
...
}
}
针对Car不可变的变体进行了更新:
Car[] cars = new Car[3];
for (int i = 0; i < 100; i++) {
one = one.setLapTime();
two = two.setLapTime();
three = three.setLapTime();
cars[0] = one;
cars[1] = two;
cars[2] = three;
Arrays.sort(cars);
}
或者......更简洁:
Car[] cars = new Car[]{one, two, three};
for (int i = 0; i < 100; i++) {
for (j = 0; j < cars.length[]; j++) {
cars[j] = cars[j].setLapTime();
}
Arrays.sort(cars);
}
(虽然我必须说实际创建并返回一个新对象的setter
是非常差的界面设计。如果我是代码审查该代码,那么就会有很多红色的写作。 。)
顺便说一句,使用TreeMap
的想法没有用,因为你的算法实际上是在对地图的值集进行排序而不是键集。
答案 1 :(得分:1)
您应该考虑使用TreeMap
或TreeSet
。
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
http://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html
它们可能非常适合您的情况。
答案 2 :(得分:0)
我还没有计时或做过任何基准测试,但我强烈怀疑你会通过消除processLap中ArrayList的“新”分配来获得最大的加速。内存分配比3项列表上的排序要贵得多。
如果在连续调用processLap之间没有添加任何汽车,那么实际上不需要再次将HashMap中的值复制到已分配的ArrayList中。只需对您已有的ArrayList进行排序。
public class LapRanking {
private final Map<String, Car> carsInRace = new HashMap<String,Car>();
ArrayList<Car> lapTimeRankings;
public List<Car> processLap(Car car){
Car oldcar = carsInRace.put(car.driverName, car);
if (oldcar == null)
{
lapTimeRankings = new ArrayList<Car>(carsInRace.values());
}
Collections.sort(lapTimeRankings);
return lapTimeRankings;
}
正如其他人已经说过的那样 - 对哈希表的需求也是可疑的。
如果您可以使用单独的功能将汽车插入比赛,而不是重载processLap,那么您将会更好......
public class LapRanking {
private final Map<String, Car> carsInRace = new HashMap<String,Car>();
boolean isDirty;
ArrayList<Car> lapTimeRankings;
void insertCarIntoRace(Car car)
{
carsInRace.put(car.driverName, car);
isDirty = true;
}
public List<Car> processLap(Car car){
if (isDirty)
{
lapTimeRankings = new ArrayList<Car>(carsInRace.values());
isDirty = false;
}
Collections.sort(lapTimeRankings);
return lapTimeRankings;
}
public static void main(String[] args) {
Car one = new Car("DriverOne");
Car two = new Car("DriverTwo");
Car three = new Car("DriverThree");
LapRanking lapRanking = new LapRanking();
lapRanking.insertCarIntoRace(car1);
lapRanking.insertCarIntoRace(car2);
lapRanking.insertCarIntoRace(car3);
for (int i = 0; i < 100; i++) {
one.setLapTime();
two.setLapTime();
three.setLapTime();
lapRanking.processLap(one);
lapRanking.processLap(two);
lapRanking.processLap(three);
}
}
}