上下文:给定一个目录,我想在列表中列出其名称中包含模式的所有文件,按lastModified时间戳排序,并将此列表格式化为Json字符串,我将获取每个文件的名称和时间戳:
[{"name": "somefile.txt", "timestamp": 123456},
{"name": "otherfile.txt", "timestamp": 456789}]
Run Code Online (Sandbox Code Playgroud)
我有以下代码:
private StringBuilder jsonFileTimestamp(File file) {
return new StringBuilder("{\"name\":\"")
.append(file.getName())
.append("\", \"timestamp\":")
.append(file.lastModified())
.append("}");
}
public String getJsonString(String path, String pattern, int skip, int limit) throws IOException {
return Files.list(Paths.get(path))
.map(Path::toFile)
.filter(file -> {
return file.getName().contains(pattern);
})
.sorted((f1, f2) -> {
return Long.compare(f2.lastModified(), f1.lastModified());
})
.skip(skip)
.limit(limit)
.map(f -> jsonFileTimestamp(f))
.collect(Collectors.joining(",", "[", "]"));
}
Run Code Online (Sandbox Code Playgroud)
这很好用.我只关心StringBuilder实例化(或字符串连接)的性能.只要文件数量很少就可以了(这是我的情况,所以我很好),但我很好奇:你会建议什么作为优化?我觉得我应该使用reduce正确的累加器和组合器,但我不能让我的大脑围绕它.
谢谢.
我终于进行了以下"优化":
private StringBuilder jsonFileTimestampRefactored(StringBuilder res, File file) {
return res.append(res.length() …Run Code Online (Sandbox Code Playgroud) 我有Flyweight模式,我尝试将循环转换为流,但结果是不同的:
public Line getLine(Color color) {
for(Line line: pool) {
if(line.getColor().equals(color)) {
return line;
}
}
return createLine(color);
}
factory.getLine(Color.RED);
factory.getLine(Color.RED);
System.out.println(getPool().size()); // print 1
Run Code Online (Sandbox Code Playgroud)
重构代码:
public Line getLine(Color color) {
return pool.stream()
.filter(l -> l.getColor().equals(color))
.findFirst()
.orElse(createLine(color));
}
factory.getLine(Color.RED);
factory.getLine(Color.RED);
System.out.println(getPool().size()); // print 2
Run Code Online (Sandbox Code Playgroud)
流有什么问题?
老实说,除了相邻的代码行之外,我还不确定这是否可行.但是,我想我会和社区核实一下.
Java 8允许通过Stream API管理其集合.我们以前需要外部迭代的地方,现在我们可以简单地使用:
<Collection>.stream().forEach([expression]);
Run Code Online (Sandbox Code Playgroud)
当我尝试快速格式化大型集合时,这很好,比如,将它输出到BufferedOutputStream或其他目标.我需要做的是在我旁边写一些关于我正在写的内容的信息.到目前为止,我能想到的最好的是:
labelData();
firstNames.stream().sequential().forEach(sz -> reportData(sz));
Run Code Online (Sandbox Code Playgroud)
然而,如果我可以这样的话,那将是非常好的:
firstNames.stream().sequential().
.onOpen(labelData())
.forEach(sz->reportData(sz));
Run Code Online (Sandbox Code Playgroud)
我知道可以使用BaseStream.onClose(Runnable closeHandler)设置一个on-close方法.这种方法是否存在开放?
谢谢你的时间.
假设我有两个类C1和C2,其中C2由C1的构造函数使用:
public class C1
{
public C1( C2 o2 ){ ... }
public String getProperty()
{
String result;
...
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我有了一个C2对象列表(列表列表),我想使用从流C2对象创建的C1的getProperty()上的条件来流式传输和过滤。
有没有办法用流来做到这一点?
List<C2> list = ...
List<C2> result = list.stream().filter( XXXX )
Run Code Online (Sandbox Code Playgroud)
我猜我应该有XXXX,它使用流中的C2对象创建一个C1对象并比较其getProperty()(例如,“ value” .equals(o2.getProperty()))
这有可能吗?
这是如何从字节数组创建IntStream的后续问题?
我创建了一个方法将给定的字节数组转换为连接的十六进制字符
static String bytesToHex(final byte[] bytes) {
return IntStream.rang(0, bytes.length * 2)
.map(i -> (bytes[i / 2] >> ((i & 0x01) == 0 ? 4 : 0)) & 0x0F)
.mapToObj(Integer::toHexString)
.collect(joining());
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,不使用任何第三方库,上面的代码是否足够有效?我做错了什么或不必要的吗?
在阅读了关于流的内容后,我现在尝试使用它们,并且已经通过简单的示例出现了第一个问题.我想实现一个非常简单的加密算法,它使用替换.有一些文本需要加密:
static List<Integer> text = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
Run Code Online (Sandbox Code Playgroud)
有一些密码:
private List<Integer> password = Arrays.asList(1, 5, 7, 3);
Run Code Online (Sandbox Code Playgroud)
现在的想法是将密码值添加到文本值.结果应该是
1 + 1,2 + 5,3 + 7,4 + 3,5 + 1,6 + 5 ......
所以我必须从密码创建一个流,它从到达上面列表末尾的开头开始.这部分我已经设法做到了.
现在我不得不将2个流合并为1个流.任何想法,如何实现?
在stream().filter().map()列表上有一个类似的数据结构,List<List<Object>>如下所示:
[["1","a",20],
["1","b",10],
["2","a",10],
["2","b",30]]
Run Code Online (Sandbox Code Playgroud)
我想要的是按内部列表的第一个元素的值进行分组,保留中间元素,最后将每个"组"的最后元素相加.
[["1", 30],
["2", 40]]
Run Code Online (Sandbox Code Playgroud)
对不起,如果这对你们中的一些人来说很明显,但我还没有找到如何实现这一目标的任何例子.我假设它可以通过Stream.reduce(U身份,BiFunction累加器,BinaryOperator组合器)来完成,但到目前为止我还没有成功.如果有人可以为此提供一些示例代码,我相信它也会受到许多其他人的赞赏.
想象一下,通过回调或InputStream您需要不断转换为Java 8的某种传入数据Stream.我们不知道传入的数据流何时停止,但我们知道它可以停止.
到目前为止,我已经看到了解决这个问题的两种方法,我对如何实现这一目标的最佳实践感兴趣.主要是因为我必须是某人以前面对的事情.必须有比下面的想法更简单的方法.
1)最简单的方法是将源视为a Supplier并仅用于Stream.generate提供数据:
Stream.generate(() -> blockCallToGetData());
Run Code Online (Sandbox Code Playgroud)
然而,这具有缺点,即流永远不会结束.因此,只要输入源停止发送,流就会一直调用该方法.除非我们自然地抛出一个Runtime异常,但这可能会变得很难看.
2)第二个想法是使用a Iterator(转换为a Spliterator)next方法阻塞,直到我们找到下一个元素.作为一个粗略的例子:
class BlockingIterator implements Iterator<Data> {
@Override void boolean hasNext() {
return true;
}
@Override Data next() {
return blockCallToGetData();
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的好处是,我可以通过返回停止流false的hasNext方法.但是,在我们不控制传入数据速度的情况下(例如在回调中),我们需要为迭代器保留一个就绪元素的缓冲区.在有人调用next迭代器之前,这个缓冲区可能会变得无限大.
所以,我的问题是; 将阻塞输入提供给流的最佳做法是什么?
当我最初问这个问题,2015年2月,在报道的行为所链接的问题是反直觉的,但那种规范允许(尽管在文档一些小的矛盾).
然而,Tagir Valeev在2015年6月问了一个新问题,我认为他清楚地证明了这个问题中报告的行为实际上是一个错误.Brain Goetz回答了他的问题,并承认,当一个终端操作触发时,不会阻止on 的特性的反向传播是一个错误,这个终端操作不会被迫尊重元素的遭遇顺序(例如) .此外,在他自己的回答的评论中,他分享了JDK的错误跟踪系统中发布的问题的链接.UNORDEREDStreamskip()forEach()
该问题的状态现已解决,其修复版本为9,这意味着该修复程序将在JDK9中可用.但是,它也被反向移植到JDK8 update 60,build 22.
所以从JDK8u60-b22开始,这个问题再也没有意义了,因为现在skip()表现得像直觉一样,甚至在并行流上也是如此.
我原来的问题是......
最近我和一些同事讨论了这件事.我说skip()在并行流上使用它是没用的,因为它似乎没有一个很好的用例.他们告诉我有关性能提升,FJ池处理,jvm可用的核心数量等等,但他们无法给我任何实际的使用示例.
skip()并行流是否存在良好的用例?
使用Java 8+,您可以轻松找到与a匹配的集合的所有元素Predicate.
someCollection.stream().filter(somePredicate)
Run Code Online (Sandbox Code Playgroud)
然后你可以找到第一个元素:
someCollection.stream().filter(somePredicate).findFirst()
Run Code Online (Sandbox Code Playgroud)
但问题是,它会Predicate针对所有元素运行.有没有一种干净的方法只能运行Predicate反对元素,直到找到第一个匹配,然后返回它,就像它一样anyMatch(但返回一个boolean告知是否找到一个)?
java-stream ×10
java-8 ×9
java ×6
lambda ×3
filtering ×1
for-loop ×1
handler ×1
hex ×1
optimization ×1
parsing ×1
performance ×1
predicate ×1
reduce ×1
theory ×1