2016-10-25 3 views
2

새로운 Java 8 기능을 천천히 배우고 클래스 계층 구조 (하위에서 상위까지)를 스트림으로 처리하는 방법을 찾으려고합니다.Java8 클래스 계층 구조 스트리밍

예를 들어 클래스 또는 그 부모에 대한 주석을 찾습니다.

자바 8 전에, 나는 이런 식으로했을 :

public static <T extends Annotation> T getAnnonationOn(Class<?> type, Class<T> annType) { 
    Class<?> t = type; 
    T annot = null; 
    while (t != null && annot == null) { 
     annot = t.getAnnotation(annType); 
     t = t.getSuperclass(); 
    } 
    return annot; 
} 

은 이제 더 "함수형 프로그래밍"방법으로 그것을하고 싶습니다. 나는 다음과 같은 재귀와 CONCATENATE 스트림보다 더 좋은 방법을 찾을 수 없습니다 :

import java.lang.annotation.Annotation; 
import java.util.stream.Stream; 

public static <T extends Annotation> T getAnnonationOn(Class<?> type, Class<T> annType) { 
    return ClassIterator.streamSuperclass(type) 
     .map(t -> t.getAnnotation(annType)) 
     .filter(a -> a != null) 
     .findFirst() 
     .orElse(null); 
} 

public static class ClassIterator { 
    public static Stream<Class<?>> streamSuperclass(Class<?> type) { 
     if (type.getSuperclass() != null) { 
      return Stream.concat(Stream.of(type), Stream.of(type.getSuperclass()).flatMap(ClassIterator::streamSuperclass)); 
     } 
     return Stream.of(type); 
    } 
} 

하지만이 솔루션의 매우 만족 아닙니다. 벤치마킹을하지는 않았지만 스트림 연결이 상당히 복잡하고 성능이 좋지 않다고 생각합니다.

재귀를 스트림으로 전환하는 더 좋은 방법이 있습니까?

+1

기본적으로, 여러분은 'takeWhile' (슈퍼 클래스를 반복하고 널이 아닌 동안 가져옵니다)을 찾고 있습니다. http : // stackoverflow를 참조하십시오. co.kr/questions/20746429/limit-a-stream -by-a-predicate – Tunaki

+1

'takeWhile()'이 Java 9로 들어갑니다. 또한'for' 스타일 루프를 모델링 할 수있는'Stream.iterate()'의 3 인수 버전입니다. –

답변

3

자바 9에서, 당신은 아마

public static Stream<Class<?>> streamSuperclass(Class<?> type) { 
    return Stream.iterate(type, Objects::nonNull, Class::getSuperclass); 
} 

을 사용하지만, 수동으로 스트림을 구현하기 위해 의지 할 수 있도록 자바 (8),이 기능은 사용할 수 없습니다 :이 그

public static Stream<Class<?>> streamSuperclass(Class<?> type) { 
    return StreamSupport.stream(
     new Spliterators.AbstractSpliterator<Class<?>>(100L, 
      Spliterator.ORDERED|Spliterator.IMMUTABLE|Spliterator.NONNULL) { 
      Class<?> current = type; 
      public boolean tryAdvance(Consumer<? super Class<?>> action) { 
       if(current == null) return false; 
       action.accept(current); 
       current = current.getSuperclass(); 
       return true; 
      } 
     }, false); 
} 

주 가장 구체적인 유형에서 java.lang.Object으로 스트리밍됩니다. 순서가 Object에서 가장 구체적인 순서로 이루어 지도록하려면 재귀 적이든 반복적이든 상관없이 요소를 수집하는 방법은 없지만 Stream.concat은 실제로 성능이 가장 낮은 변형입니다.

일반적인 클래스 계층 구조로 작은 스트림
public static Stream<Class<?>> streamSuperclass(Class<?> type) { 
    List<Class<?>> l=new ArrayList<>(); 
    for(; type!=null; type=type.getSuperclass()) l.add(type); 
    Collections.reverse(l); 
    return l.stream(); 
} 

, ArrayListStream.Builder에 비해 매우 큰 스트림하지 나쁘다 : 당신은 단순히 반복적 인 변형도 그렇게 나쁘지 않다

public static Stream<Class<?>> streamSuperclass(Class<?> type) { 
    return reverse(Stream.<Class<?>>builder(), type, Class::getSuperclass).build(); 
} 
private static <T> Stream.Builder<T> reverse(
     Stream.Builder<T> builder, T t, UnaryOperator<T> op) { 
    return t==null? builder: reverse(builder, op.apply(t), op).add(t); 
} 

사용할 수 있습니다 재귀를 사용하여 빌더를 채우는 것이 최상의 솔루션이 아닐 수도 있습니다 ...