2017-02-19 2 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[] {}); 
} 

저는 Function과 BiFunction을 사용해 보았지만 abit를 잃어 버렸습니다. 그런 사례를 구현하는 방법에 대한 스 니펫을 제공 할 수 있습니까?

+4

목표는 무엇입니까? 코드를 난독 화합니까? 람다 (lambda)를 사용하는 것이 유용한 경우가 많이 있지만, 실제로는 이들 중 하나가 아닙니다. –

+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에 루프를 넣어 이유가 없습니다. 여기서 비효율적 인 구현을 사용하고자하기 때문에 여기에 함수가 있기를 원하지만 람다 식에서는 전혀 액세스하지 못합니다. 그들은 필드에 액세스 할 수 있으며, 기능 인터페이스를 구현하는 인스턴스는 인데,이 필드가 인 경우 원하지 않는 필드에 저장됩니다. 로컬 람다 표현식을 사용하면 재귀를 수행 할 수 없습니다. 직진 루프와

, 당신은 단지 생각

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과 같은 목적을 설명하는 명명 된 메서드에 루프를 캡슐화하는 것은 실제로 좋은 방법입니다. 노출시키지 않으려면 public 대신 private을 선언하십시오.

+0

이 문제에 대한 귀납적 또는 재귀 적 접근법은 물론 재귀 적 접근법을 사용하여 아무 것도 얻지 못하는 것에 대해 매우 옳았음에도 불구하고 주제가 아니었고 & 유도적인 방법은 rec 1보다 훨씬 더 정당합니다. javaScript에서와 마찬가지로 함수형 프로그래밍 방법론에 더 많은 관심이있었습니다. 참조를 만들지 않거나 메서드 참조를 만들지 않는 익명 메소드를 만들 수 있습니다. 로컬 메서드 참조, 자바 8에서 이것을보고 싶었습니다. – Benma

+0

람다 식은 anony와 같습니다 (사실, 그것들은 하나의 메소드로 컴파일된다.)하지만 재귀 적으로 호출 할 수는 없다. 음, 메소드 호출 문법에는 메소드 이름이 필요합니다 ... – Holger

2

이것은 (아직) 직접적으로 가능하지 않습니다. 자바 구에서 Stream 클래스는 다음과 같이 구현할 수있는 iterate 방법이됩니다 그러나

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

, 이미 원하는 기능의 좋은 깨끗한 구현이 가지고있는 getAllFields 방법을하고, 이름이 명확하게 밝혀집니다 이 방법은 무엇입니까. 기능 구현은 이해하기가 훨씬 어려울 것입니다.