2014-02-11 58 views
45

在Java中8個工作,我有一個TreeSet這樣定義:使用流收集到TreeSet中使用自定義比較

private TreeSet<PositionReport> positionReports = 
     new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp)); 

PositionReport是這樣定義的一個相當簡單的類:

public static final class PositionReport implements Cloneable { 
    private final long timestamp; 
    private final Position position; 

    public static PositionReport create(long timestamp, Position position) { 
     return new PositionReport(timestamp, position); 
    } 

    private PositionReport(long timestamp, Position position) { 
     this.timestamp = timestamp; 
     this.position = position; 
    } 

    public long getTimestamp() { 
     return timestamp; 
    } 

    public Position getPosition() { 
     return position; 
    } 
} 

這工作正常。

現在我想從TreeSet positionReports中刪除條目,其中timestamp比某些值舊。但我無法弄清楚正確的Java 8語法來表達這一點。

這種嘗試實際上編譯,但給了我一個新的TreeSet有一個未定義的比較:

positionReports = positionReports 
     .stream() 
     .filter(p -> p.timestamp >= oldestKept) 
     .collect(Collectors.toCollection(TreeSet::new)) 

如何表達,我想收集到一個TreeSet與像Comparator.comparingLong(PositionReport::getTimestamp)一個比較?

我還以爲像

positionReports = positionReports 
     .stream() 
     .filter(p -> p.timestamp >= oldestKept) 
     .collect(
      Collectors.toCollection(
       TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp)) 
      ) 
     ); 

但是,這並不編譯/似乎是方法引用有效的語法。

回答

58
Comparator<PositionReport> byTimestamp = 
    Comparator.comparingLong(PositionReport::getTimestamp); 

Supplier<TreeSet<PositionReport>> supplier = 
    () -> new TreeSet<PositionReport>(byTimestamp); 

positionReports = positionReports.stream() 
           .filter(p -> p.getTimeStamp() >= oldestKept) 
           .collect(Collectors.toCollection(supplier)); 
+0

非常感謝您! – tbsalling

+3

需要注意的一點是,如果TreeSet的類型(在本例中爲PositionReport)實現可比較性,則不需要比較器。 – xtrakBandit

+17

繼續使用@xtrakBandit - 再次如果您不需要指定比較器(自然排序) - 您可以使它非常簡潔:'.collect(Collectors.toCollection(TreeSet :: new));' –

6

你可以在最後轉換成SortedSet(假設你不介意附加副本)。

positionReports = positionReports 
       .stream() 
       .filter(p -> p.getTimeStamp() >= oldestKept) 
       .collect(Collectors.toSet()); 

return new TreeSet(positionReports); 
+2

你這樣做的時候一定要小心。這樣做你可能會失去元素。 就像上面提到的問題一樣,元素的自然比較器與OP想要使用的不同。所以你在初始轉換中,因爲它是一個集合,它可能會失去其他比較器可能沒有的元素(例如,第一個比較器可能會將compareTo()作爲0返回,而另一個可能不會進行某些比較。因爲這是一個集合,所以'compareTo()'爲0的那個會丟失。) – looneyGod

4

有一個方法收集這個,而不必使用流:default boolean removeIf(Predicate<? super E> filter)。見Javadoc

所以,你的代碼可能只是看起來像這樣:

positionReports.removeIf(p -> p.timestamp < oldestKept); 
7

這是很容易只需要使用下面的代碼:

positionReports = positionReports 
     .stream() 
     .filter(p -> p.timestamp >= oldestKept) 
     .collect(
      Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp) 
)));