Java 使用流API过滤器和peek运算符将字符串转换为映射

Java 使用流API过滤器和peek运算符将字符串转换为映射,java,string,java-stream,Java,String,Java Stream,我有一个输入字符串,我想把它放到HashMap中。 字符串(这不是url参数)看起来像:source=google&date=2019-01-01& public Map<String, String> extract(String source) { return Arrays.stream(source.split("&")) .map(s -> s.trim().split("="))

我有一个输入字符串,我想把它放到HashMap中。 字符串(这不是url参数)看起来像:source=google&date=2019-01-01&

public Map<String, String> extract(String source) {
   return Arrays.stream(source.split("&"))
           .map(s -> s.trim().split("="))
           .peek(pairs -> pairs[0] = convert(pairs[0])
           .filter(this::isValid)
           .collect(Collectors.toMap(
                   key -> key[0],
                   value -> value[1],
                   (val1, val2) -> val2)
           );
}

private boolean isValid(String[] strings) {
        return strings.length == 2
                && !strings[0].isBlank()
                && !strings[1].isBlank();
    }

它可以正常工作,但现在如果字符串无法拆分为包含2个元素的数组,例如:
源活动和日期…
它将抛出ArrayIndexOutOfBoundException,因为
字符串[1]
不存在。因此,我将
过滤器
移到
peek
上方:

.filter(this::isValid)
.peek(pairs -> pairs[0] = convert(pairs[0])
         
现在字符串
source campaign&date…
将无法通过过滤器,但这里还有另一个问题。 方法
convert
可以返回空字符串“”,我应该过滤它们。这就是为什么过滤器在peek操作员之后。我可以用两个过滤器来解决它,如下所示:

.map(s -> s.trim().split("="))
.filter(strings -> strings.length==2)
.peek(this::removeWhiteSpaces)
.filter(strings -> !strings[0].isBlank() && !strings[1].isBlank())
.collect(..)
但是我可以用一个过滤器吗?也许我的流链一点也不好

UPD
转换
方法:

private String convert(String string) {
   return conversionTable.getOrDefault(string, ""); //map with key/values
}

使用@Holger建议剥离空白,您只需处理字符串[]长度为0、1或2的输入数据,该字符串由过滤器处理,并更改为收集器
value->value.length<2?“”:值[1]

public Map<String, String> extract(String source) {
    return Arrays.stream(source.split("\\s*&\\s*"))
            .map(s -> s.trim().split("\\s*=\\s*")) // String[0..2] based on your input
            //.peek(a -> System.out.println(Arrays.toString(a)))
            .filter(a -> a.length > 0 && a[0].length() > 0)
            .collect(Collectors.toMap(
                    key -> key[0],
                    value -> value.length < 2 ? "" : value[1],
                    (val1, val2) -> val2)
            );

}
    System.out.println("1="+u.extract("      &source=google&date=2019-01-01&name1=value1&=&&       &  =   &flag2&arg=v"));
    System.out.println("2="+u.extract("   source = google&date=2019-01-01&flag3  & name1 = value1&flag2 &arg=v&flag4"));
如果要映射键并剥离未识别的条目,可以在collect()之前添加此项:

其中转换为:

private String[] convert(String[] arr) {
    arr[0] = conversionTable.getOrDefault(arr[0], null);

    return arr[0] != null ? arr : null;
}

是否要删除结果中的任何空格或前导空格?
空白这是字符串空白
应该是
这是字符串
。同时用于键和值(按=)拆分)。你说结果是
[source=google,…]
为什么不
[source=google,…
你想
返回Arrays.stream(source.split(&”).map(s->Arrays.stream(s.split(=).map(String::trim).toArray(String[]::new)).filter(此::有效)。collect(Collectors.toMap(x->x[0],x->x[1]);
在五年前被要求回答这个问题。除此之外,为什么不使用
.split(\\s*&\\s*”)
.split(\\s*=\\s*)
首先,不要在额外的操作中删除空格?感谢您建议使用另一个正则表达式进行拆分,但我还需要转换数组的第一个元素,然后检查转换后的元素是否为空。我在上次编辑中添加的过滤器应该处理空格,如“&=&=&=&”我的
convert
方法从数组中获取第一个元素,例如:
source=google
(拆分后的第一个元素是
source
).Method应返回
ga:source
,然后检查
ga:source
是否为空,因为如果转换字符串的方法无法转换它,则返回空字符串。例如
sour=google
sourc
无效,然后
convert
方法在此处返回
空字符串,然后过滤器应勾选这个新字符串并跳过这个元素。所以在检查数组中的第一个元素是否为空之前,我应该转换它。
1={date=2019-01-01, arg=v, flag2=, source=google, name1=value1}
2={date=2019-01-01, flag4=, arg=v, flag3=, flag2=, source=google, name1=value1}
 .map(this::convert)
 .filter(Objects::nonNull)
private String[] convert(String[] arr) {
    arr[0] = conversionTable.getOrDefault(arr[0], null);

    return arr[0] != null ? arr : null;
}