我正在寻找可以使收集流,但是是安全的方法.如果collection为null,则返回空流.像这样:
Utils.nullSafeStream(collection).filter(...);
Run Code Online (Sandbox Code Playgroud)
我创建了自己的方法:
public static <T> Stream<T> nullSafeStream(Collection<T> collection) {
if (collection == null) {
return Stream.empty();
}
return collection.stream();
}
Run Code Online (Sandbox Code Playgroud)
但我很好奇,如果标准JDK中有这样的东西?
我可以想到两种方式:
public static IntStream foo(List<Integer> list)
{
return list.stream().mapToInt(Integer::valueOf);
}
public static IntStream bar(List<Integer> list)
{
return list.stream().mapToInt(x -> x);
}
Run Code Online (Sandbox Code Playgroud)
什么是惯用的方式?也许已经有一个库函数完全符合我的要求?
我的确切方案是批量插入数据库,所以我想累积DOM对象然后每1000个,刷新它们.
我通过将代码放入累加器来检测丰满度然后刷新来实现它,但这似乎是错误的 - 刷新控件应该来自调用者.
我可以将流转换为List然后以迭代方式使用subList,但这似乎也很笨拙.
有一个简洁的方法来处理每n个元素然后继续流,而只处理流一次?
使用以下结构是否存在差异,除了后者的可读性稍好一些?
someList.stream().map(item -> new NewClass(item)).collect(Collectors.toList());
someList.stream().map(NewClass::new).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud) 我有一个List<Users>.我想用特定的用户名获取流中(第一个)用户的索引.我不想竟要求User将.equals()一些描述User,只是为了有相同的用户名.
我可以想到这样做的丑陋方法(迭代和计数),但感觉应该有一个很好的方法来做到这一点,可能是通过使用Streams.到目前为止,我所拥有的最好的是:
int index = users.stream()
.map(user -> user.getName())
.collect(Collectors.toList())
.indexOf(username);
Run Code Online (Sandbox Code Playgroud)
这不是我写过的最糟糕的代码,但它并不好.它也不是那么灵活,因为它依赖于一个带有.equals()描述你正在寻找的属性的函数的类型的映射函数; 我宁愿有一些可以随心所欲的东西Function<T, Boolean>
谁知道怎么样?
请参阅下面的简单示例,该示例计算列表中每个单词的出现次数:
Stream<String> words = Stream.of("a", "b", "a", "c");
Map<String, Integer> wordsCount = words.collect(toMap(s -> s, s -> 1,
(i, j) -> i + j));
Run Code Online (Sandbox Code Playgroud)
最后,wordsCount是{a=2, b=1, c=1}.
但我的流非常大,我想要并行工作,所以我写道:
Map<String, Integer> wordsCount = words.parallel()
.collect(toMap(s -> s, s -> 1,
(i, j) -> i + j));
Run Code Online (Sandbox Code Playgroud)
但是我注意到这wordsCount很简单HashMap所以我想知道我是否需要明确要求并发映射以确保线程安全:
Map<String, Integer> wordsCount = words.parallel()
.collect(toConcurrentMap(s -> s, s -> 1,
(i, j) -> i + j));
Run Code Online (Sandbox Code Playgroud)
非并发收集器是否可以安全地与并行流一起使用,还是在从并行流收集时只应使用并发版本?
在Java 8中,这适用于:
Stream<Class> stream = Stream.of(ArrayList.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Run Code Online (Sandbox Code Playgroud)
但这不是:
Stream<Class> stream = Stream.of(List.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Run Code Online (Sandbox Code Playgroud)
Maps允许null键,List.class.getSuperclass()返回null.但Collectors.grouping可以在Collectors.java第907行发出NPE:
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
Run Code Online (Sandbox Code Playgroud)
如果我创建自己的收集器,它的工作原理改为:
K key = classifier.apply(t);
Run Code Online (Sandbox Code Playgroud)
我的问题是:
1)Collectors的Javadoc.GroupingBy并没有说它不应该映射一个空键.出于某种原因这种行为是否必要?
2)是否有另一种更简单的方法来接受一个空键,而不必创建我自己的收集器?
哦,那些棘手的Java 8流与lambdas.它们非常强大,但错综复杂需要一点点围绕它的所有.
假设我有User一个属性类型User.getName().假设我有一个Map<String, User>与名称相关联的用户的地图(例如,登录用户名).让我们进一步说,我有一个比较器的实例UserNameComparator.INSTANCE来排序用户名(可能与花哨的合作者等).
那么如何获取地图中的用户列表,按用户名排序?我可以忽略地图键并执行此操作:
return userMap.values()
.stream()
.sorted((u1, u2) -> {
return UserNameComparator.INSTANCE.compare(u1.getName(), u2.getName());
})
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
但是,我必须提取名称以使用的那一行UserNameComparator.INSTANCE似乎太多的手工工作.有什么方法我可以简单地提供User::getName一些映射函数,只是为了排序,并仍然将User实例返回到收集列表中?
额外奖励:如果我想要排序的东西是两个层次,如User.getProfile().getUsername()?
我有这个代码:
List<String> strings = Arrays.asList("a", "b", "cc");
for (String s : strings) {
if (s.length() == 2)
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
我想用过滤器和lambda来编写它:
for (String s : strings.stream().filter(s->s.length() == 2)) {
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
我得到Can only iterate over an array or an instance of java.lang.Iterable.
我尝试:
for (String s : strings.stream().filter(s->s.length() == 2).iterator()) {
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
我得到了同样的错误.这甚至可能吗?我真的不想做stream.forEach()并传递消费者.
编辑:对我来说重要的是不要复制元素.
在Java中,可以轻松地生成无限流Stream.generate(supplier).但是,我需要生成一个最终完成的流.
想象一下,例如,我想要一个目录中所有文件的流.文件数量可能很大,因此我无法预先收集所有数据并从中创建流(via collection.stream()).我需要逐个生成序列.但是流很明显会在某个时刻完成,终端运营商喜欢(collect()或findAny())需要对它进行处理,因此Stream.generate(supplier)不适合这里.
有没有合理的简单方法在Java中执行此操作,而不是自己实现整个Stream接口?
我可以想到一个简单的黑客 - 用无限做它Stream.generate(supplier),并在获取所有实际值时提供null或抛出异常.但是它会破坏标准的流操作符,我只能将它用于我自己的操作符,这些操作符都知道这种行为.
澄清
评论中的人提议我takeWhile()操作员.这不是我的意思.如何更好地表达问题...我不是在问如何过滤(或限制)现有的流,我问如何动态创建(生成)流,而不是先加载所有元素,但是流会有有限的大小(事先未知).
解
我正在寻找的代码是
Iterator it = myCustomIteratorThatGeneratesTheSequence();
StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);
Run Code Online (Sandbox Code Playgroud)
我刚看了一下java.nio.file.Files,该list(path)方法是如何实现的.
java ×10
java-8 ×10
java-stream ×10
lambda ×3
collections ×2
boxing ×1
chunking ×1
collectors ×1
concurrency ×1
foreach ×1
hashmap ×1
null ×1
sorting ×1