자바 8 방법 참조 사용 안내

[편집자 의 말]본 고 는 저자 가 15 년 동안 자바 개발 경험 을 가 진 베테랑 프로그래머 인 Per-Å ke Minborg 를 위해 자바 의 방법 을 어떻게 유연 하 게 해석 하 는 지 소개 한다.문장 과 국내 ITOM 관리 플랫폼 OneAPM 컴 파일 구현.
방법 참조
자바 8 에서 우 리 는 방법 으로 인용 할 수 있다 는 것 은 잘 알려 져 있다.예 를 들 어 우리 가 스 트림 요 소 를 옮 겨 다 닐 때String::isEmpty방법 을 참조 할 수 있다.다음 코드 를 보십시오.
Stream.of("A", "", "B").filter(Stream::isEmpty).count();

실행 결 과 는 1 입 니 다.그러나 빈 문자열 을 걸 러 내 려 면isEmpty으로 써 야 합 니 다.이것 은 Lambda 표현 식 입 니 다.분명히 여기 에는 싫 은 비대 칭 상상 이 있다.우 리 는 방법 을 써 서 인용 할 수 있 지만,그것 의 반식 을 써 서 는 안 된다.우 리 는 쓸 수 있 지만 쓸 수 없다.filter(s -> !s.isEmpty())또는predicate.negate().
왜 일 까요?람 다 표현 식 이나 함수 인터페이스 가 아 닌 방법 을 인용 하기 때 문 입 니 다.단,자바 의 유형 추 도 를 사용 하면 방법 인용 을 하나 이상 의 함수 인터페이스 로 해석 할 수 있 습 니 다.상례Stream::isEmpty.negate()는 적어도 다음 과 같이 해석 할 수 있다.
Predicate<String>
Function<String, Boolean>

따라서 우 리 는 다른 가능성 을 배제 하고 방법 인용 을 어떤 함수 인터페이스 로 바 꾸 는 지 확인 해 야 한다.본문 은 어느 정도 에 이 문 제 를 해결 했다.글 의 코드 는 오픈 소스 프로젝트 Speedment 에서 나 왔 습 니 다.데이터 베 이 스 를 자바 8 의 흐름 처럼 보이 게 합 니 다.
해석 방법 참조
사실은 정적 방법 을'파이프'로 하여 이 문 제 를 부분적으로 해결 할 수 있 습 니 다.이 정적 방법 은 하나의 방법 으로 입력 하고 특정한 함수 인 터 페 이 스 를 되 돌려 줍 니 다.아래 의 간단 한 정적 방법 을 고려 해 보 세 요.
public static <T> Predicate<T> as(Predicate<T> predicate) {
    return predicate;
}

지금 이 방법 을 정적 으로 가 져 오 면 사실상 우 리 는 더욱 간단하게 방법 을 인용 할 수 있다.다음 과 같은 예 에서 보 듯 이:
Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();

이 코드 가 되 돌아 온 결 과 는 2,즉 흐 르 는 비 공 원소 의 수량 입 니 다.방법 인용 에 관 한 사용 방식 에 대해 우 리 는 또 한 걸음 앞으로 나 아 갔다.또 다른 장점 은 이 솔 루 션 이 predicates 인 터 페 이 스 를 쉽게 만 드 는 것 입 니 다.예 를 들 어:
.filter(as(String::isEmpty).negate().and("A"::equals))

