如何避免使用!!类的可选属性
class PostDetailsActivity {
private var post: Post? = null
fun test() {
if (post != null) {
postDetailsTitle.text = post.title // Error I have to still force using post!!.title
postDetailsTitle.author = post.author
Glide.with(this).load(post.featuredImage).into(postDetailsImage)
} else {
postDetailsTitle.text = "No title"
postDetailsTitle.author = "Unknown author"
Toast.makeText(this, resources.getText(R.string.post_error), Toast.LENGTH_LONG).show()
}
}
}
Run Code Online (Sandbox Code Playgroud)
我应该创建一个局部变量吗?我认为使用!!不是一个好习惯
使用该.let { }功能时,我注意到在执行以下操作时:
bucket?.assignedVariantName.let {
bucket?.determineVariant() <-- guarantee safety for bucket
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下你必须保证铲斗的安全,即 bucket?.或者bucket!!在使用?.let时已经保证了零安全性,然后我注意到在执行以下操作时:
bucket?.assignedVariantName?.let { <-- added safety check for property
bucket.determineVariant() <-- doesn't need to guarantee safety for bucket
}
Run Code Online (Sandbox Code Playgroud)
虽然在桶的属性上使用let而不是直接在桶上我想知道这是故意还是Kotlin插件中的错误(在这种情况下我在Android Studio中遇到过这个)
另外的信息是,在这种情况下,存储桶是一个已local val分配的变量名是可以为空的变量.
val bucket: T? = ...
Run Code Online (Sandbox Code Playgroud) 我有一个简单的功能检查,如下所示:
fun parseValidBluetoothBrickedId(controllerId: String?): Boolean{
if(controllerId != null){
if(controllerId.startsWith(BLUETOOTH_NAME_PREFIX) && controllerId.length > BLUETOOTH_NAME_PREFIX.length)
return true
}
return false
}
Run Code Online (Sandbox Code Playgroud)
我想将它转换为更简单的风格:
fun parseValidBluetoothBrickedId(controllerId: String?) =
controllerId?.length > BLUETOOTH_NAME_PREFIX.length
&& controllerId?.startsWith(BLUETOOTH_NAME_PREFIX)
Run Code Online (Sandbox Code Playgroud)
但IDE(Android Studio 3.0 Beta7)给我一个错误,强调大于('>')运算符:
操作员调用对应于点限定调用'controllerId?.length.compareTo(BLUETOOTH_NAME_PREFIX.length),此处不允许
它还强调为错误行controllerId?.startsWith(BLUETOOTH_NAME_PREFIX)并说:
类型不匹配.必需:Boolean,Found Boolean?
有什么问题,真的吗?它只是一个简单的方法,适用于第一个块if-else风格.
刚刚开始使用kotlin进行android开发.我的arraylist被宣布为这样 -
var day1: ArrayList<DietPlanDetailModel>? = null
Run Code Online (Sandbox Code Playgroud)
现在我试图通过它的位置访问一个元素
val dietPlan= day1[position]
Run Code Online (Sandbox Code Playgroud)
但我在编译时错误 -
在可空的接收器类型的arraylist上只允许安全或非空的assserted调用
为什么我会收到此错误,我该如何解决?
假设我有一个对象Response.现在我想检查一个布尔变量,成功,在Response下并做一个早期返回是响应不成功.
if(response == null || !response.success){
return;
} //Java version
Run Code Online (Sandbox Code Playgroud)
现在我想使用Kotlin的null安全检查,如下所示
if(response?.success ?: true){
return
}
Run Code Online (Sandbox Code Playgroud)
如果我没有错,如果响应或成功为null,我们将在if条件内返回true.但是,如果response.success不为null且等于true,我们仍将从函数返回,这不是我想要的.我该如何纠正这种情况?
我正在写一个Kotlin应用程序,我一直在研究这种语言,我注意到要创建一个变量,你必须明确定义它是否为null然后你使用?运营商.
现在,我的问题.有时我必须定义一个全局变量(在这种情况下是一个片段),所以我需要将它设为null,因为我还不能初始化它
在java中我没有这个问题,因为在声明它之后我做的第一件事是在onCreate()中初始化像这样
TurboFragment fragment = null;
@Override
public void onCreate(Bundle savedInstanceState) {
...
fragment = adapter.getCurrentFragment();
}
Run Code Online (Sandbox Code Playgroud)
然后我可以在没有语法问题的情况下使用它在Kotlin中是不同的,因为我必须这样做
private var fragment: TurboFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
fragment = adapter!!.currentFragment
fragment!!.foo()
var x = fragment!!.sampleInt
}
Run Code Online (Sandbox Code Playgroud)
现在,每次我调用片段的实例时我都必须使用null-safe !! 运营商.这使我的代码变得混乱,因为对于每一行,我至少有一个!运算符,它看起来真的不清楚它是否如此频繁,特别是如果你有5个或更多这样的变量.有没有办法简化代码或这种语言的性质是这样的?
假设我在旧/遗留Java库中有特定代码:
public class JavaClass {
private String notNullString;
private String nullableString;
private String unannotatedString;
public JavaClass(@NotNull String notNullString,
@Nullable String nullableString,
String unannotatedString) {
this.notNullString = notNullString;
this.nullableString = nullableString;
this.unannotatedString = unannotatedString;
}
@NotNull
public String getNotNullString() {
return notNullString;
}
@Nullable
public String getNullableString() {
return nullableString;
}
public String getUnannotatedString() {
return unannotatedString;
}
}
Run Code Online (Sandbox Code Playgroud)
前两个参数使用@NotNull和@Nullable注释正确注释(使用jetbrains.annotations).第三个(unnanotatedString)没有正确的注释.
当我在我的Kotlin代码中使用这个类并将所有构造函数参数设置为非null值时,一切都很好:
val foo = JavaClass("first string", "second string", "third string")
println("Value1: ${foo.notNullString.length}")
println("Value2: ${foo.nullableString?.length}")
println("Value3: ${foo.unannotatedString.length}")
Run Code Online (Sandbox Code Playgroud)
第一个值是非null,所以我可以在没有安全调用的情况下访问它.第二个值我需要使用安全调用(nullableString?.length),如果没有,我有一个编译时错误,到目前为止一直很好.在第三个值(unannotatedString)我可以在没有安全调用的情况下使用它,它编译得很好.
但是当我将第三个参数设置为"null"时,我没有得到编译时错误(不需要安全调用,只有运行时NullPointerException:
val …Run Code Online (Sandbox Code Playgroud) 我在 JVM 11 上使用 Kotlin 1.5.20 做了以下操作(AdoptOpenJDK build 11.0.4+11)
通常在 Kotlin 中,我会执行偏向x?.let {}或x?.run {}超过if(x != null) {}. 我将这三种方法反编译为 Java,以了解我最喜欢的方法是否会引入任何类型的低效率。反编译这个 Kotlin 代码
class Main {
fun main1(x: String?){
x?.run { println(this) }
}
fun main2(x: String?){
x?.let { x1 -> println(x1) }
}
fun main3(x: String?){
if (x != null){
println(x)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我得到这个 Java 代码
@Metadata(
mv = {1, 5, 1},
k = 1,
d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0003\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0010\u0010\u0003\u001a\u00020\u00042\b\u0010\u0005\u001a\u0004\u0018\u00010\u0006J\u0010\u0010\u0007\u001a\u00020\u00042\b\u0010\u0005\u001a\u0004\u0018\u00010\u0006J\u0010\u0010\b\u001a\u00020\u00042\b\u0010\u0005\u001a\u0004\u0018\u00010\u0006¨\u0006\t"},
d2 = {"Lcom/cgm/experiments/Main;", "", "()V", "main1", …Run Code Online (Sandbox Code Playgroud) 请看这段代码:
fun localVarNullSafety1(){
var number: Double? = 3.0
val sum = 2.0 + number // does not compile (Type mismatch: inferred type is Double? but Double was expected)
}
fun localVarNullSafety1(){
var number: Double? = null
number = 3.0
val sum = 2.0 + number // compiles fine
}
Run Code Online (Sandbox Code Playgroud)
我认为上面的代码由语义上相同的函数组成 - 局部变量不会超出范围,并且它们对于执行线程来说是本地的。在我看来,第一个函数没有理由不编译。
我认为 Kotlin 的智能转换应该考虑变量初始化。
我错过了一些明显的事情吗?
当与没有 null 安全性的 Java 库交互时,如何在 Kotlin 中处理 null 安全性?
通过研究,我发现以下一些东西“有效”,但并不安全。
将 Kotlin 的非 null 类型与返回 null 的 Java 方法结合使用:
!!将运算符与返回 null 的 Java 方法一起使用:
假设 Java 布尔值永远不为 null:在 Java 中,Boolean可以是true, false, 或null,但在 Kotlin 中,Boolean只能是true或false。
在这些示例中,我的 Kotlin 编译器不会显示错误,因为它没有足够的关于 Java 方法是否可以返回 null 的信息。