Является ли "двойное восклицание" таким же, как "как" в Котлине?

Предположим, что мы имеем переменную типа var text: String?.

Когда я хочу применить его к типу, который не имеет значения NULL, я могу использовать:

  • text!!
  • text as String

Означает ли это то же самое?

Я знаю, что эти способы будут генерировать исключение, если text - null.

Ответ 1

Они почти одинаковы, но сначала бросает KotlinNullPointerExcption для null, а второй бросает TypeCastException.

Ответ 2

Разница - это исключение (либо 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

Ответ 3

Они одинаковы в том смысле, что они будут вызывать ошибку исключения при неправильном использовании. В соответствии с docs при использовании оператора as вы выполняете небезопасную операцию, и если они не одного типа, будет вызывать ошибку, тогда как force unwrew ​​ !! выдаст ошибку только в том случае, если переменная, которая была отбракована, равна нулю.

Ответ 4

В полученном исключении он отличается:

Приведение значения с нулевым значением в его непустой тип вызывает 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 также поможет вам.