2016-05-27 4 views
4

私は、テキストファイルimgui.ini含む必要があります。各「要素」についてはJava 8では、ストリームを使用してswitch文を実装するにはどうすればよいですか?

[Debug] 
Pos=7,79 
Size=507,392 
Collapsed=0 

[ImGui Demo] 
Pos=320,5 
Size=550,680 
Collapsed=0 

を私はいつもPosSizeCollapsedを持っていると私はそれらを読んでする必要があります。

可能であれば、Java 8ストリームを使用したいと思います。

switch文の動作をシミュレートすることはできますか?

try (Stream<String> stream = Files.lines(Paths.get(context.io.iniFilename))) { 

     ... 
/* 
    switch(string) { 

     case "Pos": 
      settings.pos = value; 
      break; 

     case "Size": 
      settings.size = value; 
      break; 

     case "Collapsed": 
      settings.collapsed = value; 
      break; 
    } 
*/ 

    } catch (IOException e) { 
    } 
} 
+2

あなたの質問は不明です - 何を入れようとしていますか?行を読み込んで 'Map '(ここで 'ConfigurationBlock'はあなた自身の型です、あるいは' Properties'を使うかもしれません)を返すメソッドを書いてみたいかもしれません。 –

+1

ストリームのない通常のスイッチステートメントで何をしたいかを表示して開始 –

+0

質問が修正されました – elect

答えて

6

(専用のサードパーティのライブラリを使用せずに)、このようなファイルを解析するための最良の方法は、正規表現のAPIを介してであり、そのフロントエンドクラスScanner。残念ながら、Stream API経由で実装するのに最適な操作は現在ありません。すなわち、Matcher.results()Scanner.findAll(…)はまだありません。だから我々は、Java 9まで待ちたくない限り、我々は、Java 8の互換性ソリューションのための同様の方法を作成する必要があります。同様のセマンティックを持つメソッドを使用して

public static Stream<MatchResult> findAll(Scanner s, Pattern pattern) { 
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<MatchResult>(
      1000, Spliterator.ORDERED|Spliterator.NONNULL) { 
     public boolean tryAdvance(Consumer<? super MatchResult> action) { 
      if(s.findWithinHorizon(pattern, 0)!=null) { 
       action.accept(s.match()); 
       return true; 
      } 
      else return false; 
     } 
    }, false); 
} 
public static Stream<MatchResult> results(Matcher m) { 
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<MatchResult>(
      m.regionEnd()-m.regionStart(), Spliterator.ORDERED|Spliterator.NONNULL) { 
     public boolean tryAdvance(Consumer<? super MatchResult> action) { 
      if(m.find()) { 
       action.accept(m.toMatchResult()); 
       return true; 
      } 
      else return false; 
     } 
    }, false); 
} 

をJavaの後に、標準APIのメソッドとその使用法を置き換えるために私たちをことができます9がリリースされ、一般的になります。これら2つの操作を使用して

、あなたは印刷することができ、すなわち、結果のマップmは、キー/値のペアを保持し、別のマップにグループ名からマッピングをすべての情報を保持している

Pattern groupPattern=Pattern.compile("\\[(.*?)\\]([^\\[]*)"); 
Pattern attrPattern=Pattern.compile("(.*?)=(.*)\\v"); 
Map<String, Map<String, String>> m; 
try(Scanner s=new Scanner(Paths.get(context.io.iniFilename))) { 
    m = findAll(s, groupPattern).collect(Collectors.toMap(
     gm -> gm.group(1), 
     gm -> results(attrPattern.matcher(gm.group(2))) 
      .collect(Collectors.toMap(am->am.group(1), am->am.group(2))))); 
} 

を使用してファイルを解析することができます使用して同等の.iniファイル:

m.forEach((group,attr)-> { 
    System.out.println("["+group+"]"); 
    attr.forEach((key,value)->System.out.println(key+"="+value)); 
}); 
+0

ああ、そうですね、それは質問のswitch文よりも読みやすく保守的です。 –

4

試み:

