2016-12-08 11 views
3

私はIntegersのマップを持っています。地図の全要素を繰り返してStringに追加する必要がありますが、まずすべて結果を制限する必要がありますその後、マップの値に基づいてソートします(ソートしてから制限する方が効率的です)。Java 8ストリームAPIとラムダを使用してマップを操作する

Map<Integer, Integer> allHighScoresPerLevel=highScores.get(levelId); 
Set<Map.Entry<Integer, Integer>> sortedHighScores=allHighScoresPerLevel.entrySet() 
       .stream().limit(Configuration.MAX_HIGHSCORES_DISPLAYED) 
       .map((e)->e).sorted((o1,o2)->(o1.getValue().compareTo(o2.getValue()))) 
       .collect(Collectors.toCollection(TreeSet::new)); 

しかし、私は次の例外を取得しています:

ので、それを行うためには、私は、Java 8ストリームAPIとラムダ式を使用しています、これは私がこれまでに書いたコードは次のとおりです。

java.util.concurrent.ConcurrentHashMap$MapEntry cannot be cast to java.lang.Comparable 

私はそれを得る、マップエントリはComparableを拡張していないので、エントリをソートするには何の自然な方法はありませんが、私はspecificlyソートする方法を教えるためにソートされた方法では、コンパレータ(ラムダ)を提供していますエントリ。

だから私は2つの質問がある:

1)これを行うための正しい方法は何ですか?私は何を間違えているのですか?

2)ストリームは安全ですか?私はマルチスレッド環境で作業しているので、トレッドセーフコレクションを返すコレクタを使用する必要がありますか?

+0

'TreeSet'もソートされているので、そのコンストラクタにもコンパレータを渡す必要があります。 –

+0

しかし、最後にはCollectors.toCollection(TreeSet :: new)を使用しています。これは、すでにソートされたオブジェクトで新しいTreeSetを作成するでしょうか? – fgonzalez

+0

いいえ、 'TreeSet'は要素が挿入されているときにソートしようとします。代わりに 'List'を使うことができます。これは、要素の順序が維持されていることを保証します。 –

答えて

9

あなたはものをオーバーコンプリートしています:オブジェクトが匹敵しない限り(Map.Entrysは比較できない)、TreeSetによって並べ替えが行われない限り、TreeSetはComparatorを必要とします。

だから、(静的な輸入品との)このような何か:あなたは、コードがスレッドセーフであるかどうかを知るための十分な情報を与えられていない

Set<Entry<Integer, Integer>> sortedHighScores = allHighScoresPerLevel.entrySet().stream() 
      .limit(Configuration.MAX_HIGHSCORES_DISPLAYED) 
      .collect(toCollection(() -> new TreeSet<> (Entry.comparingByValue()))); 

- しかし、元のマップは、スレッドセーフである場合、あなたは問題ないはずです。

+0

偉大な答え、ありがとう – fgonzalez

関連する問題