我有一个很大的流管道,因此希望保持清洁.我有以下部分更大的管道
Integer defaultInt;
//...
Stream<Integer> ints;
ints.filter(/* predicate_goes_here */).collect(toSingletonIfEmptyCollector);
Run Code Online (Sandbox Code Playgroud)
凡toSingletonIfEmptyCollector被认为是作用于同一Collectors.toList()的确,如果它返回非emtpy列表,Collections.singletonList(defaultInt)如果Collectors.toList()返回空.
是否有更短的方法来实现它(例如,通过组合JDK中提供的标准收集器)而不是Collector从头开始实现所有方法?
我正在尝试重构一些代码以返回可选列表而不是可选。
我的班级有以下清单
private final List<Mapper<? extends Message>> mappers;
Run Code Online (Sandbox Code Playgroud)
有一个私有方法可以为这些映射器创建特征并返回消息列表
private List<Message> mapToFeature() {
mappers.stream()
.map(mapper -> mapper.createFeature())
.collect(Optionals.toList());
}
Run Code Online (Sandbox Code Playgroud)
Mapper 的界面如下所示:
public interface Mapper<T extends Message> {
Optional<T> createFeature();
}
Run Code Online (Sandbox Code Playgroud)
该Optionals.toList()方法返回一个收集器以将当前选项过滤到列表中。
我想更改接口(以及所有相应的类)以返回可选列表
public interface Mapper<T extends Message> {
List<Optional<T>> createFeature();
}
Run Code Online (Sandbox Code Playgroud)
我在Options util 中没有方法从多个列表中过滤当前选项。我如何能够在不对 util 类进行任何更改的情况下执行相同的操作?
JDK 16 现在toList()直接在Stream实例上包含一个方法。在以前的 Java 版本中,您总是必须使用该collect方法并提供一个Collector实例。
新方法显然需要输入更少的字符。这两种方法是否可以互换,或者是否存在应该注意的细微差别?
var newList = someCollection.stream()
.map(x -> mapX(x))
.filter(x -> filterX(x))
.toList();
// vs.
var oldList = someCollection.stream()
.map(x -> mapX(x))
.filter(x -> filterX(x))
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
(这个问题类似于会不会 Stream.toList() 比 Collectors.toList() 表现更好,但关注行为而不是(仅)关注性能。)
我实际上试图回答这个问题如何跳过从Files.lines获得的Stream <String>的行.所以我虽然这个收集器并不能很好地并行工作:
private static Collector<String, ?, List<String>> oddLines() {
int[] counter = {1};
return Collector.of(ArrayList::new,
(l, line) -> {
if (counter[0] % 2 == 1) l.add(line);
counter[0]++;
},
(l1, l2) -> {
l1.addAll(l2);
return l1;
});
}
Run Code Online (Sandbox Code Playgroud)
但它的确有效.
编辑:它实际上没有工作; 我被我的输入集太小而无法触发任何并行性这一事实所迷惑; 见评论中的讨论.
我认为这是行不通的,因为我想到了以下两个执行计划.
counter数组在所有线程之间共享.线程t1读取Stream的第一个元素,因此满足if条件.它将第一个元素添加到其列表中.然后在他有时间更新数组值之前停止执行.
线程t2,从流的第4个元素开始,将其添加到列表中.所以我们最终得到了一个非想要的元素.
当然,既然这个收藏家似乎有效,我猜它不会那样.而且无论如何更新都不是原子的.
在这种情况下,更新没有更多的问题,但没有什么能阻止线程t2不会从流的第4个元素开始.所以他也不像那样工作.
有人能解释我基本上它是如何工作的以及为什么我的收藏家在并行运行时工作?
非常感谢你!
我想计算一个流的不同元素,我想知道为什么
Stream<String> stream = Stream.of("a", "b", "a", "c", "c", "a", "a", "d");
Map<String, Integer> counter1 = stream.collect(Collectors.toMap(s -> s, 1, Integer::sum));
Run Code Online (Sandbox Code Playgroud)
不起作用.Eclipse告诉我
收集器类型中的Map(Function,Function,BinaryOperator)方法不适用于参数((s) - > {},int,Integer :: sum)
顺便说一句,我知道这个解决方案:
Map<String, Long> counter2 = stream.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
Run Code Online (Sandbox Code Playgroud)
所以我有两个问题:
编辑:我自己解决了第一个问题:
Map<String, Integer> counter1 = stream.collect(Collectors.toMap(s -> s, s -> 1, Integer::sum));
Run Code Online (Sandbox Code Playgroud)
Java期望一个函数作为第二个参数.
Javadoc说
返回将输入元素累积到新Set中的Collector.返回的Set的类型,可变性,可序列化或线程安全性无法保证; 如果需要更多地控制返回的Set,请使用toCollection(java.util.function.Supplier).
所以Collectors.toCollection(HashSet::new)在这里避免问题似乎是一个好主意(问题).
我的问题是,很难,因为我已经试过,我不能得到任何来自其他返回toSet()比HashSet
这是我使用的代码:
public static void main(String[] args) {
List<Integer> l = Arrays.asList(1,2,3);
for (int i = 0 ; i++<1_000_000;){
Class clazz = l.stream().collect(Collectors.toSet()).getClass();
if (!clazz.equals(HashSet.class)) {
System.out.println("Not a HashSet");
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么,为什么Javadoc说实际上没有保证,有......
我有一个带有项目的List,其中每个项目都是一个对象,我有一个我感兴趣的getter方法.我想在完整列表上运行以总结所有这些getter结果.
当我使用java 8流时,它看起来像这样:
double currentProduction = itemList.stream().collect(
Collectors.summingDouble((e) -> e.getProduction(param)));
Run Code Online (Sandbox Code Playgroud)
在普通的旧java中,它看起来像这样:
for (Item item : itemList) {
currentProduction += item.getProduction(param);
}
Run Code Online (Sandbox Code Playgroud)
两种方法产生完全相同的结果,但我的记录器报告,对于每个项目实例,在java 8流解决方案的情况下,getProduction()方法运行TWICE.在普通的旧java列表迭代解决方案中,getProduction方法只是按预期运行一次.
由于getProduction方法成本很高,这对我来说是一个问题.
为什么是这样?我能做些什么(除了只使用for循环)?
在java.util.stream.Stream接口中,
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
Run Code Online (Sandbox Code Playgroud)
组合器是a BiConsumer<R, R>,而在
<R, A> R collect(Collector<? super T, A, R> collector);
Run Code Online (Sandbox Code Playgroud)
组合器是一个BinaryOperator<A>只是一个BiFunction<A,A,A>.
虽然后面的形式清楚地定义了组合后组合对象的参考,但前一种形式却没有.
那么任何Stream实现库如何知道,前一种情况下的组合对象是什么?
我该如何转换:
return this.subjects.entrySet()
.stream()
.collect(Collectors.toMap(e -> getArtistryCopy(e.getKey()), Map.Entry::getValue));
Run Code Online (Sandbox Code Playgroud)
要返回 LinkedHashMap 而不是地图?
如果您需要知道,this.subjects是一个LinkedHashMap<AbstractArtistries, ArrayList<AbstractCommand>>. AbstractArtistry 和 command 是我制作的两个自定义对象。我需要维持秩序。
getArtistryCopy() 返回 AbstractArtistry 的副本(这是关键)。
关于流和collect方法,我确实对jdk11(及更高版本)的行为有疑问。我确实想获取流化资源的参数化容器的值,并最后以收集值.collect(Collectors.toSet())。
当我用编译我的代码时,jdk8它工作得很好。但由于我们也需要支持jdk11,因此我运行了编译,但由于Error:(136, 17) java: incompatible types: java.lang.Object cannot be converted to java.util.Set<org.bson.types.ObjectId>(对于openJdk11同样适用)而失败
想象以下情况。我有一个基本上是数据容器的类。该容器可以容纳单个值或值列表。
在我的应用程序的某些部分中,我确实有此容器类的列表(它也可以包含列表作为值),并且我确实希望流经列表以将容器中的所有值作为平面列表获得。
在此示例中,我选择使用objectIds列表。
// preparation
List<ObjectId> innerObjects = new ArrayList<>();
innerObjects.add(new ObjectId());
innerObjects.add(new ObjectId());
List<Diamond<Object>> diamonds = new ArrayList<>();
diamonds.add(new Diamond<Object>().value(innerObjects));
Run Code Online (Sandbox Code Playgroud)
public static class Diamond<T> {
private T value;
public Diamond<T> value(T value) {
this.value = value;
return this;
}
public T getValue() {
return this.value;
}
}
Run Code Online (Sandbox Code Playgroud)
Set<ObjectId> objectIdSet = diamonds
.stream()
.filter(diamond …Run Code Online (Sandbox Code Playgroud)