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<>();        
    }
}
相關文章
相關標籤/搜索