天天看点

Java 8的6个问题

1. 并行streams实际上可能会降低你的性能

  java8带来了最让人期待的新特性之–并行。parallelstream() 方法在集合和流上实现了并行。它将它们分解成子问题,然后分配给不同的线程进行处理,这些任务可以分给不同的cpu核心处理,完成后再合并到一起。实现原理主要是使用了fork/join框架。好吧,听起来很酷对吧!那一定可以在多核环境下使得操作大数据集合速度加快咯,对吗?

  基准测试将一个集合分成不同的组(主要/非主要的):

  map<boolean, list<integer>> groupbyprimary = numbers

  .parallelstream().collect(collectors.groupingby(s -> utility.isprime(s)));

  提醒:并行带来了很多好处,但是同样也会有一些其他的问题需要考虑到。当你已经在多线程环境中运行了,记住这点,自己要熟悉背后的运行机制。

  2. lambda 表达式的缺点

  lambda表达式。哦,lambda表达式。没有lambda表达式我们也能做到几乎一切事情,但是lambda是那么的优雅,摆脱了烦人的代码,所以很容易就爱上lambda。比如说早上起来我想遍历世界杯的球员名单并且知道具体的人数(有趣的事实:加起来有254个)。

  list lengths = new arraylist();

  for (string countries : arrays.aslist(args)) {

  lengths.add(check(country));

  }

  现在我们用一个漂亮的lambda表达式来实现同样的功能:

  stream lengths = countries.stream().map(countries -< check(country));

  从更深层次来看,你写什么代码和调试什么代码是两码事。堆栈跟踪越来越大,使得难以调试代码。一些很简单的事情譬如添加一个空字符串到list中,本来是这样一个很短的堆栈跟踪

  at lmbdamain.check(lmbdamain.java:19)

  at lmbdamain.main(lmbdamain.java:34)

  变成这样:

at lmbdamain.check(lmbdamain.java:19)

at lmbdamain.lambda$0(lmbdamain.java:37)

at lmbdamain$$lambda$1/821270929.apply(unknown source)

at java.util.stream.referencepipeline$3$1.accept(referencepipeline.java:193)

at java.util.spliterators$arrayspliterator.foreachremaining(spliterators.java:948)

at java.util.stream.abstractpipeline.copyinto(abstractpipeline.java:512)

at java.util.stream.abstractpipeline.wrapandcopyinto(abstractpipeline.java:502)

at java.util.stream.reduceops$reduceop.evaluatesequential(reduceops.java:708)

at java.util.stream.abstractpipeline.evaluate(abstractpipeline.java:234)

at java.util.stream.longpipeline.reduce(longpipeline.java:438)

at java.util.stream.longpipeline.sum(longpipeline.java:396)

at java.util.stream.referencepipeline.count(referencepipeline.java:526)

at lmbdamain.main(lmbdamain.java:39

  lambda表达式带来的另一个问题是关于重载:使用他们调用一个方法时会有一些传参,这些参数可能是多种类型的,这样会使得在某些情况下导致一些引起歧义的调用。lukas eder 用示例代码进行了说明。

  提醒:要意识到这一点,跟踪有时候可能会很痛苦,但是这不足以让我们远离宝贵的lambda表达式。

  3. default方法令人分心

  default方法允许一个功能接口中有一个默认实现,这无疑是java8新特性中最酷的一个,但是它与我们之前使用的方式有些冲突。那么既然如此,为什么要引入default方法呢?如果不引入呢?

public interface timeclient {

// ...

static public zoneid getzoneid (string zonestring) {

try {

return zoneid.of(zonestring);

} catch (datetimeexception e) {

system.err.println("invalid time zone: " + zonestring +

"; using default time zone instead.");

return zoneid.systemdefault();

}

default public zoneddatetime getzoneddatetime(string zonestring) {

return zoneddatetime.of(getlocaldatetime(), getzoneid(zonestring));

  就是这样,问题迎刃而解了。是这样么?default方法将接口和实现分离混合了。似乎我们不用再纠结他们本身的分层结构了,现在我们需要解决新的问题了。想要了解更多,阅读oleg shelajev在rebellabs上发表的文章吧。

  提醒:当你手上有一把锤子的时候,看什么都像是钉子。记住它们原本的用法,保持原来的接口而重构引入新的抽象类是没有意义的。

 4. 该如何拯救你,jagsaw?

  jigsaw项目的目标是使java模块化,将jre分拆成可以相互操作的组件。这背后最主要的动机是渴望有一个更好、更快、更强大的java嵌入式。我试图避免提及“物联网”,但我还是说了。减少jar的体积,改进性能,增强安全性等等是这个雄心勃勃的项目所承诺的。

  但是,它在哪呢?oracle的首席java架构师, mark reinhold说:  jigsaw,通过了探索阶段 ,最近才进入第二阶段,现在开始进行产品的设计与实现。该项目原本计划在java8完成。现在推迟到java9,有可能成为其最主要的新特性。

  提醒:如果这正是你在等待的, java9应该在2016年间发布。同时,想要密切关注甚至参与其中的话,你可以加入到这个邮件列表。

  5. 那些仍然存在的问题

  受检异常

  没有人喜欢繁琐的代码,那也是为什么lambdas表达式那么受欢迎的的原因。想想讨厌的异常,无论你是否需要在逻辑上catch或者要处理受检异常,你都需要catch它们。即使有些永远也不会发生,像下面这个异常就是永远也不会发生的:

  try {

  httpconn.setrequestmethod("get");

  }?catch (protocolexception pe) { /* why don’t you call me anymore? */ }

  原始类型

  它们依然还在,想要正确使用它们是一件很痛苦的事情。原始类型导致java没能够成为一种纯面向对象语言,而移除它们对性能也没有显著的影响。顺便提一句,新的jvm语言都没有包含原始类型。

  运算符重载

  james gosling,java之父,曾经在接受采访时说:“我抛弃运算符重载是因为我个人主观的原因,因为在c++中我见过太多的人在滥用它。”有道理,但是很多人持不同的观点。其他的jvm语言也提供这一功能,但是另一方面,它导致有些代码像下面这样:

  javascriptentrypoints <<= (sourcedirectory in compile)(base =>

  ((base / "assets" ** "*.js") --- (base / "assets" ** "_*")).get

  )

  事实上这行代码来自scala  play框架,我现在都有点晕了。

  提醒:这些是真正的问题么?我们都有自己的怪癖,而这些就是java的怪癖。在未来的版本中可能有会发生一些意外,它将会改变,但向后兼容性等等使得它们现在还在使用。

  6. 函数式编程–为时尚早

  函数式编程出现在java之前,但是它相当的尴尬。java8在这方面有所改善例如lambdas等等。这是让人受欢迎的,但却不如早期所描绘的那样变化巨大。肯定比java7更优雅,但是仍需要努力增加一些真正需要的功能。

  其中一个在这个问题上最激烈的评论来自pierre-yves saumont,他写了一系列的文章详细的讲述了函数式编程规范和其在java中实现的差异。

  所以,选择java还是scala呢?java采用现代函数范式是对使用多年lambda的scala的一种肯定。lambdas让我们觉得很迷惑,但是也有许多像traits,lazy evaluation和immutables等一些特性,使得它们相当的不同。

  提醒:不要为lambdas分心,在java8中使用函数式编程仍然是比较麻烦的。

最新内容请见作者的github页:http://qaseven.github.io/