Java 8,如何使用流实现switch语句? [英] Java 8, how can I implement a switch statement using streams?

查看:214
本文介绍了Java 8,如何使用流实现switch语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文本文件 imgui.ini 包含:

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

[ImGui Demo]
Pos = 320,5
大小= 550,680
折叠= 0

对于每个元素我总是 Pos 尺寸折叠我需要阅读它们。



如果可能,我想使用java 8流。



是否可以模拟switch语句行为?

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

...
/ *
switch(字符串){

casePos:
settings.pos = value;
休息;

caseSize:
settings.size = value;
休息;

caseCollapsed:
settings.collapsed = value;
休息;
}
* /

} catch(IOException e){
}
}


解决方案

解析此类文件(不使用专用的第三方库)的最佳方法是通过正则表达式API,以及前端类扫描仪。不幸的是,目前缺少通过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.findWithinHorizo​​n(pattern,0)!= null){
action.accept(s.match());
return true;
}
else返回false;
}
},false);
}
public static Stream< MatchResult>结果(Matcher m){
返回StreamSupport.stream(新的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返回false;
}
},false);
}

使用具有类似语义的方法允许我们用标准API替换它们的用法方法,一旦Java 9发布并变得司空见惯。



使用这两个操作,你可以使用



<解析你的文件pre> 模式groupPattern = Pattern.compile(\\ [(。*?)\\]([^ \\ [] *));
模式attrPattern = Pattern.compile((。*?)=(。*)\\v);
Map< String,Map< String,String>>米;
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));
});


I have a text file imgui.ini containing:

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

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

For each "element" I always have Pos, Size and Collapsed and I need to read them.

I would like to use, if possible, java 8 streams.

Is it possible to simulate a switch statement behaviour?

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

解决方案

The best way to parse such a file (without using dedicated 3rd party libraries), is via the regex API, and its front-end class Scanner. Unfortunately, the best operations to implement it via Stream API, are currently missing. Namely, Matcher.results() and Scanner.findAll(…) are not there yet. So unless we want to wait until Java 9, we have to create similar methods for a Java 8 compatible solution:

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

Using methods with a similar semantic allows us to replace their usage with the standard API methods, once Java 9 is released and becomes commonplace.

Using these two operations, you can parse your file using

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

the resulting map m holds all information, mapping from the group names to another map holding the key/value pairs, i.e. you can print an equivalent .ini file using:

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

这篇关于Java 8,如何使用流实现switch语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