我有一个我想要转换和过滤的Java Map.作为一个简单的例子,假设我想将所有值转换为整数然后删除奇数条目.
Map<String, String> input = new HashMap<>();
input.put("a", "1234");
input.put("b", "2345");
input.put("c", "3456");
input.put("d", "4567");
Map<String, Integer> output = input.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> Integer.parseInt(e.getValue())
))
.entrySet().stream()
.filter(e -> e.getValue() % 2 == 0)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(output.toString());
Run Code Online (Sandbox Code Playgroud)
这是正确的,并产生: {a=1234, c=3456}
但是,我不禁想知道是否有办法避免.entrySet().stream()两次打电话.
有没有办法可以执行转换和过滤操作,.collect()最后只调用 一次?
我们知道Java 8引入了一个新的Stream API,并且java.util.stream.Collector是定义如何聚合/收集数据流的接口.
但是,Collector接口的设计如下:
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
}
Run Code Online (Sandbox Code Playgroud)
为什么它的设计不符合以下规定?
public interface Collector<T, A, R> {
A supply();
void accumulate(A accumulator, T value);
A combine(A left, A right);
R finish(A accumulator);
}
Run Code Online (Sandbox Code Playgroud)
后者更容易实现.将它设计为前者的考虑是什么?
我已经阅读过这个和这个问题,但仍然怀疑Stream.skipJDK作者是否打算观察到这种行为.
让我们简单输入数字1..20:
List<Integer> input = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
现在让我们创建一个并行流,以不同的方式结合unordered()使用skip()并收集结果:
System.out.println("skip-skip-unordered-toList: "
+ input.parallelStream().filter(x -> x > 0)
.skip(1)
.skip(1)
.unordered()
.collect(Collectors.toList()));
System.out.println("skip-unordered-skip-toList: "
+ input.parallelStream().filter(x -> x > 0)
.skip(1)
.unordered()
.skip(1)
.collect(Collectors.toList()));
System.out.println("unordered-skip-skip-toList: "
+ input.parallelStream().filter(x -> x > 0)
.unordered()
.skip(1)
.skip(1)
.collect(Collectors.toList()));
Run Code Online (Sandbox Code Playgroud)
过滤步骤在这里基本没什么,但为流引擎增加了更多的难度:现在它不知道输出的确切大小,因此关闭了一些优化.我有以下结果:
skip-skip-unordered-toList: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
// absent values: 1, 2
skip-unordered-skip-toList: …Run Code Online (Sandbox Code Playgroud) 例如,如果我打算对某些元素进行分区,我可以执行以下操作:
Stream.of("I", "Love", "Stack Overflow")
.collect(Collectors.partitioningBy(s -> s.length() > 3))
.forEach((k, v) -> System.out.println(k + " => " + v));
Run Code Online (Sandbox Code Playgroud)
哪个输出:
false => [I]
true => [Love, Stack Overflow]
Run Code Online (Sandbox Code Playgroud)
但对我partioningBy来说只是一个子问题groupingBy.虽然前者Predicate在后者a中接受as参数Function,但我只看到一个分区作为正常的分组函数.
所以相同的代码完全相同:
Stream.of("I", "Love", "Stack Overflow")
.collect(Collectors.groupingBy(s -> s.length() > 3))
.forEach((k, v) -> System.out.println(k + " => " + v));
Run Code Online (Sandbox Code Playgroud)
这也导致了Map<Boolean, List<String>>.
那么有什么理由我应该用partioningBy而不是groupingBy?谢谢
我希望能够将转换List为HashMap其中关键是elementName和值是随机的东西(在这种情况下,它的元素名称)的列表.所以总之我想要(A->List(A), B->List(B), C-> List(C)).我尝试使用toMap()并传递它keyMapper,ValueMapper但我收到编译错误.如果有人可以帮助我,我真的很感激.
谢谢!
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = Arrays.asList("A","B","C","D");
Map<String, List<String>> map = list.stream().map((element)->{
Map<String, List<String>> map = new HashMap<>();
map.put(element, Arrays.asList(element));
return map;
}).collect(??);
}
Function<Map<String, String>, String> key = (map) -> {
return map.keySet().stream().findFirst().get();
};
Function<Map<String, String>, String> value = (map) -> {
return map.values().stream().findFirst().get();
};
Run Code Online (Sandbox Code Playgroud)
=== 这对我有用
谢谢你所有的帮助!@izstas"他们应该对元素进行操作"帮了很多:).实际上这正是我想要的确切
public static void …Run Code Online (Sandbox Code Playgroud) 假设你有一个List数字.在该值List可以是类型的Integer,Double等等.当你声明这样的List有可能使用一个通配符(声明它?)或不用一个通配符.
final List<Number> numberList = Arrays.asList(1, 2, 3D);
final List<? extends Number> wildcardList = Arrays.asList(1, 2, 3D);
Run Code Online (Sandbox Code Playgroud)
所以,现在我想stream在List和collect它所有的Map使用Collectors.toMap(显然下面的代码只是为了说明问题的例子).让我们开始流式传输numberList:
final List<Number> numberList = Arrays.asList(1, 2, 3D, 4D);
numberList.stream().collect(Collectors.toMap(
// Here I can invoke "number.intValue()" - the object ("number") is treated as a Number
number -> Integer.valueOf(number.intValue()),
number -> number));
Run Code Online (Sandbox Code Playgroud)
但是,我不能对以下内容做同样的操作wildcardList:
final List<? extends Number> wildCardList …Run Code Online (Sandbox Code Playgroud) 我的一位同事向我提出了一个有趣的问题,我无法找到一个整洁而漂亮的Java 8解决方案.问题是流过POJO列表,然后根据多个属性在地图中收集它们 - 映射导致POJO多次出现
想象一下以下POJO:
private static class Customer {
public String first;
public String last;
public Customer(String first, String last) {
this.first = first;
this.last = last;
}
public String toString() {
return "Customer(" + first + " " + last + ")";
}
}
Run Code Online (Sandbox Code Playgroud)
将其设置为List<Customer>:
// The list of customers
List<Customer> customers = Arrays.asList(
new Customer("Johnny", "Puma"),
new Customer("Super", "Mac"));
Run Code Online (Sandbox Code Playgroud)
备选方案1:使用Map"流"外部(或更确切地说是外部forEach).
// Alt 1: not pretty since the resulting map is …Run Code Online (Sandbox Code Playgroud) 我有一个List<Valuta>可以表示(简化)JSON风格:
[{codice = EUR,description = Euro,ratio = 1},{codice = USD,description = Dollars,ratio = 1.1}]
我想用这样的方式改变它Map<String, Valuta>:
{EUR = {codice = EUR,description = Euro,ratio = 1},USD = {codice = USD,description = Dollars,ratio = 1.1}}
我写了这个单行:
getValute().stream().collect(Collectors.groupingBy(Valuta::getCodice));
Run Code Online (Sandbox Code Playgroud)
但这会返回一个Map<String, List<Valuta>>而不是我需要的东西.
我认为mapping()功能对我有用,但不知道如何.
它很容易转换List<V>成Map<K, List<V>>.例如:
public Map<Integer, List<String>> getMap(List<String> strings) {
return
strings.stream()
.collect(Collectors.groupingBy(String::length));
}
Run Code Online (Sandbox Code Playgroud)
但我想与自己List和Map 供应商合作.
我想出了这个:
public Map<Integer, List<String>> getMap(List<String> strings) {
return strings.stream()
.collect(Collectors.toMap(
String::length,
item -> {List<String> list = new ArrayList<>(); list.add(item); return list;},
(list1, list2) -> {list1.addAll(list2); return list1;},
HashMap::new));
}
Run Code Online (Sandbox Code Playgroud)
问题:是否有更简单,更简洁,更有效的方法?例如,像这样的东西(不起作用):
return strings.stream()
.collect(Collectors.toMap(
String::length,
ArrayList::new,
HashMap::new));
Run Code Online (Sandbox Code Playgroud)
如果我只需要定义List供应商而不是Map供应商,该怎么办?
我想List<E>从一个Map<String,List<E>>(E是一个随机类)中提取一个stream().
我想要一个使用java 8流的简单单行方法.
我到现在为止尝试过的事情:
HashMap<String,List<E>> map = new HashMap<>();
List<E> list = map.values(); // does not compile
list = map.values().stream().collect(Collectors.toList()); // does not compile
Run Code Online (Sandbox Code Playgroud) collectors ×10
java ×10
java-8 ×9
java-stream ×6
lambda ×2
collections ×1
generics ×1
grouping ×1
hashmap ×1
list ×1