5

我有一个Java to Kotlin转换器失败的例子,因为我没有将方法参数标记为可空。Java到Kotlin转换器和可空方法参数

示例:使用registerActivityLifecycleCallbacks跟踪活动的生命周期:

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { 
    @Override 
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {} 

    @Override 
    public void onActivityStarted(Activity activity) {} 

    @Override 
    public void onActivityResumed(Activity activity) {} 

    // ... other overriden methods 
}); 

粘贴此代码科特林结果:

registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { 
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle) {} 

    override fun onActivityStarted(activity: Activity) {} 

    override fun onActivityResumed(activity: Activity) {} 

    override fun onActivityPaused(activity: Activity) {} 

    // ... other overriden methods (all with non-nullable parameters) 
}) 

的问题是,savedInstanceState参数类型是Bundle它应该是Bundle?,因为它的价值可以是null

在这种情况下,当没有实例的状态创建一个Activity我们会得到以下异常:

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter savedInstanceState 

注意,根本原因这可能是onActivityCreated documentation没有提到Bundle可以为空onCreate documentation也可以解释为什么简单onCreate转换按预期工作:

// Java 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
} 
// Kotlin 
override fun onCreate(savedInstanceState: Bundle?) { 
    super.onCreate(savedInstanceState) 
    setContentView(R.layout.activity_main) 
} 

我的问题是我们如何知道哪些论据应该是可空的以防止这类问题? @Nullable注释在这里没有帮助。

回答

3

如果注释没有帮助,我不认为有办法知道参数是否可以为空。

关于你贴的代码,我想我知道这是怎么回事:

活动onCreateIS标记为@Nullable

@Override 
protected void onCreate(@Nullable Bundle savedInstanceState) { 
    final AppCompatDelegate delegate = getDelegate(); 
    delegate.installViewFactory(); 
    delegate.onCreate(savedInstanceState); 
    . 
    . 

虽然ActivityLifecycleCallbacks接口方法:(见Application.java

public interface ActivityLifecycleCallbacks { 
    void onActivityCreated(Activity activity, Bundle savedInstanceState); 
    void onActivityStarted(Activity activity); 
    void onActivityResumed(Activity activity); 
    void onActivityPaused(Activity activity); 
    void onActivityStopped(Activity activity); 
    void onActivitySaveInstanceState(Activity activity, Bundle outState); 
    void onActivityDestroyed(Activity activity); 
} 

显然Kotlin翻译器正在处理注释,但使用非空作为默认设置,这在我看来并不常见,因为它更有意义,因为它可以将非注释参数视为可为空。不过,我可以理解这个决定,以便强迫开发人员关注翻译后的代码,并明确地决定参数是否为可空

顺便提一下,记住,有几个@NonNull@Nullable注释(使用javax,机器人,JetBrains的...)我也不会,如果科特林翻译只承认其中的一些奇怪的(但它只是一个猜测)

另外关于你的代码,Java Lint应该给你一个关于你的被覆盖的onCreate的警告,说你重写了带注释参数的方法,但你没有注释它们。

+1

我想这支持你的论点:https://kotlinlang.org/docs/reference/java-interop。HTML#空性的注解。将尝试再次使用注释进行转换(以前不适用于我) –

+1

是的,Kotlin假定Java代码默认情况下不为空,除非它具有注释。它使用Java代码的'!',比如'String!'来告诉你代码来自Java。 – Joshua