Kotlin이 생성 한 불필요한 null 검사를 처리하는 방법은 무엇입니까?


9

다음의 최소 Kotlin 예제를 고려하십시오.

fun <U> someWrapper(supplier: () -> U): () -> (U) {
    return { supplier() }
}

fun foo(taskExecutor: TaskExecutor): Int {
    val future = CompletableFuture.supplyAsync(someWrapper {
        42
    }, taskExecutor::execute)
    return future.join()
}

@Test
public void shouldFoo() {
    assertThat(foo(), is(42));
}

Jacoco에 지점 적용 규칙이 있는데, 위 코드에서는 실패합니다 .2 지점 중 1 지점은 someWrapper통화 라인에 포함되지 않습니다 . 불행히도, someWrapper호출 된 모든 클래스를 제외시키는 옵션은 아닙니다 .

디 컴파일 된 Java 코드를 보면 :

public final int foo(TaskExecutor taskExecutor) {
    Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
    if (var10000 != null) {
        Object var2 = var10000;
        var10000 = new Foo$sam$java_util_function_Supplier$0((Function0)var2);
    }

    Supplier var3 = (Supplier)var10000;
    Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
        // $FF: synthetic method
        // $FF: bridge method
        public Object invoke(Object var1) {
        this.invoke((Runnable)var1);
        return Unit.INSTANCE;
        }

        public final void invoke(Runnable p1) {
        ((TaskExecutor)this.receiver).execute(p1);
        }

        public final KDeclarationContainer getOwner() {
        return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
        }

        public final String getName() {
        return "execute";
        }

        public final String getSignature() {
        return "execute(Ljava/lang/Runnable;)V";
        }
    });
    CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor$0(var4)));
    var10000 = future.join();
    Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
    return ((Number)var10000).intValue();
}

문제는 if (var10000 != null)지점이며 IDE에 의해 불필요하다고 표시됩니다 (항상 참).

예를 들어 모든 분기를 포함 할 수 있도록 코드를 조정하는 것이 가능합니까? 컴파일러가 여분의 null 검사를 생성하지 않도록함으로써? 나는 모두의 코드를 변경할 수 foo(..)someWrapper(..)내가 장식 된 람다를 제공 할 수있게되었습니다만큼을.

나는 Kotlin 1.3.50과 Jacoco 0.8.4를 사용합니다.

편집하다.

한 가지 확실한 해결 방법은 supplyAsync(someWrapper { ... })일부 utils 클래스 로 추출 하여 해당 클래스 만 제외하는 것입니다.

fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
    return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}

Kotlin이 왜 브랜치를 추가하지 않아도되는지 궁금합니다.


Type inference failed샘플 코드를 컴파일하려고 할 때 얻습니다 . 즉시 사용 가능한 샘플 코드를 제공 할 수 있다면 좋을 것입니다! 예를 들어, taskExecutorcontroller미지수이다.
Enselic

@Enselic은 산만 오류를 제거하기 위해 작은 편집을 추가했습니다. 아이디어를 얻는 데 충분해야하므로 본격적인 코드로 더 확장하지는 않을 것입니다.
BKE

1
JaCoCo가 Kotlin을 지원하기 위해 점진적으로 적응하는 방법 (github.com/jacoco/jacoco/releases 참조 및 "Kotlin 컴파일러에 의해 추가됨"검색)을 살펴보면 이것이 조만간 해결 될 또 다른 격차라고 생각합니다. 보장 범위를 토핑하는 것에 대해 심각하다고 생각되면 문제를보고하는 것이 좋습니다.
PiotrK

답변:


1

의 반환 값이 someWrapper의 인스턴스로만 Supplier사용 Supplier되는 경우 반환 유형 으로 명시 적으로 사용하여 불필요한 null 검사를 제거 할 수 있습니다 .

fun <U> someWrapper(supplier: () -> U): Supplier<U> {
    return Supplier { supplier() }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.