2015-03-13 38 views
3

什麼會更好?性能與內存列表

說我們會有一定的階級mainClass具有List<BigClass>List<Foo>foos ....

Foo本身具有List<Boo>

如果目標是能夠得到所有Boo的對foos的所有元素。 如果用戶要在foos中插入新的Foo,那麼保留BigClass中的另一個List<Boo>並插入相應的Boo元素會更好嗎?

或者每次用戶要求這個列表時,從'BigClass`內生成這個總的Boo列表會更好嗎?

這裏的主要問題是,你會不會在這裏選擇性能vs內存?

PS。 對不起廣泛的標題,不知道如何命名這個問題:/

+2

使用最容易理解的方法。這是主要關心的問題。性能或內存不要擔心,直到它是一個問題,因爲它可能不會。 – 2015-03-13 17:36:28

+1

*你會不得不在這裏選擇性能vs內存*:是的,很明顯。您還必須考慮正確性,可維護性,健壯性和可讀性。第二種解決方案比第一種解決方案簡單得多。 – 2015-03-13 17:37:32

+0

@JBNizet,是的,但如果做得對。第一個選項會是首選嗎? – 2015-03-13 17:44:17

回答

1

如果需要都得到所有Boo S和也保持Boo與分組(即Boo s表示屬於某個Foo),那麼我會說,最好將返回的視圖所有Boo包含在BigClass中,不管它們屬於哪個Foo

要完成此操作,您可以使用Google Guava IterablesJava 8 Stream.flatMap(),具體取決於您的Java版本。

與谷歌番石榴:

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,這意味着沒有新的集合或列表中創建並填充任何元素。相反,返回的Iterable是一個視圖,其消耗第一個Iterable中的元素,並在用盡時「跳轉」到下一個Iterable並消耗其元素,並跳轉到下一個元素,依此類推,直到最後一個元素最後的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] 
    } 
} 

關於懶惰同樣的考慮也適用於此。

+0

這看起來很不錯,因爲(據我所知)它不會消耗任何額外的記憶。但是,當一個呼叫讓所有'boo's被做出正確的時候,它將不得不一遍遍地重複每一次。 – 2015-03-13 22:52:15

+0

@Koen不,這是一個觀點。換句話說,在每個「Foo」中的所有「Boo」列表中都有一個包裝。這是一個'O(1)'操作。 – 2015-03-13 22:57:34

+0

@Koen水晶般清澈:元素在迭代返回的List時被最終遍歷。 – 2015-03-13 23:03:18

2

你可以有一個單一的實施兩種行爲。只需在mainClass中創建自己的List實現(可能是一個名爲FooList的內部類,或者甚至可能是一個匿名的內部類)。使FooList的方法將所有單獨的Foo列表透明地顯示爲一個列表。例如,FooList.iterator()的實現將依次透明地在每個單獨的Foo列表上實例化一個迭代器,以便它似乎遍歷一個大的列表。