2016-05-27 2 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 

Для каждого «элемента» У меня всегда есть Pos, Size и Collapsed и мне нужно, чтобы прочитать их.

Я хотел бы использовать, если возможно, java 8 потоков.

Можно ли моделировать поведение инструкции переключателя?

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» - это ваш собственный тип, или, может быть, «Свойства»). –

+1

Начните с отображения того, что вы хотите сделать с помощью обычного оператора switch без потока –

+0

Вопрос изменен – elect

ответ

6

Лучший способ разобрать такой файл (без использования специализированных библиотек 3 участника), осуществляется с помощью регулярных выражений 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); 
} 

Использование методов с подобной семантикой позволяет заменить их использование со стандартными методами API, когда Java 9 выпущен и становится обычным явлением.

Используя эти две операции, вы можете разобрать ваш файл, используя

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))))); 
} 

результирующее отображение m содержит всю информацию, отображение имен групп на другой карте, удерживающих пар ключ/значение, то есть вы можете напечатать эквивалентный .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

Ориентируясь на вопрос «есть ли способ, чтобы имитировать поведение переключателя заявление», я думаю, что ответ в том, что вы могли бы, с небольшим усилием. Я спросил себя, что пара лет назад, и сделал следующее в качестве упражнения (и затем снова никогда не использовал его):

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 и Consumer, создавая Predicate, который возвращает то же значение, но вызывает Consumer в качестве побочного эффекта, если значение равно true. Это становится основой для каждого «случая» в «переключателе». Каждый «случай» соединен вместе Predicate.or(), что обеспечивает короткое замыкание «else-if» характера коммутатора. Наконец, составленный Predicate превращается в Consumer путем добавления ::test к Predicate.

Применяя его к фрагмент кода, это выглядит следующим образом:

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 -> {})); 

Это примерно как переключатель-иш как он может получить без фактического выключателя в Consumer тела.

Смежные вопросы