[原创]Java 8 新特效与功能和改进总览_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3441 | 回复: 0   主题: [原创]Java 8 新特效与功能和改进总览        下一篇 
匿名用户
发表于: IP:您无权察看 2014-8-21 20:49:54 | [全部帖] [楼主帖] 楼主

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

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

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

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

接口的默认方法 Default Methods for Interfaces:
Lambda 表达式
函数式接口
方法和构造函数的引用
Lambda作用域


一、接口的默认方法 Default Methods for Interfaces:


Java8允许我们使用default 关键字来实现对非抽象方法的实现,例:

interface Formula {
      double calculate(int a);
      default double sqrt(int a) {
            return Math.sqrt(a);
      }
}


看,Formula定义了一个抽象方法calculate,然后又定义了一个默认方法sqrt,具体的类只要实现抽象方法calculate即可,默认方法可以直接使用。

Formula formula = new Formula() {
      @Override
      public double calculate(int a) {
            return sqrt(a * 100);
      }
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0


上面的这段代码中,formula是通过匿名对象实现的。当然,这段代码看起来过于繁琐,用6行代码实现一个小小的计算sqrt(a * 100),不过在下面我们会看到Java8用更加帅气的方式实现单个方法对象的做法,那就是

二、Lambda 表达式

让我们先来一个小例子:看看在之前的Java版本中如何实现对String字符串进行排序

    

List names = Arrays.asList("peter", "anna", "mike", "xenia");

Collections.sort(names, new Comparator() {
      @Override
      public int compare(String a, String b) {
            return b.compareTo(a);
      }
});


Collections.sort这个方法的参数是一个列表和一个比较器,它可以对你给出的list进行排序。这样你就发现经常需要创造一些匿名的comparators来进行排序方法。

为了取代一直以来的创造匿名对象的方式,Java8推出了更加简洁的语法:lambda表达式:

Collections.sort(names, (String a, String b) -> {
      return b.compareTo(a);
});


就像你看见的这段代码,它,更加的简洁,更加的清晰易读,但是,它还可以更加的简洁:

Collections.sort(names, (String a, String b) -> b.compareTo(a));


这行代码,你可以省略掉{}和关键字return,但是还可以更简洁:

Collections.sort(names, (a, b) -> b.compareTo(a));


Java编译器可以自动判断参数类型,因此,类型也可以省略

感受到了简洁的语法后,我们需要深入了解一下,看看Lambda表达式怎样在实际工作中使用:

三、函数式接口

Lambda表达式是怎样匹配Java类型系统呢?通过接口指定,每一个lambda对应一个给定的类型。一个被称为函数式接口必须要包含一个准确的抽象方法的声明。这样每个lambda和它的对应类型将会匹配到个抽象方法。因为default method不是抽象的,所以可以自由的在函数式接口中添加default方法
只要这个接口包含唯一的一个抽象方法,我们就可以使用任意的接口。为了确定你的接口满足要求,需要添加一个@FunctionalInterface注解,这样,当你试图给这个接口添加第二个抽象方法声明的时候,编译器就会自动感知,会抛出一个编译期错误。

栗子:

@FunctionalInterface
interface Converter {
      T convert(F from);
}
Converter converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123


记住:如果代码中没有写注解 @FunctionalInterface,那么也是错误的!

四、方法和构造函数的引用

上面实例的代码通过使用静态函数引用可以进一步的简化

Converter converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted); // 123


Java 8 允许你使用关键字 :: 来引用方法和构造器。上面的代码显示的是怎样引用一一个静态方法。但是我们同样,也可以引用对象方法。

class Something {
      String startsWith(String s) {
            return String.valueOf(s.charAt(0));
      }
}
Something something = new Something();
Converter converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted); // "J"


让我们看看 :: 关键字对于构造方法是如何工作的。首先我们需要构造一个带有不同构造器的bean实例:

class Person {
      String firstName;
      String lastName;
Person() {}
      Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
      }
}


然后我们来指定一个person 工厂接口,为创建person对象时使用:

interface PersonFactory
{
      P create(String firstName, String lastName);
}


我们可以通过构造器引用来连接所有的东西,来取代手动的创建工厂

PersonFactory personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");


我们通过Person::new 创建了一个Person构造器的引用,Java编译器会通过PersonFactory.create的方法签名,匹配到正确的构造器方法。

4、Lambda作用域

从Lambda表达式中获取外部作用域变量的方式与匿名对象的方式非常相似,你可以获取final变量从局部外部变量中,跟实例域和静态变量一样。
获取局部变量
我们可以读取final局部变量从lambda表达式的外部作用域中

final int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3


但是不同于匿名对象,变量num不需要必须设置���final,下面的代码同样有效:

int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3


然而,num是一个隐式的final局部变量,编译器才能通过。下面这段代码就不会编译通过:

int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
num = 3;


在Lambda表达式内部修改num的值同样是不被允许的。你只要把这个变量看做final修饰的即可,只是final没有写出来罢了。

获取实体域和静态变量
不同于局部变量,我们在具有Lambda表达式的代码中,可以对实体域和静态变量进行读和写的权利。这种方式同样在匿名对象中为我们所熟知。

class Lambda4 {
      static int outerStaticNum;
      int outerNum;
      void testScopes() {
            Converter stringConverter1 = (from) -> {
                  outerNum = 23;
                  return String.valueOf(from);
            };
            Converter stringConverter2 = (from) -> {
                  outerStaticNum = 72;
                  return String.valueOf(from);
            };
      }
}


获取默认接口方法:
还记得开头讲述的formula 那个栗子吗?接口fomula定义个一个默认方法:sqrt,可以被包含匿名对象的每一个formula实例使用,这种机制跟lambda表达式无关

默认方法不能被lambda表达式使用,下面的代码不能被编译:

Formula formula = (a) -> sqrt( a * 100);


原文地址: http://tngou.yi18.net/articles/2014/08/21/1408624533071.html



赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论