JDK1.8的新特性(Lambda表达式等)(一)

一、接口的默认方法

Java 8允许在接口中添加非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:

interface iNews{
    List getAllNews();

    default int aadd(int a){
          return a*100;
    }
}

iNews接口的子类只需要实现getAllNews();这个方法就可以了,默认就会带有getDate()这个方法不需要再实现。

二、Lambda表达式

我先举一个例子,示例代码如下:

  //定义一个stringlist
  List names = Arrays.asList("Lucy","XiaoMing","Mike");
  //排序
  Collections.sort(names,Comparator() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});

老版本中的做法就是给静态方法Collections.sort方法传入一个list对象还有一个比较器来指定顺序排列。通常做法都是创建一个匿名的比较器对象然后传给sort方法。

但是在Java 8 中就没有必要再这样做了,Java8中提供了更加简洁的方式:Lambda表达式
直接上示例代码:

  //定义一个stringlist
  List names = Arrays.asList("Lucy","XiaoMing","Mike");
  //排序
  Collections.sort(names,(String a,String b) ->{
      return b.compareTo(a);
  });

只用Lambda表达式代码变得更加简洁了,但是还可以变短,示例代码如下:

  //排序
  Collections.sort(name,(String a , String b) -> b.compareTo(a) );

如果函数体只有一行代码,那么可以直接去掉大括号{}还有return关键字,但实际上还可以更短

  //排序
  Collections.sort(name,(a,b) -> b.compareTo(a));

Java编译器可以自动推导出来参数类型,所以你可以不用再写参数类型。

三、函数式接口

Lambda表达式是如何在Java的类型系统中表示的呢?每一个Lambda表达式都表示对应一个类型,通常是接口类型。而函数式接口就是指只有一个抽象方法的接口,每一个该类型的Lambda表达式都会匹配到这个抽象方法。因为默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
默认方法指的就是Java8中的新特性——给接口添加一个默认方法,具体有在第一点讲到

我们可以将Lambda表达式当做任意一个只包含一个抽象方法的接口类型,确保你的接口达到了这个要求,可以使用一个注解:@FunctionalInterface ,这个注解的作用也是非常简单明了,把这个注解贴在接口上,如果这个接口有多余一个的抽象方法,就会报错。(再直白点,就是贴上了之后,这个接口只能有一个抽象方法,多了就报错)。

实例代码如下:

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

四、方法与构造函数

前一节的代码还可以通过静态方法来引用,示例代码如下:

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

Java8允许你使用::关键字来传递方法或者是构造函数的引用,上面的代码引用的是一个静态方法,我们还可以引用一个对象的方法,示例代码如下:

converter = something::startsWith;
String converted = converter.convert("java");
System.out.println(converted);    //j

接下来来试试构造函数的引用,先创建一个具有多个构造函数的简单Java类,示例代码如下:

class Person{
    String name;
    Double money;
}

Person(){
}
Person(String name , Double money){
    this.name = name;
    this.money = money;
}

接下来指定一个用来创建Person对象的对象工厂接口,示例代码如下:

interface PersonFactory

{ P create(String name, Double money); }

我们使用构造函数把他们关联起来,而不是实现一个完整的工厂,示例代码如下:

PersonFactory personFactory = Person::new;
Person person = personFactory.create("小明",1000.0);

我们使用的时候,只需要用Persion :: new来获取Person类的构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。

五、访问局部变量

我们可以直接在lambda表达式中访问外层的局部变量,示例代码如下:

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

但是这里的 final int num可以不用final 修饰,代码同样正确,但是如果去掉了final的话,num变量就不能被后面的代码修改(其实就是final了),如果被后面的代码修改了,代码就无法被编译。

六、访问对象字段与静态变量

和本地变量不同的是,lambda内部对于实例的字段以及静态变量是又可读又可写。
示例代码如下:

class lambda {
  static int staticNum;
  int num;
  void test(){
    Converter stringConverter1 = (from) ->{
       staticNum = 123;
       return String.valueOf(from)  
    };
    Converter stringConverter2= (from) ->{
       num = 123;
       return String.valueOf(from)  
    };
  }
}

七、访问接口的默认方法

还记得第一节的例子吗?一个接口除了抽象方法,还可以定义一个默认方法,这个方法可以被它的实例对象或者是匿名对象访问,但是这个在Lambda中是不行的。
Java8 API提供了很多全新的函数式接口让工作更加方便:

  1. Predicate接口
    Predicate接口只有一个参数,返回boolean类型,其中包含了很多默认方法来组成复杂的逻辑
    示例代码如下:
Predicate predicate = (s) -> s.length() > 0 ;
predicate.test("foo");    //true
predicate.negate().test("foo");     // false

Predicate nonNull = Objects::nonNull;
Predicate isNull = Objects::isNull;

Predicate isEmpty = String::isEmpty;
Predicate isNotEmpty = isEmpty.negate();
  1. Supplier 接口
    Supplier接口返回一个任意范围的值,和Function接口不同的是这个接口没有任何参数
    示例代码如下:
Supplier personSupplier = Person :: new
personSupplier.get();    //new Person
  1. Consumer接口
    Consumer接口代表在单个参数上执行的操作
    示例代码如下:
Consumer con = (p) -> System.out.println("Hello,"+p.name);
con.accept(new Person("Lucy",500.0));      //Hello,Lucy
  1. Comparator接口
    Comparator是以前版本中的经典接口,Java8在此之上添加了多种默认方法
    示例代码如下:
Comparator comparator = (p1,p2) -> p1.name.comparaTo(p2.name);
Person p1 = new Person("小明",100.0);
Person p2 = new Person("小红",100.0);
comparator.compara(p1,p2);
comparator.reversed().compare(p1, p2);
  1. Optional接口
    Optional不是函数是接口,这个是用来防止NullPointerException异常的辅助类型
    Optional被定义为一个简单的容器,其值可能是null或者不是null。在Java8之前一般某个函数应该返回非空对象但是偶尔会返回null,而在Java8中,不推荐你返回null,而是返回Optional

你可能感兴趣的:(JDK1.8的新特性(Lambda表达式等)(一))