Ответ 1
Они почти одинаковы, но сначала бросает KotlinNullPointerExcption
для null
, а второй бросает TypeCastException
.
Предположим, что мы имеем переменную типа var text: String?
.
Когда я хочу применить его к типу, который не имеет значения NULL, я могу использовать:
text!!
text as String
Означает ли это то же самое?
Я знаю, что эти способы будут генерировать исключение, если text
- null
.
Они почти одинаковы, но сначала бросает KotlinNullPointerExcption
для null
, а второй бросает TypeCastException
.
Разница - это исключение (либо KotlinNullPointerExcption
или TypeCastException
), которое вы получаете, когда text == null
(как указано в @Miha_x64) в каждом другом отношении они генерируют один и тот же байт-код. Также литой и!! действительны только в текущем операторе, поэтому поведение вряд ли изменится. Я бы пошел на !!
каждый раз, потому что исключение лучше отражает ошибку.
fun foo() {
var s = ""
val t: String? = ""
if (t as String != "") s = "1"
if (t!! != "") s = "2"
}
дает
public final foo()V
L0
LINENUMBER 9 L0
LDC ""
ASTORE 1
L1
LINENUMBER 10 L1
LDC ""
ASTORE 2
L2
LINENUMBER 12 L2
ALOAD 2
L3
LDC ""
INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
ICONST_1
IXOR
IFEQ L4
LDC "1"
ASTORE 1
L4
LINENUMBER 13 L4
ALOAD 2
L5
LDC ""
INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
ICONST_1
IXOR
IFEQ L6
LDC "2"
ASTORE 1
L6
LINENUMBER 14 L6
RETURN
L7
LOCALVARIABLE t Ljava/lang/String; L2 L7 2
LOCALVARIABLE s Ljava/lang/String; L1 L7 1
LOCALVARIABLE this Lde/leo; L0 L7 0
MAXSTACK = 2
MAXLOCALS = 3
Интересная часть L3 и L5
Они одинаковы в том смысле, что они будут вызывать ошибку исключения при неправильном использовании. В соответствии с docs при использовании оператора as
вы выполняете небезопасную операцию, и если они не одного типа, будет вызывать ошибку, тогда как force unwrew !!
выдаст ошибку только в том случае, если переменная, которая была отбракована, равна нулю.
В полученном исключении он отличается:
Приведение значения с нулевым значением в его непустой тип вызывает TypeCastException
if null
:
val s: String? = null
val s2 = s as String //kotlin.TypeCastException: null cannot be cast to non-null type kotlin.String
Двойной восклицательный знак, двойной взрыв, означает, что вы не заботитесь о типе информации о недействительности и просто хотите использовать его, как будто он не может быть null
. В случае, если выбрано значение NullpointerException
:
val s: String? = null
val s2: String = s!! //Exception in thread "main" kotlin.KotlinNullPointerException
Вы редко должны использовать один из двух вариантов и осторожно обращаться с обнулянием:
s?.let {
//it safe here!
} ?: //optionally handle null case
Smart casting также поможет вам.