如何使用 equals() 和 contains() 检查可空类型的数据?我想它们都是字符串的方法,但为什么它们的行为不同呢?

How to use equals() and contains() to check nullable type of data? I suppose they are both string's methods, but why they behave differently?

案例 1:它可以编译 运行。为什么 null 调用 equals() 时没有异常?

var myStr:String? = null
if (myStr.equals("hello"))  
    println("equals hello")
else
    println("not equals hello")

情况2:无法编译。我想这与上述情况类似,但我错了。为什么?

var myStr:String? = null
if (myStr.contains("hello"))
    println("contains hello")
else
    println("not contains hello")

equals 函数定义为可空字符串引用 String? 上的扩展函数,而 contains 方法定义在不可空 CharSequence.

public actual fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean = ...


public operator fun CharSequence.contains(other: CharSequence, ignoreCase: Boolean = false): Boolean = ...

在这两种情况下,myStr 都是可为空的字符串,因此您不能直接调用 contains。您可以使用空安全运算符 ?. 来调用 contains

if(myStr?.contains("hello") == true)
    println("contains hello")
else
    println("not contains hello")

PS:等式检查时,不需要使用equals方法,直接使用==运算符

即可

equals 对可空字符串有效,只是因为它是一种非常特殊的情况。有一个equals专门为String?写的。

fun String?.equals(
    other: String?, 
    ignoreCase: Boolean = false
): Boolean

这不适用于 Int?,例如:

var i: Int? = null
if (i.equals(1)) // error here
    println("equals 1")
else
    println("not equals 1")

equals 函数是为 Any 而不是 Any? 声明的,因此您不能在可空类型上调用它 通常 .

无论如何,比较相等性的惯用方法是使用 a == b,对于可为 null 的 a.

,它转换为 a?.equals(b) ?: (b === null)

也没有理由允许 myStr.contains("hello") 编译,因为 contains 是在不可为 null 的 CharSequence.

上声明的
operator fun CharSequence.contains(
    other: CharSequence, 
    ignoreCase: Boolean = false
): Boolean

您可以这样检查它,使用可空链接:

if (myStr?.contains("hello") == true)

在第一个示例中,myStr.equals 调用 String?.equals 扩展函数,该函数执行以下操作:

if (this === null)
    return other === null

在你的例子中,thisnull,而 other 不是 null,所以 other === null 产生 false


在第二个示例中,myStr.contains("hello") 试图调用一个名为 contains 的函数,但它不存在,因为您有一个可为空的 String?,并且没有contains 为该类型定义的函数。有 CharSequence.contains 函数,但它仅为不可空类型定义。

因此,由于该函数不存在,您会收到编译器错误。


一般情况下,您不需要使用 equals 函数,应该更喜欢 == 运算符:

val myStr:String? = null
if (myStr == "hello")
    println("equals hello")
else
    println("not equals hello")

对于contains,可以使用?.运算符先确保左边的对象不为null:

val myStr:String? = null
if (myStr?.contains("hello") == true)
    println("contains hello")
else
    println("not contains hello")

这里,myStr?.contains("hello")产生null,而null == truefalse,所以结果是false