您应该尽量避免创建那么多对象。无论您选择哪种算法,如果您的数据库在某个时候会继续增长,您将无法将其全部放入内存中。此外,瓶颈很可能是从 DB 获取数据(而不是创建对象)。
因此请尝试重新构建您的应用,以便在执行相关操作时预先计算数据并将其存储在 DB 中。
如果经过仔细考虑,您决定确实需要使用这么多对象,那么更好的选择是继续使用原语:
class EmployeesInGroup {
private final int[] ids;
private final Group group;
...
Detail get(int idx) {
return new Details(ids[idx], group);
}
int size() {
return ids.length;
}
}
然后您可以遍历此列表并一次使用 1 个对象,而无需在内存中保留大量对象:
EmployeesInGroup list = new EmployeesInGroup(ids, group);
for(int i = 0; i < list.size(); i++) {
Detail d = list.get(i);
...
}
你可以让它实现Iterable并使用for-each循环。
基准测试
我上面列出的方法比创建 Detail 对象的 array 至少快 20 倍。使用流和列表会更加缓慢。我没有与Integer 核对过,但我预测它会使一切速度减慢 2 倍左右。
Benchmark Mode Cnt Score Error Units
EmployeeConversionBenchmark.objectArray thrpt 20 368.702 ± 3.483 ops/s
EmployeeConversionBenchmark.primitiveArray thrpt 20 7595.080 ± 68.841 ops/s
EmployeeConversionBenchmark.streamsWithObjects thrpt 20 197.923 ± 1.616 ops/s
这是我使用的代码:
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import static java.util.stream.Collectors.toList;
public class EmployeeConversionBenchmark {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(new String[]{EmployeeConversionBenchmark.class.getSimpleName()});
}
@Benchmark @Fork(value = 1, warmups = 0)
public int primitiveArray(Data data) {
EmployeesInGroup e = new EmployeesInGroup(data.ids, data.group);
int sum = 0;
for (int i = 0; i < e.size(); i++)
sum += e.get(i).getId();
return sum;
}
@Benchmark @Fork(value = 1, warmups = 0)
public int objectArray(Data data) {
EmployeesInGroup.Detail[] e = new EmployeesInGroup.Detail[data.ids.length];
for (int i = 0; i < data.ids.length; i++)
e[i] = new EmployeesInGroup.Detail(data.ids[i], data.group);
int sum = 0;
for (EmployeesInGroup.Detail detail : e)
sum += detail.getId();
return sum;
}
@Benchmark @Fork(value = 1, warmups = 0)
public int streamsWithObjects(Data data) {
List<EmployeesInGroup.Detail> e = Arrays.stream(data.ids).mapToObj(id -> new EmployeesInGroup.Detail(id, data.group)).collect(toList());
int sum = 0;
for (EmployeesInGroup.Detail detail : e)
sum += detail.getId();
return sum;
}
@State(Scope.Benchmark)
public static class Data {
private final int[] ids = new int[500_000];
private final EmployeesInGroup.Group group = new EmployeesInGroup.Group();
public Data() {
for (int i = 0; i < ids.length; i++)
ids[i] = new Random().nextInt();
}
}
public static class EmployeesInGroup {
private final int[] ids;
private final Group group;
public EmployeesInGroup(int[] ids, Group group) {
this.ids = ids;
this.group = group;
}
public Detail get(int idx) {
return new Detail(ids[idx], group);
}
public int size() {
return ids.length;
}
public static class Group {
}
public static class Detail {
private final int id;
private final Group group;
public Detail(int id, Group group) {
this.id = id;
this.group = group;
}
public int getId() {
return id;
}
}
}
}