모든 방법 참조 분석
하지만 아직 해결 해 야 할 문제 가 있다.우 리 는 많은 정적!Stream::isEmpty함 수 를 마음대로 만 들 수 없다.왜냐하면 하나의 방법 은 여러 가지String::isEmpty방법 으로 해석 할 수 있 기 때문이다.본 고 에서 처음에 언급 한 것 처럼.따라서 더욱 절묘 한 해결 방안 은 함수 인터페이스 유형 명 을 모든 정적 방법 에 추가 하 는 것 이다.그러면 우 리 는 모든 함수 인터페이스 변환 방법 에 특정한 방법 을 선택 하여 인용 할 수 있다.모든 방법의 인용 을 자바 표준 패키지`java.util.function 에서 임의로 일치 하 는 함수 인터페이스 로 변환 할 수 있 는 도구 클래스 가 있 습 니 다.
GitHub 에서 최신 버 전 을 직접 다운로드 합 니 다.
import java.util.function.*;
/**
 *
 * @author Per Minborg
 */
public class FunctionCastUtil {
    public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
        return biConsumer;
    }
    public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
        return biFunction;
    }
    public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
        return binaryOperator;
    }
    public static <T, U> BiPredicate<T, U> asBiPredicate(BiPredicate<T, U> biPredicate) {
        return biPredicate;
    }
    public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) {
        return booleanSupplier;
    }
    public static <T> Consumer<T> asConsumer(Consumer<T> consumer) {
        return consumer;
    }
    public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) {
        return doubleBinaryOperator;
    }
    public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) {
        return doubleConsumer;
    }
    public static <R> DoubleFunction<R> asDoubleFunction(DoubleFunction<R> doubleFunction) {
        return doubleFunction;
    }
    public static DoublePredicate asDoublePredicate(DoublePredicate doublePredicate) {
        return doublePredicate;
    }
    public static DoubleToIntFunction asDoubleToIntFunction(DoubleToIntFunction doubleToIntFunctiontem) {
        return doubleToIntFunctiontem;
    }
    public static DoubleToLongFunction asDoubleToLongFunction(DoubleToLongFunction doubleToLongFunction) {
        return doubleToLongFunction;
    }
    public static DoubleUnaryOperator asDoubleUnaryOperator(DoubleUnaryOperator doubleUnaryOperator) {
        return doubleUnaryOperator;
    }
    public static <T, R> Function<T, R> asFunction(Function<T, R> function) {
        return function;
    }
    public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) {
        return intBinaryOperator;
    }
    public static IntConsumer asIntConsumer(IntConsumer intConsumer) {
        return intConsumer;
    }
    public static <R> IntFunction<R> asIntFunction(IntFunction<R> intFunction) {
        return intFunction;
    }
    public static IntPredicate asIntPredicate(IntPredicate intPredicate) {
        return intPredicate;
    }
    public static IntSupplier asIntSupplier(IntSupplier intSupplier) {
        return intSupplier;
    }
    public static IntToDoubleFunction asIntToDoubleFunction(IntToDoubleFunction intToDoubleFunction) {
        return intToDoubleFunction;
    }
    public static IntToLongFunction asIntToLongFunction(IntToLongFunction intToLongFunction) {
        return intToLongFunction;
    }
    public static IntUnaryOperator asIntUnaryOperator(IntUnaryOperator intUnaryOperator) {
        return intUnaryOperator;
    }
    public static LongBinaryOperator asLongBinaryOperator(LongBinaryOperator longBinaryOperator) {
        return longBinaryOperator;
    }
    public static LongConsumer asLongConsumer(LongConsumer longConsumer) {
        return longConsumer;
    }
    public static <R> LongFunction<R> asLongFunction(LongFunction<R> longFunction) {
        return longFunction;
    }
    public static LongPredicate asLongPredicate(LongPredicate longPredicate) {
        return longPredicate;
    }
    public static <T> LongSupplier asLongSupplier(LongSupplier longSupplier) {
        return longSupplier;
    }
    public static LongToDoubleFunction asLongToDoubleFunction(LongToDoubleFunction longToDoubleFunction) {
        return longToDoubleFunction;
    }
    public static LongToIntFunction asLongToIntFunction(LongToIntFunction longToIntFunction) {
        return longToIntFunction;
    }
    public static LongUnaryOperator asLongUnaryOperator(LongUnaryOperator longUnaryOperator) {
        return longUnaryOperator;
    }
    public static <T> ObjDoubleConsumer<T> asObjDoubleConsumer(ObjDoubleConsumer<T> objDoubleConsumer) {
        return objDoubleConsumer;
    }
    public static <T> ObjIntConsumer<T> asObjIntConsumer(ObjIntConsumer<T> objIntConsumer) {
        return objIntConsumer;
    }
    public static <T> ObjLongConsumer<T> asObjLongConsumer(ObjLongConsumer<T> objLongConsumer) {
        return objLongConsumer;
    }
    public static <T> Predicate<T> asPredicate(Predicate<T> predicate) {
        return predicate;
    }
    public static <T> Supplier<T> asSupplier(Supplier<T> supplier) {
        return supplier;
    }
    public static <T, U> ToDoubleBiFunction<T, U> asToDoubleBiFunction(ToDoubleBiFunction<T, U> toDoubleBiFunction) {
        return toDoubleBiFunction;
    }
    public static <T> ToDoubleFunction<T> asToDoubleFunction(ToDoubleFunction<T> toDoubleFunction) {
        return toDoubleFunction;
    }
    public static <T, U> ToIntBiFunction<T, U> asToIntBiFunction(ToIntBiFunction<T, U> toIntBiFunction) {
        return toIntBiFunction;
    }
    public static <T> ToIntFunction<T> asToIntFunction(ToIntFunction<T> ioIntFunction) {
        return ioIntFunction;
    }
    public static <T, U> ToLongBiFunction<T, U> asToLongBiFunction(ToLongBiFunction<T, U> toLongBiFunction) {
        return toLongBiFunction;
    }
    public static <T> ToLongFunction<T> asToLongFunction(ToLongFunction<T> toLongFunction) {
        return toLongFunction;
    }
    public static <T> UnaryOperator<T> asUnaryOperator(UnaryOperator<T> unaryOperator) {
        return unaryOperator;
    }
    private FunctionCastUtil() {
    }
}

정적 으로 관련 방법 을 가 져 온 후에 우 리 는 이렇게 쓸 수 있다.
Stream.of("A", "", "B").filter(asPredicate(String::isEmpty).negate()).count();

더 좋 은 해결 방안
함수 인터페이스 자체 에 수신 방법 을 인용 하여 특정한 함수 인터페이스 로 전환 하 는 정적 방법 이 포함 되 어 있다 면 더욱 좋 을 것 입 니 다.예 를 들 어 표준 자바as()함수 인 터 페 이 스 는 이렇게 됩 니 다.
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    default Predicate<T> and(Predicate<? super T> other) {...}
    default Predicate<T> negate() {...}
    default Predicate<T> or(Predicate<? super T> other) {...}
    static <T> Predicate<T> isEqual(Object targetRef) {...}
    // New proposed support method to return a 
    // Predicate view of a Functional Reference 
    public static <T> Predicate<T> of(Predicate<T> predicate) {
        return predicate;
    }
}

그래서 우 리 는 이렇게 쓸 수 있다.
Stream.of("A", "", "B").filter(Predicate.of(String::isEmpty).negate()).count();

필 자 는 이렇게 하 는 것 이 매우 좋아 보인다 고 생각한다!
가장 가 까 운 Open JDK 개발 자 에 게 연락 해서 수정 제안 을 하 세 요!
OneAPM 은 엔 드 에서 엔 드 까지 의 자바 응용 성능 솔 루 션 을 제공 할 수 있 습 니 다.저 희 는 흔히 볼 수 있 는 자바 프레임 워 크 와 응용 서버 를 지원 합 니 다.시스템 병목 을 신속하게 발견 하고 이상 근본 원인 을 찾 을 수 있 습 니 다.분 급 배치,즉각 체험,자바 모니터링 은 이렇게 간단 한 적 이 없 었 다.더 많은 기술 글 을 읽 으 려 면 OneAPM 공식 기술 블 로 그 를 방문 하 세 요.
본 고 는 OneAPM 공식 블 로그 에서 이전 되 었 다.
원본 주소:https://dzone.com/articles/put-your-java-8-method-references-to-work

좋은 웹페이지 즐겨찾기