与C#不同IEnumerable
,执行管道可以根据需要执行多次,在Java中,流只能"迭代"一次.
对终端操作的任何调用都会关闭流,使其无法使用.这个"功能"消耗了很多力量.
我想这个的原因不是技术性的.这个奇怪限制背后的设计考虑是什么?
编辑:为了演示我在说什么,请考虑以下C#中的Quick-Sort实现:
IEnumerable<int> QuickSort(IEnumerable<int> ints)
{
if (!ints.Any()) {
return Enumerable.Empty<int>();
}
int pivot = ints.First();
IEnumerable<int> lt = ints.Where(i => i < pivot);
IEnumerable<int> gt = ints.Where(i => i > pivot);
return QuickSort(lt).Concat(new int[] { pivot }).Concat(QuickSort(gt));
}
Run Code Online (Sandbox Code Playgroud)
现在可以肯定的是,我并不是说这是一个很好的快速排序!然而,它是lambda表达式与流操作相结合的表达能力的一个很好的例子.
它不能用Java完成!我甚至无法询问流是否为空而不使其无法使用.
List<Integer> integer = Stream.generate(new Supplier<Integer>() {
int i = 0 ;
@Override
public Integer get() {
return ++i;
}
}).filter(j -> j < 5)
.limit(10) // Note the call to limit here
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
与我的期望相反,collect
呼叫永远不会回来.设置limit
之前filter
产生预期结果.为什么?
我正在为新手程序员编写一个库,所以我试图保持API尽可能干净.
我的库需要做的一件事就是对大量的int或long进行一些复杂的计算.我的用户需要从中计算这些值所需的大量场景和业务对象,因此我认为最好的方法是使用流来允许用户将业务对象映射到IntStream
或者LongStream
然后计算收集器内的计算.
但是IntStream和LongStream只有3参数collect方法:
collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)
Run Code Online (Sandbox Code Playgroud)
而且没有简单的collect(Collector)
方法Stream<T>
.
所以不是能够做到的
Collection<T> businessObjs = ...
MyResult result = businessObjs.stream()
.mapToInt( ... )
.collect( new MyComplexComputation(...));
Run Code Online (Sandbox Code Playgroud)
我必须提供像这样的供应商,蓄电池和组合器:
MyResult result = businessObjs.stream()
.mapToInt( ... )
.collect(
()-> new MyComplexComputationBuilder(...),
(builder, v)-> builder.add(v),
(a,b)-> a.merge(b))
.build(); //prev collect returns Builder object
Run Code Online (Sandbox Code Playgroud)
对于我的新手用户来说这太复杂了,而且非常容易出错.
我的工作是创建一个静态方法,它接受IntStream
或LongStream
作为输入,并为您隐藏收集器的创建和执行
public static MyResult compute(IntStream stream, ...){
return .collect(
()-> new MyComplexComputationBuilder(...),
(builder, v)-> builder.add(v),
(a,b)-> a.merge(b))
.build();
} …
Run Code Online (Sandbox Code Playgroud) class Program
{
static void Main(string[] args)
{
var dictionary = new Dictionary<string, int>()
{
{"1", 1}, {"2", 2}, {"3", 3}
};
foreach (var s in dictionary.Keys)
{
// Throws the "Collection was modified exception..." on the next iteration
// What's up with that?
dictionary[s] = 1;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我完全理解为什么在枚举列表时抛出此异常 - 在枚举期间,枚举对象的结构不会改变似乎是合理的.但是,更改字典的值会改变其结构吗?具体来说,其键的结构?
我有一个maven构建过程,可以将可执行jar及其测试发布到Nexus.我有另一个maven构建过程需要访问这些jar(可执行文件+测试)并运行测试.
我该怎么办呢?到目前为止,只有当jar被分解为类文件时,我才设法做到这一点.我是maven的新手,完全迷失在文档中.
该YAML规范明确规定:
映射使用冒号和空格(":")来标记每个键:值对.
所以这是合法的:
foo: bar
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
foo:bar
Run Code Online (Sandbox Code Playgroud)
我看到网上有很多人在讨论这个空间.我认为他们有一个观点.我自己被它烧了几次.
为什么空间是强制性的?它背后的设计考虑是什么?
DirectoryStream的文档明确指出:
迭代器非常一致.它是线程安全的,但在迭代时不会冻结目录,因此它可能(或可能不)反映在创建DirectoryStream之后发生的目录的更新.
在我的机器上,我在调试模式下对目录执行了一个简单的迭代.在迭代完成之前,我打破了执行,将文件添加到正在迭代的目录并重新开始.迭代没有看到额外的文件.
我的问题:在什么情况下会迭代反映更新的目录内容?不幸的是,正式文件对此非常模糊.至少可以说.
在对溢出文件规定:
OVERFLOW - 表示事件可能已丢失或丢弃.
它没有说在什么情况下我应该期望事件丢失或丢弃?起初我以为这是将很多文件写入文件夹的结果.我创建了几千个零大小的文件,并将它们移动到受监控的目录.没有溢出.
我错过了什么?
我已经阅读了大量有关Java SE 6和7的HotSpot GC的文档.在谈到获得自由记忆的连续区域的策略时,提出了两种"竞争"方法:疏散方法(通常应用于年轻一代) ),将活动对象从"从"复制到空'到'和压缩(CMS的后退),其中活动对象移动到碎片区域内的一侧,形成一个连续的未使用块记忆.
两种方法都与"实时集"的大小成比例.不同之处在于疏散需要x2倍的空间,而实际集合则不需要压缩.
为什么我们需要撤离技术呢?需要完成的复制量是相同的,但是它需要保留更多的堆大小,并且不允许更快地重新映射引用.
是的:疏散可以并行执行(其中 - 压缩不能,或者至少不那么容易),但这个特性从未被提及过,并且看起来并不那么重要(考虑到重新映射比移动要昂贵得多).
这是关于API设计的问题.在C#中添加扩展方法时,获取IEnumerable
所有在所有集合上直接使用lambda表达式的方法.
随着Java中lambdas和默认方法的出现,我希望Collection
能够实现Stream
并为其所有方法提供默认实现.这样,我们就不需要调用stream()
它来利用它提供的功率.
图书馆建筑师选择不太方便的方法的原因是什么?
java ×7
java-8 ×4
api-design ×3
java-stream ×3
java-7 ×2
c# ×1
dictionary ×1
enumeration ×1
file-io ×1
io ×1
jar ×1
lambda ×1
maven ×1
nio2 ×1
unit-testing ×1
yaml ×1