在Java8中,有一个新方法String。chars()
返回表示字符代码的int
s(IntStream
)流。我猜很多人会希望这里有一个char
s流。以这种方式设计API的动机是什么?
斯基维的回答已经涵盖了许多要点。我会补充一些背景知识。
任何API的设计都是一系列权衡。在Java中,一个困难的问题是处理很久以前做出的设计决策。
原语从1.0开始Java。它们使Java一种“不纯净”的面向对象语言,因为原语不是对象。我认为,添加原语是一个以牺牲面向对象的纯度为代价来提高性能的务实决定。
这是近20年后我们今天仍然生活在一起的权衡。Java5中添加的自动装箱功能基本上消除了用装箱和取消装箱方法调用来混淆源代码的需要,但是开销仍然存在。在许多情况下,这是不明显的。但是,如果您要在内部循环中执行装箱或拆箱,您会看到它会带来大量的CPU和垃圾回收机制开销。
在设计Streams API时,很明显我们必须支持原语。装箱/拆箱开销会破坏并行性带来的任何性能好处。不过,我们不想支持所有的原语,因为这会给API增加大量的混乱。(你真的能看到短流的用途吗?)“全部”或“无”对于设计来说都是舒适的地方,但两者都不可接受。因此,我们必须找到“some”的合理值。我们最终得到了
int
、long
和double
的基本专门化。(就我个人而言,我可能会忽略int
,但那只是我自己。)
对于
CharSequence。chars()
我们考虑返回流
我们还考虑了
CharStream
原语专门化,但与它将添加到API中的批量相比,它的使用范围似乎非常狭窄。似乎不值得添加它。
这对调用者造成的惩罚是,他们必须知道
IntStream
包含char
表示为ints
的值,并且必须在适当的位置进行转换。这让人倍感困惑,因为存在像PrintStream这样的重载API调用。打印(字符)
和PrintStream。打印(int)
,它们的行为明显不同。另一个混淆点可能会出现,因为codePoints()
调用还返回一个IntStream
,但它包含的值完全不同。
所以,这归结为在几个选择中务实地选择:
>
我们不能提供原始的专门化,从而产生一个简单、优雅、一致的API,但这会带来高性能和GC开销;
我们可以提供一套完整的原始专门化,代价是将API弄得乱七八糟,并给JDK开发人员带来维护负担;或者
我们可以提供原语专门化的子集,提供一个中等大小、高性能的API,在相当狭窄的用例范围(字符处理)中对调用方施加相对较小的负担。
我们选择了最后一个。
正如其他人已经提到的,这背后的设计决策是防止方法和类的爆炸。
不过,我个人认为这是一个非常糟糕的决定,考虑到他们不想使用CharStream
,这是合理的,应该使用不同的方法而不是chars()
,我会想到:
流
然而,与其关注为什么现在这样做,我认为这个答案应该专注于展示一种方法,用我们从Java8获得的应用编程接口来做这件事。
在Java 7中,我会这样做:
for (int i = 0; i < hello.length(); i++) {
System.out.println(hello.charAt(i));
}
我认为在Java 8中实现这一点的合理方法如下:
hello.chars()
.mapToObj(i -> (char)i)
.forEach(System.out::println);
在这里,我获得一个
IntStream
,并通过lambdai-映射到一个对象
请注意,虽然你必须做
mapToObj
,如果你忘记并使用map
,那么没有什么会抱怨,但是你最终仍然会得到一个IntStream
,你可能会想知道为什么它会打印整数值,而不是表示字符的字符串。
Java 8的其他丑陋替代方案:
通过留在
IntStream
中并希望最终打印它们,您无法再使用方法引用进行打印:
hello.chars()
.forEach(i -> System.out.println((char)i));
此外,对自己的方法使用方法引用不再有效!考虑以下事项:
private void print(char c) {
System.out.println(c);
}
然后
hello.chars()
.forEach(this::print);
这将导致编译错误,因为可能存在有损转换。
结论:
API是这样设计的,因为不想添加
CharStream
,我个人认为该方法应该返回流
问题内容: 在Java 8中,有一个新方法可返回代表字符代码的)流。我想很多人会期待这里有s 流。这样设计API的动机是什么? 问题答案: 正如其他人已经提到的那样,其背后的设计决策是防止方法和类的爆炸式增长。 尽管如此,我个人还是认为这是一个非常糟糕的决定,并且鉴于他们不想做出合理的替代方法,我应该考虑: ,它会提供一系列字符,这会降低性能。 ,该代码将用于性能代码。 但是,我认为,这个答案应该
为什么,给定: 这是否不安全: 但这是安全的: 我所说的安全是指保证不受溢出的影响(我正在编写一个整数的)。
问题内容: 我想知道为什么当描述为char时indexOf方法的参数为int。 public int indexOf(int ch) http://download.oracle.com/javase/1,5.0/docs/api/java/lang/String.html#indexOf%28int%29 a]基本上,我感到困惑的是java中的int是32位,而unicode字符是16位。 b]
我一直在做一些欧拉项目练习,以提高我的C语言知识。 我编写了以下函数: 这将在17毫秒内计算。 但是,如果我改变路线 自 计算在2毫秒内完成。我是否遗漏了< code>pow(int,int)的一些明显的实现细节,导致第一个表达式的计算速度如此之慢?
我已经看到变量的原始版本和对象版本之间有以下映射: 浮- 所以,对他们所有人来说,唯一的区别就是世界上的第一个字母。我想知道为什么这个规则不适用于变成整数(而不是int)的int和变成字符而不是(char)的char。 我不知道这是否是问这个问题的正确地方,但我真的很想知道这个选择是否有原因,即使因为我教孩子们java,他们也经常问我同样的问题。
示例:类中的字段使用。 如果差异太小,那么为什么这些数据类型(、)会存在呢?