2016-07-26 50 views
2

我正在學習有關在Java 8中存在的FunctionalInterface。在做了一些基本的功能性示例之後,我試圖對GenericType參數進行相同的操作。Java 8通用java.util.Function

public class Main { 

    public enum LocType { 
     Area, Country 
    } 

    public <T> Function<T, T> getCreateFunction(LocType type) { 

     AreaService areaService = new AreaService(); 
     CountryService countryService = new CountryService(); 
     switch(type) { 
      case Area : return areaService::createArea; 
      case Country : return countryService::createCountry; 
      default : return null; 
     } 
    } 

} 

public class AreaService { 

    public Area createArea(Area area) { 
     // some logic 
     return area; 
    } 

} 

public class CountryService { 

    public Country createCountry(Country country) { 
     // some logic 
     return country; 
    } 

} 

// Area & Country are Model Classes 

但是Eclipse編譯器會引發錯誤的

The type AreaService does not define createArea(T) that is applicable here

難道就沒有可能在FunctionalInterface定義泛型類型參數..?

+7

您不能有一個泛型函數,其返回類型取決於運行時參數:返回類型在編譯時確定;該參數的值僅在運行時才知道。 –

+0

此外,看起來對我很可疑。這就是說這個泛型依賴於兩種類型,但它們必須是相同的。除非我錯過了什麼?編輯:等等,我現在看到,沒關係。 –

+1

目前還不清楚'createArea()'和'createCountry()'的返回類型是什麼。此外,您可能需要考慮'UnaryOperator '而不是'Function '(假設這裏是正確的)。 – shmosel

回答

3

您可以使用Class類作爲一個類型的令牌在這裏。 (我會忽略你發佈的代碼的一些明顯問題,比如不能撥打new AreaService()等)。相反定義的事物類型的枚舉,你希望你的函數來創建(操作?),使用Class作爲參數:

@SuppressWarnings("unchecked") 
public <T> Function<T, T> getCreateFunction(Class<T> type) { 

    AreaService areaService = new AreaService(); 
    CountryService countryService = new CountryService(); 
    if (type == Area.class) { 
     return t -> (T) areaService.createArea((Area)t); 
    } else if (type == Country.class) { 
     return t -> (T) countryService.createCountry((Country)t); 
    } 
    return null ; // may be better to throw an IllegalArgumentException("Unsupported type") 
} 

現在你可以做的事情,如

Main main = new Main(); 
Function<Area, Area> areaChanger = main.getCreateFunction(Area.class); 
Function<Country, Country> countryChanger = main.getCreateFunction(Country.class); 

的這種方式的工作原理是類對於任何類T是類型Class<T>。所以Area.class的型號爲Class<Area>,而Country.class的型號爲Class<Country>

因此,如果你打電話getCreateFunction(Area.class),編譯器可以推斷T是在調用Area,並且返回類型就Function<Area, Area>。另一方面,在執行getCreateFunction時,雖然編譯器只能推斷參數爲lambda是未知類型T,但我們知道它T必須是由參數type表示的類型;即如果type==Area.class,我們可以安全地投tArea和(從areaService.createArea返回的值)AreaT。因此這些演員陣容是安全的(即使演員陣容是未知類型T)。

如果您想進一步限制可以傳遞給getCreateFunction(...)的值,您可以定義一個標記接口:例如, public interface Region { }並使AreaCountry實現該接口。然後定義

public <T extends Region> Function<T,T> getCreateFunction(Class<T> type) {...} 

,它只會是有效傳遞令牌類爲實現(即延長或接口)Region類。

+0

我想知道'FunctionalInterface'的真正目的是什麼,如果它不能用於泛型類型參數,那麼直到現在.. !!看起來我們可以定義泛型類型參數,但不能以'::'通常的方式。謝謝.. –

+0

你是什麼意思?我只是向您展示瞭如何將它用於泛型類型參數。 –

+0

編輯評論。只是一個錯誤的溝通。 –

0

可以定義泛型類型參數。你可以找到例子在JDK像

andThen

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { 
    Objects.requireNonNull(after); 
    return (T t) -> after.apply(apply(t)); 
} 

identity

static <T> Function<T, T> identity() { 
    return t -> t; 
} 

什麼在你的例子不工作是areaService::createAreacountryService::createCountryFunctions的具體類型。

編譯器無法將Area分配到泛型類型T。由於T可以是任何東西,即IntegerStream