2016-11-02 5 views
7

私はちょっとしたプログラミングをしていましたが、ClassCastExceptionを見つけました。背景として、私は、問題を示すために、運動の簡易版を与えている:文字だけAまたはBキーと値として出現数などの文字でマップを計算を含む文字列を考えるとグループ化でカスタムマップサプライヤを使用しているときのClassCastException

。さらに、マップには必ず両方の文字がキーとして含まれている必要があります(文字が入力文字列にない場合は値がゼロ)。

例:

  • "A" => {A=1, B=0}
  • "AAB" => {A=2, B=1}

私の最初のソリューションは、以下ました:

import static java.util.stream.Collectors.counting; 
import static java.util.stream.Collectors.groupingBy; 

public Map<Character, Long> createResult(String input) { 
    Map<Character, Long> map = input.chars() 
     .mapToObj(c -> (char) c) 
     .collect(groupingBy(c -> c, counting())); 

    map.putIfAbsent('A', 0L); 
    map.putIfAbsent('B', 0L); 
    return map; 
} 

このソリューションでは、働いていたが、私はそれがあった場合は試してみたかったですpos入力AcreateResult2を呼び出すとき

public HashMap<Character, Long> createResult2(String input) { 
    return input.chars() 
     .mapToObj(c -> (char) c) 
     .collect(groupingBy(c -> c, this::mapFactory, counting())); 
} 

private HashMap<Character, Long> mapFactory() { 
    HashMap<Character, Long> map = new HashMap<>(); 
    map.put('A', 0L); 
    map.put('B', 0L); 
    return map; 
} 

ClassCastExceptionは、実行時にスローされます:groupingBy関数にデフォルト値を使用してマップを供給するsible

 
java.lang.ClassCastException: java.lang.Long cannot be cast to [Ljava.lang.Object; 
    at java.util.stream.Collectors.lambda$groupingBy$45(Collectors.java:909) 
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) 
    at java.util.stream.IntPipeline$4$1.accept(IntPipeline.java:250) 
    at java.lang.CharSequence$1CharIterator.forEachRemaining(CharSequence.java:149) 
    at java.util.Spliterators$IntIteratorSpliterator.forEachRemaining(Spliterators.java:1908) 
    at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693) 
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) 
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) 
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) 
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) 
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) 

なぜこれが起こっている誰もが説明できますか?

+0

ストリームは、この単純な問題のために過剰なもののように見えます。さらに悪いことに、stacktraceには*あなたの*コードがエラーを引き起こした場所については何も含まれていません。それが私には単純なループを使用するのに十分な理由です。 –

+0

stacktraceの最後の行は、自分のコードスニペットの 'collect'呼び出しに対応しています。 – eee

+1

@LutzHornこの質問はなぜこれが起こっているのか、そしてエクササイズを解決する方法については詳しくありません。 – eee

答えて

0

なぜ単純なループではないのですか?

private static Map<Character, Integer> count(String input) { 
    Map<Character, Integer> result = new HashMap<>(); 
    result.put('A', 0); 
    result.put('B', 0); 
    for (Character c : input.toCharArray()) { 
     result.put(c, result.get(c) + 1); 
    } 
    return result; 
} 
+0

遅いです。 'result.put(c、result.get(c)+ 1); 'を' result.merge(c、1、...)'に置き換えて、文字ごとにマップへのアクセスを2回取る( 'get' +' put') – talex

+4

@ Integer :: sum); '問題が解決されました。マップをゼロで事前に初期化していないときは、さらに効率的ですが、 'map.putIfAbsent( 'A'、0L);を実行してください。 map.putIfAbsent( 'B'、0L); 'その後、質問のように。 – Holger

2

あり関与推論魔法型ですが、解決策をしたい場合はここにある:

私は強くあなたのを阻止

map.put('A', new Object[]{0L}); 
map.put('B', new Object[]{0L}); 

しかしによって

map.put('A', 0L); 
map.put('B', 0L); 

を交換してください実際にはこのソリューションを使用して。実装の詳細はすべてのアップデートで変更でき、このハック・ストップが機能します。 groupingBy javadocの

mapFactoryから "なぜ" についてここで

以上説明 - と呼ばれる、機能、所望のタイプ

mapFactoryの新しい空の地図は二番目のパラメータで生成されます。単語 "空"は非常に重要です。実装では、作成したマップを使用してlongの配列を格納し、反復してlongに変換します。それは内部に大量の鋳物があるために機能します。

+2

'new Object [] {0L}'でそのことをしないでください。 Java 9では、代わりに 'long []'を使用して、カウント中にボクシングオーバーヘッドを避けますが、他の実装では他の実装でも他の一時的なコンテナの種類... – Holger

+0

@Holgerはもっと同意できません。実際に私のソリューションを使用することは悪い考えです。 – talex

+0

純粋に冗談を言った。また、明示的なキャスティングがたくさんあります。ランタイムの観点からは違いはありませんが、コードの品質は悪い設計です。私はあなたのリンクを見て、それが私の答えより良い状況を説明することに同意します。 – talex

関連する問題