下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

java 8新特点归纳(上集)

作者:课课家教育     来源: http://www.kokojia.com点击数:725发布时间: 2016-01-08 10:55:42

标签: 开发Oraclejava 8

大神带你学编程,欢迎选课

  这篇文章是对java 8中即将到来的改进做一个面向开发者的综合性的总结,JDK的这一特性将会在2013年9月份发布。

  在写这篇文章的时候,Java 8的开发工作仍然在紧张有序的进行中,语言特新和API仍然有可能改变,我会尽我最大的努力保持这份文档跟得到Java 8的改动。

  Java 8的预览版,也就是 “Project Lambda”,现在可以从java.net下载到。

  我使用了IntelliJ的预览版做我的IDE,在我看来他是目前支持java 8特性最好的一个IDE,你可以从这里下载到.

  由于我没有找到Oracle发布的Java 8的官方文档,所以目前Java 8的文档还只有本地版本,等Oracle公开文档的时候,我将会重新链接到官方文档。

  接口改善

  现在接口里已经完全可以定义静态方法了. 举一个比较普遍的例子就是在java类库中, 对于一些接口如Foo, 都会有一个有静态方法的工具类Foos 来生成或者配合Foo对象实例来使用. 既然静态方法可以存在于接口当中, 那么大多数情况下 Foos工具类完全可以使用接口中的公共方法来代理 (或者将Foos置成package-private).

  除此之外更重要的就是, Java 8中接口可以定义默认的方法了.举个例子,一个for-each循环的方法就可以加入到java.lang.Iterable中: 

      1public default void forEach(Consumer action) {

  Objects.requireNonNull(action); for (T t : this) {

  action.accept(t);

  在过去,java类库的接口中添加方法基本上是不可能的. 在接口中添加方法意味着破坏了实现了这个接口的代码. 但是现在, 只要能够提供一个正确明智的默认的方法的实现, java类库的维护者就可以在接口中添加方法.

  Java 8中, 大量的默认方法已经被添加到核心的JDK接口中了. 稍候我会详细介绍它们.

  为什么不能用默认方法来重载equals,hashCode和toString?

  接口不能提供对Object类的任何方法的默认实现。特别是,这意味着从接口里不能提供对equals,hashCode或toString的默认实现。

  这刚看起来挺奇怪的,但考虑到一些接口实际上是在文档里定义他们的equals行为的。List接口就是一个例子了。因此,为什么不允许这样呢?

  Brian Goetz在这个问题上的冗长的回复里给出了4个原因。我这里只说其中一个,因为那个已经足够说服我了:

  它会变得更困难来推导什么时候该调用默认的方法。现在它变得很简单了:如果一个类实现了一个方法,那总是优先于默认的实现的。一旦所有接口的实例都是Object的子类,所有接口实例都已经有对equals/hashCode/toString的非默认实现。因此,一个在接口上这些的默认版本都是没用的,它也不会被编译。

  要看更多的话,看下由Brian Goetz写的解释: 对“允许默认方法来重载Object的方法”的回复

  函数式接口

  Java 8 引入的一个核心概念是函数式接口。如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。比如,java.lang.Runnable就是一个函数式接口,因为它只顶一个一个抽象方法:

  1public abstract void run();

  留意到“abstract”修饰词在这里是隐含的,因为这个方法缺少方法体。为了表示一个函数式接口,并非想这段代码一样一定需要“abstract”关键字。

  默认方法不是abstract的,所以一个函数式接口里可以定义任意多的默认方法,这取决于你。

  同时,引入了一个新的Annotation:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。加上它的接口不会被编译,除非你设法把它变成一个函数式接口。它有点像@Override,都是声明了一种使用意图,避免你把它把它用错。

  Lambdas

  一个函数式接口非常有价值的属性就是他们能够用lambdas来实例化。这里有一些lambdas的例子:

  左边是指定类型的逗号分割的输入列表,右边是带有return的代码块:

  ?1(int x, int y) -> { return x + y; }

  左边是推导类型的逗号分割的输入列表,右边是返回值:

  ?1(x, y) -> x + y

  左边是推导类型的单一参数,右边是一个返回值:

  ?1x -> x * x

  左边没有输入 (官方名称: "burger arrow"),在右边返回一个值:

  ?1() -> x

  左边是推导类型的单一参数,右边是没返回值的代码块(返回void):

  1x -> { System.out.println(x); }

  静态方法引用:

  1String::valueOf

  非静态方法引用:

  1Object::toString

  继承的函数引用:

  1x::toString

  构造函数引用:

  1ArrayList::new

  你可以想出一些函数引用格式作为其他lambda格式的简写。 

     excepiton

     翻译于 3年前

   方法引用 等价的lambda表达式

   String::valueOf

  x -> String.valueOf(x)

  Object::toString

  x -> x.toString()

  x::toString

  () -> x.toString()

  ArrayList::new

  () -> new ArrayList<>()

  当然,在Java里方法能被重载。类可以有多个同名但不同参数的方法。这同样对构造方法有效。ArrayList::new能够指向它的3个构造方法中任何一个。决定使用哪个方法是根据在使用的函数式接口。

  一个lambda和给定的函数式接口在“外型”匹配的时候兼容。通过“外型”,我指向输入、输出的类型和声明检查异常。

  给出两个具体有效的例子:

  2Comparator c = (a, b) -> Integer.compare(a.length(),

  b.length());

  一个Comparator的compare方法需要输入两个阐述,然后返回一个int。这和lambda右侧的一致,因此这个任务是有效的。

  1Runnable r = () -> { System.out.println("Running!"); }

  一个Runnable的run方法不需要参数也不会返回值。这和lambda右侧一致,所以任务有效。

  在抽象方法的签名里的受检查异常(如果存在)也很重要。如果函数式接口在它的签名里声明了异常,lambda只能抛出受检查异常。

赞(14)
踩(3)
分享到:
华为认证网络工程师 HCIE直播课视频教程