Java 使用流API过滤器和peek运算符将字符串转换为映射
我有一个输入字符串,我想把它放到HashMap中。 字符串(这不是url参数)看起来像:source=google&date=2019-01-01&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("="))
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;
}