2016-03-28 12 views
4

私は、Java-8ストリームを使用するには、この(簡体字)コードを変換しようとしている:は、ストリームを使用して条件付きでマップを移入 - Javaの8

files = reader.lines().parallel().collect((content != null)? 
       (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) :            
       (Collectors.toConcurrentMap(line->line+"null", line->line+"null"))); 
を:ここで

Map<String, String> files = new ConcurrentHashMap<String, String>(); 

while(((line = reader.readLine()) != null) { 
     if(content != null) 
     files.put("not null"+line, "not null"+line); 
     else 
     files.put("its null"+line, "its null"+line); 
    } 
reader.close(); 

は、私が試したものです

しかし、上記では、intelliJ上のすべてのメッセージについて「循環推論」メッセージを示しています。周期的推論とは何ですか?このロジックにエラーはありますか?

私はSOに関するいくつかの同様の問題に注意しました。しかし、彼らは実装の代わりにインタフェース(Map)を使うことを提案している。ただしfilesMapと宣言されています。

更新:コンテキストをさらに追加すると、contentはディレクトリ名を保持する文字列です。 filesは、複数のファイルパスを保持するマップです。どのファイルパスがfilesマップに入る必要があるかは、contentディレクトリ名が入力されているかどうかに依存します。

+1

コードサンプルは少し不明です。 (1) "content"変数とは何ですか? (2)1つのファイルの行を読み込んでいますが、それらを "files"というマップに入れていますか? –

+1

1. 'content'は、ディレクトリの名前を保持するStringです。 2。はい、私はテキストファイル(基本的にいくつかの部分トークンを含んでいます)から行を読み込み、一緒にファイルマップに入るファイルパスに追加しています。 – AshwiniR

答えて

7

この問題を解決する別の方法は、コレクタの中間変数を導入することである。

Collector<String, ?, ConcurrentMap<String, String>> collector = (content != null) ? 
     (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) : 
     (Collectors.toConcurrentMap(line->line+"null", line->line+"null")); 
Map<String, String> files = reader.lines().parallel().collect(collector);  

この溶液を(@JanXMarekによって提示された1つとは異なり)中間体アレイを割り当てず、すべての入力ラインのためcontentをチェックしません。

循環推論は、内部副表現のタイプを決定するときにタイプ推論手続きの状況であり、外部副表現のタイプを決定する必要がありますが、内部副表現のタイプを知らなくては決定できません。 Java-8の型推論では、Stream<String>.collect(Collectors.toConcurrentMap(line->line+"null", line->line+"null"))の場合、コレクタのタイプはCollector<String, ?, ConcurrentMap<String, String>>であると推論できます。通常、部分式の型(ここではtoConcurrentMap(...)の部分式について話している)を明示的に決定できないときは、外部コンテキストがメソッド呼び出し、キャストまたは代入の場合は、外部コンテキストを使用して減らすことができます。ここでは外側の文脈は?:演算子です。これは複雑な型推論規則を持っていますので、あまりにも多くなりすぎて、明示型をどこかで指定する型推論システムを助けてください。

+0

私は、あなたが動的に多くのメモリを割り当てていないので、このソリューションははるかに読みやすく効率的だと思います。 –

+0

私はこの解決策が好きですが、私は三項演算子を 'keyMapper'と' valueMapper'関数定義に移動し、 'Collectors.toConcurrentMap'でそれらを使用していたでしょう –

4

あなたは、この

reader.lines().parallel() 
    .map(line -> content == null ? 
      new String[]{"notnull"+line, line+"notnull"} : 
      new String[]{line+"null", line+"null"}) 
    .collect(Collectors.toConcurrentMap(pair -> pair[0], pair -> pair[1])); 

まず同じようにそれを行うことができますマップ(キー、値)に行配列に格納されたペア(またはペアオブジェクトのいくつかの種類で)、その後、コレクターでは、それをもう一度キーと値に分割します。

+0

ありがとう@Jan。 'pair'がString配列であることをどうやって知っていますか?私は 'toConcurrentMap()'の中で宣言すべきですか?私は.map()は文字列配列を 'pair'変数に渡すべきだと思いますが、定義されていないというエラーが出てきます。 – AshwiniR

+1

申し訳ありませんが、私は自分のコードに入力ミスを修正しました。しかし、どこにでも型を宣言する必要はありません。 Javaコンパイラは、map()操作の結果からそれを推測します。コードをコピー&ペーストするだけで済みます( "reader"と "content"変数が定義されている限り)。そうでない場合は、正確にどのようなエラーが表示されますか? –

+0

私はまだ周期的な推論が何か不思議です。誰もその上にいくつかの光を投げることができます。 – AshwiniR

1

単なるメモです。私は、この文脈で.parallel()が良いとは思っていません。標準Java APIを使用してファイルを読み取っている場合、その下のイテレーターは引き続きファイルを順次読み取ります。並行して実行されるのは、ラインを変換することだけです。私はちょうど私の好奇心のために自分のPCで試してみましたが、.parallel()がなければ約10%速くなりました。

並列化は、ストリームの入力を読み取る処理よりも処理速度が遅い場合に意味がありますが、ここではそうではありません。

+0

こんにちはJan、 parallel() '+' toConcurrentMap() '対nonparallel +' toMap() 'の組み合わせですか?非平行+ toMap()がより速く動作することが分かりましたか? – AshwiniR

+0

私はConcurrentMapに対して非並列で、入力は約100K行のファイルでした。つまり、別のハードウェアやOSで動作が異なる場合があります。この場合、システム上で並列性を10%増やすことができます。私の指摘は、.parallell()は無料のビールではないということでした。あなたが8コアのプロセッサを持っていても、いつもどこかに潜んでいるAhmdalの法則のため、実際のケースの93.73547%の非パラレルストリームよりも優れた動作をしません。 –

関連する問題