jdk8系列2、jdk8方法引用、重复注解、更好的类型推断、新增注解

1、方法引用

  方法引用使得开发者能够直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有不少复杂的模板代码。html

方法引用包括几种状况:java

  • 静态方法引用
  • 构造方法引用
  • 类成员方法引用
  • 对象方法引用

例子中,Car类是不一样方法引用的例子,能够帮助读者区分四种类型的方法引用。oracle

package com.study.demo.TestRefernce;

import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;

public class Car {
    private String name ="I am a car";

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }

    public static Car create(final Supplier< Car > supplier ) {
        return supplier.get();
    }

    public static void collide( Car car ) {
        System.out.println( "Collided " + car.toString() );
    }

    public void follow( Car another ) {
        System.out.println( "Following the " + another.toString() );
    }

    public void repair() {
        System.out.println( "Repaired " + this.toString() );
    }

    public static void main(String[] args) {
        final Car car = Car.create(Car::new);
        final List< Car > cars = Arrays.asList( car ,Car.create(Car::new));

        cars.forEach(Car::collide );
        cars.forEach(Car::repair);

        final Car car1 = Car.create(Car::new);
        cars.forEach(car1::follow);
    }
}

一、构造方法引用

方法引用的类型是构造器引用,语法是Class::new,或者更通常的形式:Class<T>::new。注意:这个构造器没有参数。
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );

二、静态方法引用

方法引用的类型是静态方法引用,语法是Class::static_method。注意:这个方法接受一个Car类型的参数。
cars.forEach( Car::collide );

三、类成员方法引用

一、无参方法引用

方法引用的类型是某个类的成员方法的引用,语法是Class::method,注意,这个方法没有定义入参:
cars.forEach( Car::repair );

也能够这样:框架

cars.forEach(c -> c.repair());

二、有参方法引用

final Car police = Car.create(Car::new);
cars.forEach((car1) -> police.follow(car1));

四、对象方法引用

与类方法引用不一样的是, 对象方法引用方法的调用者是一个外部的对象。以下图方法引用的类型是某个实例对象的成员方法的引用,语法是instance::method。注意:这个方法接受一个Car类型的参数:
final Car police = Car.create( Car::new );
cars.forEach( police::follow );

运行上述例子,能够在控制台看到以下输出(Car实例可能不一样):ide

若是想了解和学习更详细的内容,能够参考 官方文档

3、重复注解

  自从Java 5中引入注解以来,这个特性开始变得很是流行,并在各个框架和项目中被普遍使用。不过,注解有一个很大的限制是:在同一个地方不能屡次使用同一个注解。Java 8打破了这个限制,引入了重复注解的概念,容许在同一个地方屡次使用同一个注解。函数

  在Java 8中使用@Repeatable注解定义重复注解,实际上,这并非语言层面的改进,而是编译器作的一个trick,底层的技术仍然相同。能够利用下面的代码说明。学习

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class RepeatingAnnotations {
    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    public @interface Filters {
        Filter[] value();
    }

    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    @Repeatable( Filters.class )
    public @interface Filter {
        String value();
    };

    @Filter( "filter1" )
    @Filter( "filter2" )
    public interface Filterable {        
    }

    public static void main(String[] args) {
        for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
            System.out.println( filter.value() );
        }
    }
}

正如咱们所见,这里的Filter类使用@Repeatable(Filters.class)注解修饰,而Filters是存放Filter注解的容器,编译器尽可能对开发者屏蔽这些细节。这样,Filterable接口能够用两个Filter注解注释(这里并无提到任何关于Filters的信息)。this

另外,反射API提供了一个新的方法:getAnnotationsByType(),能够返回某个类型的重复注解,例如Filterable.class.getAnnoation(Filters.class)将返回两个Filter实例,输出到控制台的内容以下所示:spa

filter1
filter2

若是你但愿了解更多内容,能够参考官方文档code

4、更好的类型推断

Java 8编译器在类型推断方面有很大的提高,在不少场景下编译器能够推导出某个参数的数据类型,从而使得代码更为简洁。例子代码以下:

public class Value< T > {
    public static< T > T defaultValue() { 
        return null; 
    }

    public T getOrDefault( T value, T defaultValue ) {
        return ( value != null ) ? value : defaultValue;
    }
}

下列代码是Value<String>类型的应用:

public class TypeInference {
    public static void main(String[] args) {
        final Value< String > value = new Value<>();
        value.getOrDefault( "22", Value.defaultValue() );
    }
}

参数Value.defaultValue()的类型由编译器推导得出,不须要显式指明。在Java 7中这段代码会有编译错误,除非使用Value.<String>defaultValue()

5、拓宽注解的应用场景

Java 8新增的两个注解:

  • ElementType.TYPE_USER:注解泛型
  • ElementType.TYPE_PARAMETER:注解参数

Java 8拓宽了注解的应用场景。如今,注解几乎可使用在任何元素上:局部变量、接口类型、超类和接口实现类,甚至能够用在函数的异常定义上。下面是一些例子:

package com.javacodegeeks.java8.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;

public class Annotations {
    @Retention( RetentionPolicy.RUNTIME )
    @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
    public @interface NonEmpty {        
    }

    public static class Holder< @NonEmpty T > extends @NonEmpty Object {
        public void method() throws @NonEmpty Exception {            
        }
    }

    @SuppressWarnings( "unused" )
    public static void main(String[] args) {
        final Holder< String > holder = new @NonEmpty Holder< String >();        
        @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();        
    }
}
相关文章
相关标签/搜索