2017-02-19 104 views
1

我的目標是通過將其重寫爲匿名函數將getAllFields方法遷移到init中,我知道這很有可能使用函數式編程。Java 8,匿名遞歸嵌套方法

public void init(){ 

} 

public static Field[] getAllFields(Class klass) { 
    List<Field> fields = new ArrayList<Field>(); 
    fields.addAll(Arrays.asList(klass.getDeclaredFields())); 
    if (klass.getSuperclass() != null) { 
     fields.addAll(Arrays.asList(getAllFields(klass.getSuperclass()))); 
    } 
    return fields.toArray(new Field[] {}); 
} 

我試過使用函數也BiFunction但得到了丟失的技能。 任何人可以給如何實施這種情況下的片段?

+4

目標是什麼?混淆你的代碼?有很多情況下使用lambdas是有用的,但這實際上不是其中之一。 –

+0

請顯示您嘗試過的內容,並解釋您遇到的問題。 – shmosel

+0

我不同意,我認爲一旦你的整個代碼邏輯被封裝在1個方法中,它就更容易維護 – Benma

回答

1

getAllFields實施是非常低效率,創建多個ArrayList實例和數組,重複地在它們之間來回複製整個數據。值得慶幸的是,階級層級很少深刻,這成爲一個瓶頸。

不過,你可以用一個直接的循環,這是更簡單,更高效的實現這一點:

public static Field[] getAllFields(Class<?> klass) { 
    List<Field> fields = new ArrayList<>(); 
    for(; klass!=null; klass=klass.getSuperclass()) 
     Collections.addAll(fields, klass.getDeclaredFields()); 
    return fields.toArray(new Field[0]); 
} 

沒有從這裏使用遞歸半點好處。

有了一個循環,你可以輕鬆地創建一個Function如果你真的想:

public void init(){ 
    Function<Class<?>,Field[]> f = klass -> { 
     List<Field> fields = new ArrayList<>(); 
     for(; klass!=null; klass=klass.getSuperclass()) 
      Collections.addAll(fields, klass.getDeclaredFields()); 
     return fields.toArray(new Field[0]); 
    }; 
    Field[] someFields = f.apply(SomeClass.class); 
} 

雖然,當然,竟然沒有把環路成Function在所有的理由。由於希望使用低效的遞歸實現,因此您只想在此處有一個函數,但lambda表達式根本不支持訪問它們。他們只能訪問字段,實現功能接口的實例已存儲到該實例中,如果存儲在您不想要的字段中,那麼它們就是。用本地lambda表達式,遞歸是不可能的。

有了直接的循環,你可以只寫

public void init(){ 
    List<Field> fields = new ArrayList<>(); 
    for(Class<?> klass=SomeClass.class; klass!=null; klass=klass.getSuperclass()) 
     Collections.addAll(fields, klass.getDeclaredFields()); 
    Field[] someFields = fields.toArray(new Field[0]); 
} 

不過,實際上,很少有針對fields內容複製到陣列中的真正的原因,你可以只用List<Field>工作,而不是。這就是說,將循環封裝到描述其目的的命名方法中,如getAllFields,實際上是一件好事。如果您不想公開它,請將其聲明爲private而不是public

+0

這個問題的歸納或遞歸方法並不是主題,儘管當然你對於使用遞歸方法獲得一無所獲當然是非常正確的&我完全接受這樣一個事實,即歸納方式遠比rec 1更合理,我像在javaScript中一樣更關心函數式編程方法,它允許創建一個匿名方法,它不會創建引用,也不會創建方法引用,只會檢索值一個本地方法的參考,希望能在java 8中看到這個。 – Benma

+0

lambda表達式就像一個anony mous方法(實際上,它們被編譯爲一個方法),但它不能遞歸地調用它自己。那麼,方法調用語法需要一個方法名稱...... – Holger

2

這還不是直接可能的。在Java中9,Stream類將有一個iterate方法,這使得實現這個如下:

Field[] allFields = Stream 
    .iterate((klass, Objects::nonNull, Class::getSuperclass) 
    .flatMap(c -> Stream.of(c.getDeclaredFields())) 
    .toArray(Field[]::new); 

然而,getAllFields方法,你已經是一個很好的,乾淨實現所需的功能,以及名稱明確清除這個方法做什麼。功能實現將更難以理解。