性能与内存列表
Performance vs memory Lists
什么会更好?
假设我们有一个 class mainClass
有一个 List<BigClass>
和 List<Foo>foos
...
Foo
本身就有一个List<Boo>
如果目标是能够获得 foos
的所有元素的所有 Boo
。
如果用户要将新的 Foo
插入 foos
,那么在 BigClass
中保留另一个 List<Boo>
并插入相应的 Boo
元素会更好吗?
或者每次用户请求此列表时从“BigClass”中生成此总 Boo
列表会更好吗?
这里的主要问题是,您必须在这里选择性能还是内存?
PS。
抱歉标题太笼统,不太清楚如何命名这个问题:/
您可以通过一个实现同时拥有这两种行为。只需在 mainClass 中创建您自己的 List 实现(可能是一个名为 FooList 的内部 class,或者甚至是一个匿名内部 class)。使 FooList 的方法透明地将所有单独的 Foo 列表呈现为单个列表。例如,FooList.iterator() 的实现将透明地依次在每个单独的 Foo 列表上实例化一个迭代器,因此它看起来像是在遍历单个大列表。
如果您既需要获取所有 Boo
s 又需要将 Boo
s 分组(即属于某些 Foo
的 Boo
s),那么我最好的办法是 return 查看 BigClass
中所有 Boo
的 ,无论哪个 Foo
他们属于。
为此,您可以使用 Google Guava Iterables
or Java 8 Stream.flatMap()
,具体取决于您的 Java 版本。
与Google番石榴:
class BigClass {
List<Foo> foos = new LinkedList<Foo>();
public Iterable<Boo> allBoos() {
return Iterables.concat(this.foos);
}
}
class Boo {
final int a;
Boo(int a) {
this.a = a;
}
@Override
public String toString() {
return String.valueOf(this.a);
}
}
class Foo
implements Iterable<Boo> {
List<Boo> boos = new LinkedList<Boo>();
@Override
public Iterator<Boo> iterator() {
return this.boos.iterator();
}
}
public class Sample {
public static void main(String[] args) {
Boo b1 = new Boo(1);
Boo b3 = new Boo(3);
Boo b5 = new Boo(5);
Boo b2 = new Boo(2);
Boo b4 = new Boo(4);
Boo b6 = new Boo(6);
Foo odd = new Foo();
odd.boos.addAll(Arrays.asList(b1, b3, b5));
Foo even = new Foo();
even.boos.addAll(Arrays.asList(b2, b4, b6));
BigClass b = new BigClass();
b.foos.add(odd);
b.foos.add(even);
System.out.println(b.allBoos()); // [1, 3, 5, 2, 4, 6]
}
}
这种方法最好的地方在于 Iterable
Guava returns 是 lazy,这意味着不会创建和填充新的集合或列表与任何元素。相反,returned Iterable
是一个视图,其 Iterator
消耗第一个 Iterable
的元素,并且在耗尽时,"jumps" 到下一个 Iterable
并消耗它的元素,并且 "jumps" 到下一个,依此类推,直到最后一个 Iterable
的最后一个元素被消耗。
与Java 8:
class BigClass {
List<Foo> foos = new LinkedList<Foo>();
public Iterable<Boo> allBoos() {
Stream<Boo> s = this.foos.stream().flatMap(
f -> f.getBoos().stream());
return s::iterator;
}
}
class Boo {
final int a;
Boo(int a) {
this.a = a;
}
@Override
public String toString() {
return String.valueOf(this.a);
}
}
class Foo {
List<Boo> boos = new LinkedList<Boo>();
public List<Boo> getBoos() {
return this.boos;
}
}
public class Sample {
public static void main(String[] args) {
Boo b1 = new Boo(1);
Boo b3 = new Boo(3);
Boo b5 = new Boo(5);
Boo b2 = new Boo(2);
Boo b4 = new Boo(4);
Boo b6 = new Boo(6);
Foo odd = new Foo();
odd.boos.addAll(Arrays.asList(b1, b3, b5));
Foo even = new Foo();
even.boos.addAll(Arrays.asList(b2, b4, b6));
BigClass b = new BigClass();
b.foos.add(odd);
b.foos.add(even);
List<Boo> list = new ArrayList<>();
b.allBoos().forEach(boo -> list.add(boo));
System.out.println(list); // [1, 3, 5, 2, 4, 6]
}
}
关于懒惰的相同注意事项也适用于此。
什么会更好?
假设我们有一个 class mainClass
有一个 List<BigClass>
和 List<Foo>foos
...
Foo
本身就有一个List<Boo>
如果目标是能够获得 foos
的所有元素的所有 Boo
。
如果用户要将新的 Foo
插入 foos
,那么在 BigClass
中保留另一个 List<Boo>
并插入相应的 Boo
元素会更好吗?
或者每次用户请求此列表时从“BigClass”中生成此总 Boo
列表会更好吗?
这里的主要问题是,您必须在这里选择性能还是内存?
PS。 抱歉标题太笼统,不太清楚如何命名这个问题:/
您可以通过一个实现同时拥有这两种行为。只需在 mainClass 中创建您自己的 List 实现(可能是一个名为 FooList 的内部 class,或者甚至是一个匿名内部 class)。使 FooList 的方法透明地将所有单独的 Foo 列表呈现为单个列表。例如,FooList.iterator() 的实现将透明地依次在每个单独的 Foo 列表上实例化一个迭代器,因此它看起来像是在遍历单个大列表。
如果您既需要获取所有 Boo
s 又需要将 Boo
s 分组(即属于某些 Foo
的 Boo
s),那么我最好的办法是 return 查看 BigClass
中所有 Boo
的 ,无论哪个 Foo
他们属于。
为此,您可以使用 Google Guava Iterables
or Java 8 Stream.flatMap()
,具体取决于您的 Java 版本。
与Google番石榴:
class BigClass {
List<Foo> foos = new LinkedList<Foo>();
public Iterable<Boo> allBoos() {
return Iterables.concat(this.foos);
}
}
class Boo {
final int a;
Boo(int a) {
this.a = a;
}
@Override
public String toString() {
return String.valueOf(this.a);
}
}
class Foo
implements Iterable<Boo> {
List<Boo> boos = new LinkedList<Boo>();
@Override
public Iterator<Boo> iterator() {
return this.boos.iterator();
}
}
public class Sample {
public static void main(String[] args) {
Boo b1 = new Boo(1);
Boo b3 = new Boo(3);
Boo b5 = new Boo(5);
Boo b2 = new Boo(2);
Boo b4 = new Boo(4);
Boo b6 = new Boo(6);
Foo odd = new Foo();
odd.boos.addAll(Arrays.asList(b1, b3, b5));
Foo even = new Foo();
even.boos.addAll(Arrays.asList(b2, b4, b6));
BigClass b = new BigClass();
b.foos.add(odd);
b.foos.add(even);
System.out.println(b.allBoos()); // [1, 3, 5, 2, 4, 6]
}
}
这种方法最好的地方在于 Iterable
Guava returns 是 lazy,这意味着不会创建和填充新的集合或列表与任何元素。相反,returned Iterable
是一个视图,其 Iterator
消耗第一个 Iterable
的元素,并且在耗尽时,"jumps" 到下一个 Iterable
并消耗它的元素,并且 "jumps" 到下一个,依此类推,直到最后一个 Iterable
的最后一个元素被消耗。
与Java 8:
class BigClass {
List<Foo> foos = new LinkedList<Foo>();
public Iterable<Boo> allBoos() {
Stream<Boo> s = this.foos.stream().flatMap(
f -> f.getBoos().stream());
return s::iterator;
}
}
class Boo {
final int a;
Boo(int a) {
this.a = a;
}
@Override
public String toString() {
return String.valueOf(this.a);
}
}
class Foo {
List<Boo> boos = new LinkedList<Boo>();
public List<Boo> getBoos() {
return this.boos;
}
}
public class Sample {
public static void main(String[] args) {
Boo b1 = new Boo(1);
Boo b3 = new Boo(3);
Boo b5 = new Boo(5);
Boo b2 = new Boo(2);
Boo b4 = new Boo(4);
Boo b6 = new Boo(6);
Foo odd = new Foo();
odd.boos.addAll(Arrays.asList(b1, b3, b5));
Foo even = new Foo();
even.boos.addAll(Arrays.asList(b2, b4, b6));
BigClass b = new BigClass();
b.foos.add(odd);
b.foos.add(even);
List<Boo> list = new ArrayList<>();
b.allBoos().forEach(boo -> list.add(boo));
System.out.println(list); // [1, 3, 5, 2, 4, 6]
}
}
关于懒惰的相同注意事项也适用于此。