`
AILIKES
  • 浏览: 187364 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java 8 新增特性的优缺点

阅读更多

 

 

        Java 8或许是 迄今为止最令人期待的Java版本,最初定于今年的9月份发布,但由于一系列的安全漏洞问题,目前已推迟到明年的3月份。

 

 

  Java 8试图“创新”,根据 微软对这个词的定义,就是把其他框架或语言里成熟的特性“偷”进来。在新版本发布之前,Java社区就已经开始讨论Lambda项目、Streams、函数式接口等其他好东西。下面就让我们一起来看下这些伟大的功能,看看它们各自的优缺点,好让你更好地应用在项目中。

  Streams

  集合(Collections)的改进也是Java 8的一大亮点,而让集合越来越好的核心组件则是“Stream”。它与java.io包里的InputStream和OutputStream是完全不同的概念,它是一个全新的概念,大家不要混淆。

  此外,Stream的出现也并不是要取代ArrayLists或其他集合,它提供了一种操作大数据接口,让数据操作更容易和更快。Stream是一次性使用对象,一旦被遍历,就无法再次遍历。在遍历时,它具有过滤、映射以及减少遍历数等功能。每个Stream都有两种模式:顺序执行和并行执行,其能够利用多核处理器的优势,并可以使用 fork/join并行方式来拆分任务和加速处理过程。

  顺序流:

  1List people = list.getStream.collect(Collectors.toList());

  并行流:

  1List people = list.getStream.parallel().collect(Collectors.toList());

  顾名思义,当使用顺序方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数组会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。

  并行流实例:

  List originalList = someData;

  split1 = originalList(0, mid);

  split2 = originalList(mid,end);

  new Runnable(split1.process());

  new Runnable(split2.process());

  List revisedList = split1 + split2;

  由于一个Stream只能被遍历一次,通常会返回另外一个Stream,可以使用终端方法(terminal method)来获取有用的结果,终端方法可以是sum()、collect()或toArray()等。在Stream被终止之前,操作的结果不会被实现。

  Double result = list.getStream().mapToDouble(f -> f.getAmount()).sum();

  List people = list.getStream().filter(f -> f.getAge() > 21).collect(Collectors.toList());

  该功能最大的好处是允许使用多核处理器来处理集合,这样处理速度会更加快速。而最主要的问题则是可读性。随着流链的加长,很有可能影响可读性。其它问题则来源于内置的新东西来支持这个新路径,这些是功能接口和Lambda。

  函数式接口

  在Java 8里将会有一个全新的功能——函数式接口(functional interfaces),就是可以在接口里面添加默认方法,并且这些方法可以直接从接口中运行。

  这样就可以在接口中实现集合的向后兼容,并且无需改变实现这个方法的类,就可以让Stream放置到接口中。一般而言,在接口中创建一个默认方法,然后实现该接口的所有类都可以使用Stream(无论是默认方法还是非默认方法)。

  基本上就是一种多继承形式,这样就变成了实现者之间的问题,作为实现人员,必须重写这些方法,他们可以选择使用超方法(supermethod),这也就意味着,许多实现接口的类需要改写。

  这有可能是Java 8里最让人关心的细节,也许Java 8里的函数式接口对于熟悉Scala的开发者来说不算新功能,但是他们可能会拿函数式接口与Scala的特征进行比较。然而,两者之间不同的是:Java 8里的函数式接口不能将一个引用指向实现类,而Scala允许通过self关键字来实现该操作。会有一些语言狂热者说,Java 8里的函数式接口只允许多继承行为,而不是状态。而Scala里的多继承特征既可以是行为也可以是状态。

  在Java里实现事务和其它项目,我们一般会使用 JavaAssist或 cglib的扩展类来构建动态代理和字节码操作。而Scala的特行可以让我们更直接地实现。

 一方面,函数式接口可能会被以继承方式滥用,另一方面,它们尽量不与Scala特征重复。

  Lambda

  Java 8的另一大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。下面这个例子就是使用Lambda语法来代替匿名的内部类,代码不仅简洁,而且还可读。

  没有使用Lambda的老方法:

  button.addActionListener(new ActionListener() {

  public void actionPerformed(ActionEvent ae) {

  System.out.println(“Action Detected”);

  }

  }

  );

  使用Lambda:

  button.addActionListener(e -> {

  System.out.println(“Action Detected”);

  }

  );

  让我们来看一个更明显的例子。

  不采用Lambda的老方法:

  Runnable runnable1 = new Runnable() {

  @Override

  public void run() {

  System.out.println(“Running without Lambda”);

  }

  };

  使用Lambda:

  1Runnable runnable2 = () -> { System.out.println(“Running from Lambda”); };

  正如你所看到的,使用Lambda表达式不仅让代码变的简单、而且可读、最重要的是代码量也随之减少很多。然而,在某种程度上,这些功能在Scala等这些JVM语言里已经被广泛使用。

  并不奇怪,Sclala社区是难以置信的,因为许多Java 8里的内容看起来就像是从Scala里搬过来的。在某种程度上,Java 8的语法要比Scala的更详细但不是很清晰,但这并不能说明什么,如果可以,它可能会像Scala那样构建Lambda表达式。

  一方面,如果Java继续围绕Lambda来发展和实现Scala都已经实现的功能,那么可能就不需要Scala了。另一方面,如果它只提供一些核心的功能,例如帮助匿名内部类,那么Scala和其他语言将会继续茁壮成长,并且有可能会凌驾于Java之上。其实这才是最好的结果,有竞争才有进步,其它语言继续发展和成长,并且无需担心是否会过时。

  Java time

  Time在Java里已有很长一段时间,首先出现的java.util.Date这个包,其次还有java.sql.Date、Calendar。但处理时间和日期需要大量的monkey代码,因此,像Joda Time等第三方库因此诞生。姗姗来迟,Oracle终于决定在Java里添加一个 java.time包来清理各种时间接口。它看起来很符合现在开发者的胃口,拥有各种各样的时间API。

  Java API可以处理一些时空连续体方面的特性,比如距离、质量、重量等,这是值得称赞的,但我仍然认为 Currency会处理得更好。我认为Java API需要好好地修剪而不是添加更多的东西,并且首先Java API应该对这些基本元素提供标准的兼容。

  Nashorn

  Nashorn是Rhino的接替者,该项目的目的是基于Java实现一个轻量级高性能的JavaScript运行环境。

  JDK 7中添加了invokeDynamic,其主要是用来支持非Java语言,尤其是动态语言。而JDK 8中的Nashorn将会给开发者提供一个更加实用的JavaScript实现。事实上,Oracle已经有了他自己的Node.js实现,叫做Node.jar。这似乎比在Java里运行JavaScript更加吸引人。

  Accumulators

  自从JDK中集成了 java.util.concurrent以来,该特性并没有停止发展。相反,JDK 8将构建于JDK 7和fork/join框架之上,并通过加法器(adders)和累加器(Accumulators)得到了进一步的发展。

  首先是同步。但是,如果你使用同步在多线程之间进行增量计数,那么同步有可能难以负担。在Java 6中通过让非竞争锁更廉价(cheap)来使同步不那么难以负担。其中大多数会使用Vector来提升老应用程序性能,几乎每一个单线程都受到了Java Activation Framework的影响。

  Java.util.concurrent包使得线程池和其他相对复杂的多线程结构变得更好,但是,倘若你想要通过跨线程来增加一个变量,那么就有点大材小用了。对此,我们采用一种比真正的锁更轻更快的原子。在JDK 8中,我们采用Accumulators和adders,这些要比原子轻量多了,对于大多数异构代码来说,这些足以满足它们的需求,如果线程太多,那么可以增加一个计数器。但想要看到类似map/reduce实现或统计跨线程之间的总和,你仍然需要使用原子,因为如果要读取这些跨线程的值,累积的顺序是无法得以保证的。

  HashMap修复

  在Java中使用String.hashCode()实现已是大家熟知的bug。如果在特定的代码中引入HashMap,可能会导致拒绝服务攻击。基本上,如果有足够多的参数hash到相同值,那么可能会消耗过多的CPU时间。

  通常,HashMap bucket采用链表的方式来存储map条目。使用此算法存在大量的冲突,并且增加了O(1)到O(N)这种哈希变化的复杂性,为了解决这一问题,通过采用平衡tree算法来降低复杂度。

  TLS SNI

  SNI是 服务器名称标识(Server Name Identification)的缩写,由于大多数公共网站的访客数量不是太多,几乎很少能达到数百万用户。很多网站都使用相同的IP地址和基于名字的虚拟主机,比如我访问 podcasts.infoworld.com和 www.infoworld.com,最后的网址是一样的,但访问的主机名是不一样的,所以我有可能会访问到不同的Web页面。然而,因为SSL,我可能无法分享IP地址。由于HTTP主机头是建立在基于命名的虚拟主机上,并且主机也是依赖SSL来实现加密/解密的,所以,不得不为每个SSL证书申请不同的IP地址。

  在最近几年都是采用SNI来解决这一问题的,Java也不例外。这种方式得到了大多数浏览器的支持,现在Apache和Java也支持它。这意味着过不了多久,我们就可以看到Apache和基于Java的服务器使用Oracle的SSL实现来支持SNI,称作 JSSE。

  总结

  总之,Java 8包含了一大堆非常实用的特性,这也是许多开发者想使用最新版本的原因之一。在我看来,Stream是最好的一个特性。但愿并行集合也能够为其进程性能带来一些提升。而函数式接口可能并不会像预期中的那样好用,万一使用不当,可能会给开发者带来很多麻烦。

分享到:
评论

相关推荐

    8.java学习第八章——面向对象.pdf

    ### 8. Java 学习第八章——面向对象 #### 面向过程与面向对象的区别 在讨论面向过程和面向对象之前,我们先明确几个概念。编程语言根据其编程范式可以分为多种类型,其中面向过程和面向对象是最常见的两种。 **...

    Java各版本从控制台读取数据的方法

    本文将详细介绍从JDK 1.4到JDK 6.0各个版本中从控制台读取数据的方法及其优缺点。 #### JDK 1.4及以下版本读取的方法 在JDK 1.4及更早版本中,从控制台读取数据主要依赖于`System.in`获取系统输入流,然后通过`...

    java并发编程实战(英文版)

    - **并发集合**:详细介绍Java提供的各种并发集合类,如`ConcurrentHashMap`、`CopyOnWriteArrayList`等,并讨论它们适用的场景和优缺点。 #### 四、案例分析 书中通过大量的实际案例分析,帮助读者更好地理解并发...

    Java工程师面试题(含答案).pdf

    - Java 8新增的Lambda表达式和Stream API。 15. 软件开发工具和环境 - Maven、Gradle:Java项目的构建和依赖管理工具。 - Eclipse、IntelliJ IDEA:Java开发的集成开发环境。 16. 其他技术点 - HTML与...

    Java开发工具(JDK 11和JDK 8)

    在实际工作中,确保了解每个版本的差异和优缺点,以及如何在项目中有效利用它们,是非常重要的。 在安装和配置JDK时,需要注意设置`JAVA_HOME`环境变量,以便操作系统能找到Java命令。同时,IDEs(如IntelliJ IDEA...

    Java2参考大全.pdf

    - **Java2的新特性**:Java2引入了JDK 1.2,新增了Swing GUI组件包,支持了更多先进的图形用户界面设计;还引入了HotSpot虚拟机技术,显著提高了Java应用程序的性能。 - **企业级应用的支持**:Java2为企业级应用...

    C++造的坑Java来补,补坑的路上Java接口怎么写.pdf

    Java通过接口来模拟类似多重继承的特性,但避免了多重继承的缺点。 描述中提到的Java接口,从Java的历史演化来看,经历了多次重要的更新和功能扩展,从最初的只包含静态常量和抽象方法,到后来增加静态嵌套类、嵌套...

    稍微有点难度的10道java面试题,你会几道?

    Servlet 3.0 新增特性 Servlet 3.0 规范引入了多项新特性,包括但不限于: - **非阻塞I/O**:支持异步处理,提高高并发场景下的处理能力。 - **注解支持**:简化Servlet、过滤器和监听器的配置。 - **Servlet容器...

    Java集合容器面试题

    说一下ArrayList的优缺点 说一下ArrayList的优缺点?ArrayList的优点是:可以动态扩容,缺点是:扩容时需要重新分配内存。 如何实现数组和List之间的转换 如何实现数组和List之间的转换?使用Arrays.asList()方法...

    2021Java字节跳动面试题——面向字节_Dubbo(上).pdf

    ### Dubbo支持的协议及其应用场景、优缺点 #### 1. **Dubbo协议** - **特点**:单一长连接和NIO异步通讯,适用于大并发小数据量的服务调用,以及消费者数量远大于提供者的情况。 - **传输协议**:TCP - **序列化...

    JAVA架构师知识整理.pdf

    综上所述,《JAVA架构师知识整理》这份文档涵盖了JVM的基本概念、内存管理机制、垃圾回收策略以及Java I/O编程等多个方面的重要知识点,对于深入理解Java语言特性和系统架构有着重要的意义。通过学习这些内容,架构...

    java开发面试题文思

    - 新增了一些安全特性和工具。 - **JDK 1.5 的特性**: - 泛型支持:增强了类型安全性。 - `for-each`循环:简化了数组和集合的遍历。 - 自动装箱/拆箱:简化了基本类型和包装类型的转换。 - 注解:用于元数据...

    Java继承.docx

    在Java编程语言中,**继承**是一种重要的面向对象编程特性,它允许创建新类(称为子类或派生类)来继承现有类(称为父类、基类或超类)的属性和行为。通过继承,子类不仅能够重用父类的方法和字段,还能在此基础上...

    02-Java集合容器面试题-重点.docx

    说一下ArrayList的优缺点如何实现数组和List之间的转换?ArrayList和LinkedList的区别是什么?ArrayList和Vector的区别是什么?插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述ArrayList、Vector、...

    JAVA设计模式

    - **遵循开闭原则**:增加新的产品时,只需新增相应的具体工厂即可,无需修改现有代码。 - **支持多态**:客户端可以调用抽象工厂的工厂方法,得到的是抽象产品角色的引用,支持多态操作。 **缺点**: - **系统中类...

Global site tag (gtag.js) - Google Analytics