Rozważ następujący minimalny przykład Kotlina:
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));
}
Mam zasady zasięgu oddziałów w Jacoco, które zawodzą dla powyższego kodu, mówiąc, że 1 z 2 oddziałów nie jest objęty linią someWrapper
połączenia. Niestety nie mogę wykluczyć wszystkich klas, z których someWrapper
jest wywoływane.
Patrząc na zdekompilowany kod 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();
}
Myślę, że problemem jest if (var10000 != null)
gałąź, która jest nawet oznaczona przez IDE jako niepotrzebna (zawsze prawdziwa).
Czy w jakiś sposób można dostosować kod, tak aby możliwe było objęcie wszystkich gałęzi, np. upewniając się, że kompilator nie generuje dodatkowego sprawdzenia zerowego? Mogę zmienić kod obu foo(..)
i someWrapper(..)
tak długo, jak będę w stanie dostarczyć zdobioną lambda.
Używam Kotlin 1.3.50 i Jacoco 0.8.4.
EDYTOWAĆ.
Jednym oczywistym obejściem jest wyodrębnienie supplyAsync(someWrapper { ... })
do niektórych klas utils i wykluczenie tylko tej klasy, tj .:
fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}
Byłoby to dla mnie wystarczająco dobre, choć wciąż jestem ciekawy, dlaczego gałąź została dodana przez Kotlin, gdzie nie musi być żadnej gałęzi.
Type inference failed
gdy próbuję skompilować twój przykładowy kod. Byłoby świetnie, gdybyś mógł podać przykładowy kod, który działa po wyjęciu z pudełka! Na przykładtaskExecutor
icontroller
są nieznane.Odpowiedzi:
Jeśli zwracana wartość
someWrapper
ma być używana tylko jako instancjaSupplier
, wówczas można usunąć niepotrzebne sprawdzanie wartości zerowej, jawnie używającSupplier
jako typu zwracanego.źródło