有没有像“(k,v)”那样流式传输地图而不是使用(条目)?

基本上我寻找一种避免使用的方法

entry -> entry.getValue 

 entry -> entry.getKey 

类似于Map.forEach()function。

如果只有我可以得到一种工作方式map.stream().filter((k,v) -> ) …等等

看起来这个界面叫做BiConsumer。 或许转换为BiConsumer转换器或Stream.generate()

由于这是一个重复的问题,我将在环中提出完整的解决方案。 这是一个PairStream类型,默认情况下是普通Stream的简单包装器(尽管是一个interface ,替代方案是可能的)。

它着重于提供方便的中间操作和那些通过调用方法keys()values()entries()返回传统的单元素Stream并链接终端操作而不能轻易执行的终端操作。 因此,例如, PairStream.from(map).filterValue(predicate).keys().findAny()是获取映射值与谓词匹配的键的直接方式。 filterValue是一种方便的中间操作, keys返回普通Stream允许对键进行任意终端操作。

一些例子

  Map m=new HashMap<>(); m.put("foo", 5); m.put("bar", 7); m.put("baz", 42); // {b=49, f=5} Map m2=PairStream.from(m) .mapKey(s->s.charAt(0)) .toMap(Integer::sum); // foo bar String str=PairStream.from(m) .filterValue(i->i<30) .keys().sorted(Comparator.reverseOrder()) .collect(Collectors.joining(" ")); 

  Map map=new HashMap<>(); map.put("muhv~", 26); map.put("kfool", 3); String str = PairStream.from(map) .sortedByValue(Comparator.naturalOrder()) .flatMapToInt((s,i)->s.codePoints().map(c->c^i)) .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) .toString(); 

这是完整的类(我没有测试过所有操作,但大多数是直接的):

 import java.util.*; import java.util.function.*; import java.util.stream.*; public interface PairStream { static  PairStream from(Map map) { return from(map.entrySet().stream()); } static  PairStream from(Stream> s) { return ()->s; } static  PairStream from(Stream s, Function f) { return ()->s.map(k->new AbstractMap.SimpleImmutableEntry<>(k, f.apply(k))); } default PairStream distinct() { return from(entries().distinct()); } default PairStream peek(BiConsumer action) { return from(entries().peek(e->action.accept(e.getKey(), e.getValue()))); } default PairStream skip(long n) { return from(entries().skip(n)); } default PairStream limit(long maxSize) { return from(entries().limit(maxSize)); } default PairStream filterKey(Predicate mapper) { return from(entries().filter(e->mapper.test(e.getKey()))); } default PairStream filterValue(Predicate mapper) { return from(entries().filter(e->mapper.test(e.getValue()))); } default PairStream filter(BiPredicate mapper) { return from(entries().filter(e->mapper.test(e.getKey(), e.getValue()))); } default  PairStream mapKey(Function mapper) { return from(entries().map(e->new AbstractMap.SimpleImmutableEntry<>( mapper.apply(e.getKey()), e.getValue() ))); } default  PairStream mapValue(Function mapper) { return from(entries().map(e->new AbstractMap.SimpleImmutableEntry<>( e.getKey(), mapper.apply(e.getValue()) ))); } default  Stream map(BiFunction mapper) { return entries().map(e->mapper.apply(e.getKey(), e.getValue())); } default DoubleStream mapToDouble(ToDoubleBiFunction mapper) { return entries().mapToDouble(e->mapper.applyAsDouble(e.getKey(), e.getValue())); } default IntStream mapToInt(ToIntBiFunction mapper) { return entries().mapToInt(e->mapper.applyAsInt(e.getKey(), e.getValue())); } default LongStream mapToLong(ToLongBiFunction mapper) { return entries().mapToLong(e->mapper.applyAsLong(e.getKey(), e.getValue())); } default  PairStream flatMap( BiFunction> mapper) { return from(entries().flatMap( e->mapper.apply(e.getKey(), e.getValue()).entries())); } default  Stream flatMapToObj( BiFunction> mapper) { return entries().flatMap(e->mapper.apply(e.getKey(), e.getValue())); } default DoubleStream flatMapToDouble( BiFunction mapper) { return entries().flatMapToDouble(e->mapper.apply(e.getKey(), e.getValue())); } default IntStream flatMapToInt( BiFunction mapper) { return entries().flatMapToInt(e->mapper.apply(e.getKey(), e.getValue())); } default LongStream flatMapToLong( BiFunction mapper) { return entries().flatMapToLong(e->mapper.apply(e.getKey(), e.getValue())); } default PairStream sortedByKey(Comparator comparator) { return from(entries().sorted(Map.Entry.comparingByKey(comparator))); } default PairStream sortedByValue(Comparator comparator) { return from(entries().sorted(Map.Entry.comparingByValue(comparator))); } default boolean allMatch(BiPredicate predicate) { return entries().allMatch(e->predicate.test(e.getKey(), e.getValue())); } default boolean anyMatch(BiPredicate predicate) { return entries().anyMatch(e->predicate.test(e.getKey(), e.getValue())); } default boolean noneMatch(BiPredicate predicate) { return entries().noneMatch(e->predicate.test(e.getKey(), e.getValue())); } default long count() { return entries().count(); } Stream> entries(); default Stream keys() { return entries().map(Map.Entry::getKey); } default Stream values() { return entries().map(Map.Entry::getValue); } default Optional> maxByKey(Comparator comparator) { return entries().max(Map.Entry.comparingByKey(comparator)); } default Optional> maxByValue(Comparator comparator) { return entries().max(Map.Entry.comparingByValue(comparator)); } default Optional> minByKey(Comparator comparator) { return entries().min(Map.Entry.comparingByKey(comparator)); } default Optional> minByValue(Comparator comparator) { return entries().min(Map.Entry.comparingByValue(comparator)); } default void forEach(BiConsumer action) { entries().forEach(e->action.accept(e.getKey(), e.getValue())); } default void forEachOrdered(BiConsumer action) { entries().forEachOrdered(e->action.accept(e.getKey(), e.getValue())); } default Map toMap() { return entries().collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } default Map toMap(BinaryOperator valAccum) { return entries().collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, valAccum)); } } 

使用流处理地图的主要方法是流式传输地图的条目,这有点不幸。 这意味着您必须提取条目的键和值。 这有点冗长,但实际上并不是那么糟糕。 尽管如此,考虑某种辅助方法可能是合理的,这些辅助方法将适应BiPredicateBiFunction以便它们可以用于映射条目流的filtermap阶段。 它们看起来像这样:

 static  Predicate> p(BiPredicate bip) { return entry -> bip.test(entry.getKey(), entry.getValue()); } static  Function,R> m(BiFunction bif) { return entry -> bif.apply(entry.getKey(), entry.getValue()); } 

获得这些后,您可以使用它们来简化(?)地图输入流。 假设您有一个Map并且您希望选择字符串键的长度大于整数值的条目,然后将键和值格式化为字符串。 通常你会这样做:

  map.entrySet().stream() .filter(e -> e.getKey().length() > e.getValue()) .map(e -> e.getKey() + ":" + e.getValue()) .forEach(System.out::println); 

使用上面的辅助函数,您可以将此管道重写为:

  map.entrySet().stream() .filter(p((k, v) -> k.length() > v)) .map(m((k, v) -> k + ":" + v)) .forEach(System.out::println); 

好的,你保存了几个字符。 这值得么?

不,没有办法做到这一点; Stream仅适用于单个元素类型。 getKeygetValue方法getKey

(从你的角度来看,流式传输密钥和调用get实际上似乎没有任何好处,并且它可能严格降低效率。)