当前位置: 首页 > 科技观察

关于Java8的6个主要问题

时间:2023-03-17 10:17:51 科技观察

1.ParallelStreams实际上可能会降低你的性能Java8带来了最令人期待的新特性之一——并行性。parallelStream()方法在集合和流上实现并行。它将它们分解成子问题,然后将它们分发到不同的线程中进行处理。这些任务可以分布到不同的CPU核上进行处理,完成后再合并在一起。实现原理主要是利用fork/join框架。嗯,听起来很酷吧!那一定能在多核环境下加速大数据集的运行吧?不,如果使用不当,它实际上会使您的代码运行得更慢。我们运行了一些基准测试,发现它慢了15%,甚至更糟。假设我们已经运行了多个线程,然后使用.parallelStream()向线程池中添加更多的线程,很容易超过多核CPU处理的上限,从而增加上下文切换的次数,使整体变慢向上。将集合拆分为不同组(主要/非主要)的基准:Map>groupByPrimary=numbers.parallelStream().collect(Collectors.groupingBy(s->Utility.isPrime(s)));性能下降可能还有其他原因。如果我们把它分成多个任务,其中一个任务可能会因为某种原因比其他任务花费更长的时间来处理。.parallelStream()分解了任务的处理,这可能比将其作为一个完整的任务来处理要慢。看看这篇文章,LukasKrecan给出的一些示例和代码。提醒:并行带来很多好处,但也有一些其他问题需要考虑。当你已经在多线程环境中运行时,记住这一点,你必须熟悉它背后的运行机制。2.Lambda表达式的缺点Lambda表达式。哦,lambda表达式。没有lambda表达式我们几乎可以做任何事情,但是lambda是如此优雅并且摆脱了烦人的代码,所以很容易爱上lambda。假设我早上醒来,想查看世界杯名单并了解确切的球员人数(有趣的事实:总共有254人)。Listlengths=newArrayList();for(Stringcountries:Arrays.asList(args)){lengths.add(check(country));}现在我们使用一个很好的lambda表达式来实现相同的功能:Streamlengths=countries.stream()。地图(国家-<检查(国家));哇!这太棒了。在Java中加入一些像lambda表达式这样的新元素,虽然看起来更像是一件好事,但实际上背离了原始的Java规范。字节码是完全面向对象的,加上了lambda,使得实际代码和运行时字节码结构差异较大。在TalWeiss的这篇文章中阅读有关lambda表达式的副作用的更多信息。在更深层次上,你写什么代码和你调试什么代码是两件不同的事情。堆栈跟踪越来越大,使得调试代码变得困难。一些很简单的事情比如在列表中添加一个空字符串,本来这么短的栈和atLmbdaMain.check(LmbdaMain.java:19)atLmbdaMain.main(LmbdaMain.java:34)变成了这样:atLmbdaMain。检查(LmbdaMain.java:19)atLmbdaMain.lambda$0(LmbdaMain.java:37)atLmbdaMain$$Lambda$1/821270929.apply(UnknownSource)atjava.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)atjava.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)atjava.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)atjava.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)atjava.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)atjava.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)atjava.util.stream.LongPipeline.reduce(LongPipeline.java:438)atjava.util.stream.LongPipeline.sum(LongPipeline.java:396)atjava.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)atLmbdaMain.main(LmbdaMain.java:39lambda表达式带来的另一个问题是关于重载:当使用他们去调用一个方法,会有一些参数传递,这些参数号码可以有多种类型,这在某些情况下会导致模棱两可的呼叫。LukasEder使用示例代码进行说明。警告:请注意,跟踪有时会很痛苦,但这不足以让我们远离珍贵的lambda表达式。3.Default方法让人分心Default方法允许在函数式接口中进行默认实现,这无疑是Java8新特性中最酷的,但它与我们过去的方式有点冲突。那么既然如此,为什么要引入默认方法呢?如果不进口呢?Defalut方法背后的主要动机是,如果我们想向现有接口添加一个方法,我们可以在不重写实现的情况下做到这一点,并使其与旧版本兼容。例如,从OracleJava教程中获取这段添加了指定时区功能的代码:publicinterfaceTimeClient{//...staticpublicZoneIdgetZoneId(StringzoneString){try{returnZoneId.of(zoneString);}catch(DateTimeExceptione){System.err.println("Invalidtimezone:"+zoneString+";usingdefaulttimezoneinstead.");returnZoneId.systemDefault();}}defaultpublicZonedDateTimegetZonedDateTime(StringzoneString){returnZonedDateTime.of(getLocalDateTime(),getZoneId(zoneString));}}就是这样,问题解决了。是这样吗?Default方法混合了接口和实现的分离。看来我们不用再为自己的层级结构发愁了,现在我们需要解决新的问题了。要了解更多信息,请阅读OlegShelajev关于RebelLabs的文章。提醒:当你有锤子时,一切看起来都像钉子。记住它们原来的用法,保留原来的接口并重构引入新的抽象类是没有意义的。4.如何拯救你,Jagsaw?Jigsaw项目的目标是使Java模块化,将JRE拆分为可互操作的组件。这背后的主要动机是希望拥有更好、更快和更强大的嵌入式Java。我试图避免提及“物联网”,但我做到了。减少JAR大小、提高性能、增强安全性等等是这个雄心勃勃的项目所承诺的。但它在哪里?甲骨文高级Java架构师MarkReinhold表示:Jigsaw已经过了探索阶段,最近才进入第二阶段,现在开始产品设计和实施。该项目原计划用Java8完成。现在推迟到Java9,可能会成为它最重要的新特性。提醒:如果您正在等待,Java9应该会在2016年发布。同时,如果你想关注甚至参与进来,你可以加入这个邮件列表。5.那些仍然存在的问题Checkedexceptions没有人喜欢繁琐的代码,这就是lambdas表达式如此流行的原因。想一想讨厌的异常,无论是逻辑上需要捕获还是处理已检查的异常,都需要捕获它们。即使有些永远不会发生,像下面这样的异常也永远不会发生:试图让他们正确的痛苦。原始类型阻止了Java成为纯面向对象的语言,删除它们对性能没有明显影响。顺便说一句,较新的JVM语言都没有包含原始类型。运算符重载Java之父JamesGosling曾在接受采访时说:“我出于自己的主观原因放弃运算符重载,因为我在C++中看到太多人滥用它。”有道理,但很多人持不同意见。其他的JVM语言也提供了这个特性,但是另一方面,它导致了一些这样的代码:javascriptEntryPoints<<=(sourceDirectoryinCompile)(base=>((base/"assets"**"*.js")---(base/"assets"**"_*")).get)这行代码来自ScalaPlay框架这一事实让我现在有点头晕。提醒:这些是真正的问题吗?我们都有自己的怪癖,而这些就是Java的怪癖。在以后的版本中可能会出现一些意外,会发生变化,但是向后兼容等原因使得它们现在仍然在使用。6.函数式编程——太早了函数式编程出现在java之前,但是很尴尬。Java8在这方面有改进比如lambdas等等。这是受欢迎的,但并不像早期描绘的那样多样化。绝对比Java7更优雅,但仍需要努力添加一些真正需要的功能。关于这个问题最激烈的评论之一来自Pierre-yvesSaumont,他撰写了一系列文章,详细介绍了函数式编程规范与其在Java中的实现之间的差异。那么,选择Java还是Scala?Java采用现代函数范式是对Scala的认可,Scala多年来一直使用Lambdas。Lambda使我们感到困惑,但也有特征、惰性求值和不可变等特性使它们截然不同。提醒:不要被lambda分心,在Java8中使用函数式编程仍然很麻烦。原文链接:Jaxenter翻译:ImportNew.com-zhongjianno1翻译链接:http://www.importnew.com/13972.html