Làm thế nào để bao gồm kiểm tra null không cần thiết được tạo ra bởi Kotlin?


9

Hãy xem xét ví dụ về Kotlin tối thiểu sau đây:

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));
}

Tôi có các quy tắc bảo hiểm chi nhánh trong Jacoco, không thành công cho mã ở trên, nói rằng 1 trong 2 chi nhánh không nằm trong dòng của someWrappercuộc gọi. Thật không may, nó không phải là một lựa chọn cho tôi để loại trừ tất cả các lớp someWrapperđược gọi.

Nhìn vào mã Java được dịch ngược:

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();
}

Tôi nghĩ, vấn đề là if (var10000 != null)nhánh, thậm chí được IDE đánh dấu là không cần thiết (luôn luôn đúng).

Có phải bằng cách nào đó có thể điều chỉnh mã sao cho có thể bao gồm tất cả các nhánh, ví dụ. bằng cách đảm bảo trình biên dịch không tạo thêm kiểm tra null? Tôi có thể thay đổi mã của cả hai foo(..)someWrapper(..)miễn là tôi có thể cung cấp lambda được trang trí.

Tôi sử dụng Kotlin 1.3.50 và Jacoco 0.8.4.

BIÊN TẬP.

Một cách giải quyết rõ ràng là trích xuất supplyAsync(someWrapper { ... })vào một số lớp utils và chỉ loại trừ lớp đó, tức là:

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

Điều này sẽ đủ tốt cho tôi, mặc dù tôi vẫn tò mò tại sao chi nhánh được thêm bởi Kotlin, nơi không cần chi nhánh.


Tôi nhận được Type inference failedkhi cố gắng để biên dịch mã mẫu của bạn. Sẽ thật tuyệt nếu bạn có thể cung cấp mã mẫu hoạt động tốt! Ví dụ, taskExecutorcontrollerlà ẩn số.
Enselic

@Enselic đã thêm chỉnh sửa nhỏ để xóa các lỗi gây mất tập trung. Tôi sẽ không mở rộng nó hơn nữa thành mã đầy đủ vì điều này là đủ để có ý tưởng.
BKE

1
Nhìn vào cách JaCoCo dần dần thích nghi để hỗ trợ Kotlin (xem github.com/jacoco/jacoco/release và tìm kiếm "được thêm bởi trình biên dịch Kotlin"), tôi nghĩ rằng đây chỉ là một lỗ hổng khác sẽ sớm được khắc phục. Nếu bạn cảm thấy nghiêm túc về việc đứng đầu bảo hiểm của mình, tôi khuyên bạn nên báo cáo một vấn đề.
PiotrK

Câu trả lời:


1

Nếu giá trị trả về của someWrapperchỉ được sử dụng làm ví dụ Supplier, thì bạn có thể loại bỏ kiểm tra null không cần thiết bằng cách sử dụng rõ ràng Supplierlàm loại trả về.

fun <U> someWrapper(supplier: () -> U): Supplier<U> {
    return Supplier { supplier() }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.