Ada*_*yga 171 java string java-8
在Java 8中,有一种新方法String.chars()返回表示字符代码的ints(IntStream)流.我想很多人会期待char这里有一股流.以这种方式设计API的动机是什么?
ski*_*iwi 195
正如其他人已经提到的那样,这背后的设计决策是为了防止方法和类的爆炸.
不过,我个人认为这是一个非常糟糕的决定,并且鉴于他们不想制作CharStream,这应该是合理的,不同的方法而不是chars(),我会想到:
Stream<Character> chars(),这给出了一个盒子字符流,这将有一些轻微的性能损失.IntStream unboxedChars(),将用于性能代码.但是,我认为这个答案应该专注于展示使用Java 8获得的API的方法,而不是关注为什么它以这种方式完成.
在Java 7中,我会这样做:
for (int i = 0; i < hello.length(); i++) {
System.out.println(hello.charAt(i));
}
Run Code Online (Sandbox Code Playgroud)
我认为在Java 8中使用它的合理方法如下:
hello.chars()
.mapToObj(i -> (char)i)
.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
在这里,我获得了一个IntStream并通过lambda i -> (char)i将它映射到一个对象,这将自动将其打包成一个Stream<Character>,然后我们可以做我们想要的,并仍然使用方法引用作为加号.
请注意,你必须这样做mapToObj,如果你忘记并使用map,那么没有什么会抱怨,但你仍然IntStream会得到一个,你可能会想知道为什么它打印整数值而不是代表字符的字符串.
Java 8的其他丑陋替代品:
通过保留IntStream并希望最终打印它们,您不能再使用方法引用进行打印:
hello.chars()
.forEach(i -> System.out.println((char)i));
Run Code Online (Sandbox Code Playgroud)
而且,使用方法引用自己的方法不再起作用了!考虑以下:
private void print(char c) {
System.out.println(c);
}
Run Code Online (Sandbox Code Playgroud)
然后
hello.chars()
.forEach(this::print);
Run Code Online (Sandbox Code Playgroud)
这将产生编译错误,因为可能存在有损转换.
结论:
API是这样设计的,因为不想添加CharStream,我个人认为该方法应该返回一个Stream<Character>,并且当前的解决方法是使用mapToObj(i -> (char)i)on IntStream来能够正常使用它们.
Stu*_*rks 79
来自skiwi的答案已经涵盖了许多重点.我会填写更多背景知识.
任何API的设计都是一系列的权衡.在Java中,其中一个难题是处理很久以前制定的设计决策.
从1.0开始,基元就一直在Java中.它们使Java成为一种"不纯的"面向对象语言,因为原语不是对象.我相信,添加原语是一种务实的决定,以牺牲面向对象的纯度为代价来提高性能.
这是近20年后我们仍然生活在今天的权衡.Java 5中添加的自动装箱功能大多消除了使用装箱和拆箱方法调用来混乱源代码的需要,但开销仍然存在.在许多情况下,它并不明显.但是,如果您要在内部循环中执行装箱或拆箱,您会发现它可能会产生大量的CPU和垃圾收集开销.
在设计Streams API时,很明显我们必须支持原语.装箱/拆箱开销会破坏并行性带来的任何性能优势.但是,我们不想支持所有原语,因为这会给API增加大量的混乱.(你能真正看到一个用途ShortStream?)"全部"或"无"是设计的舒适场所,但都不可接受.所以我们必须找到合理的"一些"价值.我们结束了与原始的专长int,long和double.(我个人原谅了,int但那只是我.)
因为CharSequence.chars()我们考虑返回Stream<Character>(早期的原型可能实现了这个),但由于拳击开销而被拒绝.考虑到String将char值作为基元,当调用者可能只对该值进行一些处理并将其反转回字符串时,无条件地强加拳击似乎是错误的.
我们还考虑了一种CharStream原始的特化,但与它添加到API的批量相比,它的使用似乎相当狭窄.添加它似乎不值得.
对调用者施加的惩罚是他们必须知道IntStream包含的char值表示为ints和必须在适当的位置进行转换.这是令人困惑的,因为有过多的API调用,PrintStream.print(char)并且PrintStream.print(int)它们的行为明显不同.可能会出现另一个混乱点,因为codePoints()调用也返回一个IntStream但它包含的值非常不同.
因此,这归结为在几种选择中实际选择:
我们不能提供原始的特化,从而产生一个简单,优雅,一致的API,但它会带来高性能和GC开销;
我们可以提供一整套原始专业化,代价是混乱API并给JDK开发人员带来维护负担; 要么
我们可以提供一个原始特化的子集,给出一个中等大小,高性能的API,在相当窄范围的用例(字符处理)中给调用者带来相对较小的负担.
我们选择了最后一个.
| 归档时间: |
|
| 查看次数: |
73856 次 |
| 最近记录: |