我必须编写一些代码,将Java 8 Stream的内容多次添加到List中,而且我很难弄清楚最好的方法是什么.基于我在SO上阅读的内容(主要是这个问题:如何将Java8流的元素添加到现有List中)和其他地方,我将其缩小到以下选项:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Accumulator<S, T> {
private final Function<S, T> transformation;
private final List<T> internalList = new ArrayList<T>();
public Accumulator(Function<S, T> transformation) {
this.transformation = transformation;
}
public void option1(List<S> newBatch) {
internalList.addAll(newBatch.stream().map(transformation).collect(Collectors.toList()));
}
public void option2(List<S> newBatch) {
newBatch.stream().map(transformation).forEach(internalList::add);
}
}
Run Code Online (Sandbox Code Playgroud)
我们的想法是,对于同一个实例,将多次调用这些方法Accumulator.选择是在使用中间列表和Collection.addAll()在流外部调用一次还是collection.add()从流中为每个元素调用之间.
我倾向于更喜欢选项2,这更符合函数式编程的精神,并且避免创建中间列表,但是,当n很大时调用addAll()而不是调用add()n次可能有好处.
两种选择中的一种明显优于另一种吗?
编辑:JB Nizet有一个非常酷的答案,延迟转换,直到所有批次都添加.在我的情况下,需要直接执行转换.
PS:在我的示例代码中,我用作transformation占位符,用于需要在流上执行的任何操作
给定一组文件名:
bigList = Arrays.stream(files)
.flatMap(file - > {
try {
return Files.lines(Paths.get(path + SEPARATOR + file));
} catch (IOException e) {
LOGGER.log(Level.WARNING, "No se puede encontrar el archivo " + file);
}
return null;
})
.filter(str - > str.startsWith("ABC"))
.distinct()
.map(Mapper::mapToObj)
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
当我使用传统的for循环时(而不是Arrays.stream(..).flatMap(..)),这会返回不同的输出
for (String file: files) {
bigList.addAll(Files.lines(Paths.get(path + SEPARATOR + file))
.filter(str - > str.startsWith("ABC"))
.distinct()
.map(Mapper::mapToObj)
.collect(Collectors.toList()));
}
Run Code Online (Sandbox Code Playgroud)
为什么会这样?
提前致谢
干杯
我有这个代码:
Set<String> namesSet = new HashSet<>();
@Override
public boolean isValid(List<String> input) {
input.stream().map(item -> namesSet.add(item));
return namesSet.size() == input.size();
}
Run Code Online (Sandbox Code Playgroud)
input 是一个包含一个项目的列表.
为什么这个项目没有被添加到namesSet之后stream::map呢?
这里更新是我的修复:
Set<String> namesSet;
@Override
public boolean isValid(List<String> input) {
namesSet = new HashSet<>();
input.stream().forEach(item -> namesSet.add(item));
return namesSet.size() == input.size();
}
Run Code Online (Sandbox Code Playgroud) 假设我有两个具有相似但不一定相同内容的流.如何找到两者之间不同的第一个项目.例如,假设我有:
Stream<String> first = Arrays.asList("a", "b", "c").stream();
Stream<String> second = Arrays.asList("a", "x", "c").stream ();
Run Code Online (Sandbox Code Playgroud)
如何确定"b"和"x"是流不同的第一个项目?如果其中一个流被截断呢?
我有一个Map<String, String>我想转换为Map<Type1,Type2>使用Java流的.
这是我尝试过但我认为我的语法错误:
myMap.entrySet()
.stream()
.collect(Collectors.toMap(e -> Type1::new Type1(e.getKey()), e -> Type2::new Type2(e.getValue))));
Run Code Online (Sandbox Code Playgroud)
也试过了
myMap.entrySet()
.stream()
.collect(Collectors.toMap(new Type1(Map.Entry::getKey), new Type2(Map.Entry::getValue));
Run Code Online (Sandbox Code Playgroud)
但我只是继续运行编译错误.我该如何改造?
如何流式传输Map<String, List<String>>获取:
甲List<String>所有的String的值s List的第Map它们比5个字符?如何长期计算这些?
甲Map<String, List<String>>其中密钥保持不变,但List小号仅由String长度大于5号第?
A 在每张地图的密钥中有多于5的Map<String, Long>计数?StringList
我开始做的事情但我被困住了:
long l = map.entrySet().stream()
.filter(m -> m.getValue().stream().filter(s -> s.length() > 5)
Run Code Online (Sandbox Code Playgroud)
谢谢
我有一个用户List<User>"abc" 的列表.
class User {
int id;
String name;
String address;
.....//getters and setters
}
Run Code Online (Sandbox Code Playgroud)
我只需要从中提取名称和地址List<User>并保存到另一个新的列表对象List<User>"xyz".或者一些新的列表,它有两个字符串字段的名称和地址.例如:
class SomeClass {
String name;
String address;
........//getters and setters
}
Run Code Online (Sandbox Code Playgroud)
我知道可以通过迭代原始列表并保存到另一个新列表对象来完成.但我想知道如何Java 8更有效地完成它.通过使用streams(),map()...等使用默认构造函数.
我正在慢慢学习Java 8的新功能,并试图找到一种以流方式处理类层次结构(从子级到父级)的方法。
例如,在类或其父级上找到注释。
在Java 8之前,我会这样完成:
public static <T extends Annotation> T getAnnonationOn(Class<?> type, Class<T> annType) {
Class<?> t = type;
T annot = null;
while (t != null && annot == null) {
annot = t.getAnnotation(annType);
t = t.getSuperclass();
}
return annot;
}
Run Code Online (Sandbox Code Playgroud)
现在,我希望以一种更加“功能性的编程”方式来做到这一点。我找不到比使用以下递归连接流更好的方法:
import java.lang.annotation.Annotation;
import java.util.stream.Stream;
public static <T extends Annotation> T getAnnonationOn(Class<?> type, Class<T> annType) {
return ClassIterator.streamSuperclass(type)
.map(t -> t.getAnnotation(annType))
.filter(a -> a != null)
.findFirst()
.orElse(null);
}
public static class ClassIterator {
public static Stream<Class<?>> …Run Code Online (Sandbox Code Playgroud) 我想从流中收集前n个元素,而不是遍历整个事物.是否有标准方法可以做到这一点?翼
MyList.stream()
.filter(x -> predicate(x))
.findFirstN(100)
Run Code Online (Sandbox Code Playgroud)
会从流中返回最多100个元素的集合吗?我的另一种方法是评估整个流,然后从结果中进行采样,但这并没有利用流固有的惰性评估.
我是Java的新手,所以如果已经在其他地方回答了这个问题,那么我要么不知道搜索正确的内容还是我无法理解答案.
所以问题是:我在列表中有一堆对象:
try(Stream<String> logs = Files.lines(Paths.get(args))) {
return logs.map(LogLine::parseLine).collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)
这就是添加属性的方式:
LogLine line = new LogLine();
line.setUri(matcher.group("uri"));
line.setrequestDuration(matcher.group("requestDuration"));
....
Run Code Online (Sandbox Code Playgroud)
如何对日志进行排序,以便最终得到列表,其中具有相同"uri"的对象仅以平均requestDuration显示一次.
例:
object1.uri = 'uri1', object1.requestDuration = 20;
object2.uri = 'uri2', object2.requestDuration = 30;
object3.uri = 'uri1', object3.requestDuration = 50;
Run Code Online (Sandbox Code Playgroud)
结果:
object1.uri = 'uri1', 35;
object2.uri = 'uri2', 30;
Run Code Online (Sandbox Code Playgroud)
提前致谢!
java-stream ×10
java-8 ×9
java ×7
collections ×3
average ×1
hashmap ×1
list ×1
reflection ×1
sorting ×1