try { 
     Path file = Paths.get("G:\\tmp", "img.ini"); 
     Stream<String> lines = Files.lines(file); 

     lines.filter(line->{ 
      if("pos".equalsIgnoreCase(line.split("=")[0])){ 
       //process pos line here 
       System.out.println("pos"+line); 
       return false; 
      } 
      return true; 
     }).filter(line->{ 
      System.out.println("2"+line); 
      if("Collapsed".equalsIgnoreCase(line.split("=")[0])){ 
       //process Collapsed line here 
       System.out.println("Collapsed"+line); 
       return false; 
      } 
      return true; 
     }).filter(line->{ 
      System.out.println("3"+line); 
      if("Size".equalsIgnoreCase(line.split("=")[0])){ 
       //process Size line here 
       System.out.println("Size"+line); 
       return false; 
      } 
      return true; 
     }).forEach(line->{ 
      //settings = new Settings(); 
     });; 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
1

あなたの設定ファイルを読み込むための別の方法:

public class Main { 
    public static void main(String[] args) throws IOException { 
     Path path = Paths.get("D:\\Development\\workspace\\Application\\src\\main\\resources\\init.txt"); 
     String content = new String(Files.readAllBytes(path)); 

     Map<String, Config> configMap = Stream.of(content.split("\\n\\r")) 
      .map(config -> Arrays.asList(config.split("\\r"))) 
      .collect(HashMap<String, Config>::new, (map, list) -> { 
       String header = list.get(0); 
       String pos = list.get(1); 
       String size = list.get(2); 
       String collapsed = list.get(3); 
       map.put(header, new Config(pos.substring(pos.indexOf("=") + 1), size.substring(size.indexOf("=") + 1), collapsed.substring(collapsed.indexOf("=") + 1))); 
      }, (m, u) -> {}); 

     System.out.println(configMap); 
    } 
} 

class Config { 
    public String pos; 
    public String size; 
    public String collapsed; 

    public Config(String pos, String size, String collapsed) { 
     this.pos = pos; 
     this.size = size; 
     this.collapsed = collapsed; 
    } 

    @Override 
    public String toString() { 
     return "Config{" + "pos='" + pos + '\'' + ", size='" + size + '\'' + 
       ", collapsed='" + collapsed + '\'' + '}'; 
    } 
} 

結果はマップになります。

{ 
    [Debug]=Config{pos='7,79', size='507,392', collapsed='0'}, 
    [ImGui Demo]=Config{pos='320,5', size='550,680', collapsed='0'} 
} 
+0

なぜ行末をハードコードしますか? MacまたはLinuxで動作しないようにするには?なぜパス内にスラッシュの代わりにバックスラッシュを使用するのですか?ちょうどあなたはそれらをエスケープするようになる? –

2

質問を中心に「switch文の挙動をシミュレートする方法がある」、私は答えがあると思いますが、あなたができることを少しの努力で。私は数年前という自問し、運動として以下でした(その後、再びそれを使用することはありません):

private static <T> Predicate<T> testAndConsume(Predicate<T> pred, Consumer<T> cons) { 
    return t -> { 
     boolean result = pred.test(t); 
     if (result) cons.accept(t); 
     return result; 
    }; 
} 

public static class SwitchConsumer<T> { 
    Predicate<T> conditionalConsumer; 
    private SwitchConsumer(Predicate<T> pred) { 
     conditionalConsumer = pred; 
    } 

    public static <C> SwitchConsumer<C> inCase(Predicate<C> pred, Consumer<C> cons) { 
     return new SwitchConsumer<>(testAndConsume(pred, cons)); 
    } 

    public SwitchConsumer<T> elseIf(Predicate<T> pred, Consumer<T> cons) { 
     return new SwitchConsumer<>(conditionalConsumer.or(testAndConsume(pred,cons))); 
    } 

    public Consumer<T> elseDefault(Consumer<T> cons) { 
     return testAndConsume(conditionalConsumer.negate(),cons)::test; // ::test converts Predicate to Consumer 
    } 
} 

testAndConsumeは同じ値を返しますPredicateを作成し、PredicateConsumerを構成するが、値がtrueの場合は副作用としてConsumerを呼び出します。それが「スイッチ」の各「ケース」の基礎になります。各「ケース」は、Predicate.or()でまとめられています。スイッチの短絡「else-if」の性質を提供します。最後に、PredicatePredicate::testを加えることによってConsumerに変わります。

は、あなたのコードスニペットにそれを適用すると、それは次のようになります。

それは Consumer体内で実際のスイッチなしで得ることができるように、スイッチっぽいなどについてです
Stream.of("Pos=320,5", "Size=550,680", "Collapsed=0") 
      .map(s -> s.split("=")) 
      .forEach(SwitchConsumer.<String[]> 
        inCase(arr -> "Pos".equals(arr[0]), arr -> settings.pos = arr[1]) 
        .elseIf(arr -> "Size".equals(arr[0]), arr -> settings.size = arr[1]) 
        .elseIf(arr -> "Collapsed".equals(arr[0]), arr -> settings.collapsed = arr[1]) 
        .elseDefault(arr -> {})); 

関連する問題