#kotlin #null-check
#kotlin #нулевая проверка
Вопрос:
Насколько я понимаю, большое преимущество ?.let{}
over != null
заключается в том, что оно гарантирует, что изменяемое значение не изменяется внутри блока.
Однако, в случае неизменяемой переменной есть ли разница в производительности?
Например, у меня есть простой метод
private fun test() {
val x: String? = ""
if (x != null) {
print("test")
}
x?.let {
print("test")
}
}
Когда я вижу результирующий байт-код Kotlin, кажется, что для let в нем гораздо больше кода.
Для случая x != null:
LINENUMBER 8 L1
L2
LINENUMBER 9 L2
LDC "test"
ASTORE 2
L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/Object;)V
L4
L5
Для случая x?.let { } это:
LINENUMBER 12 L5
ALOAD 1
ASTORE 2
L6
L7
ALOAD 2
ASTORE 3
L8
ICONST_0
ISTORE 4
L9
LINENUMBER 13 L9
LDC "test"
ASTORE 5
L10
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 5
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/Object;)V
L11
L12
LINENUMBER 14 L12
L13
NOP
L14
LINENUMBER 12 L14
L15
NOP
L16
Если я декомпилирую в java, то результирующий код выглядит похожим, и для let назначается еще одна переменная (любопытно, что переменная int имеет значение false)
Для x != null:
String var2 = "test";
System.out.print(var2);
Для x?.let { }
int var4 = false;
String var5 = "test";
System.out.print(var5);
В конце концов, мой вопрос: отличается ли производительность между let и !=
для неизменяемых переменных?
Комментарии:
1. Это случай микрооптимизации — разница настолько мала, что вам будет трудно даже измерить ее. Просто используйте все, что более читаемо в контексте.
2. @Pawel: Согласен. Большие выигрыши в производительности достигаются за счет отказа от ненужных: синхронизации / потоковой передачи, алгоритмической сложности, ввода / вывода сети / файла / базы данных, временных объектов и (в меньшей степени) доступа к основной памяти. Оптимизация здесь не уменьшает ни одного из них, поэтому на практике это никогда не будет иметь никакого практического значения. На самом деле, JVM, вероятно, все равно оптимизирует его.
3. Я просто вижу слишком много строк в декомпилированной версии, но я не могу прочитать, что это такое, вот почему мне было интересно!
Ответ №1:
Эти два утверждения на самом деле не эквивалентны. Результат, очевидно, одинаков в ваших двух примерах, но let
является функцией области видимости и, следовательно, делает немного больше, чем простое управление потоком.
Из связанной документации:
Стандартная библиотека Kotlin содержит несколько функций, единственной целью которых является выполнение блока кода в контексте объекта. Когда вы вызываете такую функцию для объекта с предоставленным лямбда-выражением, она формирует временную область видимости.
Например, даже если вы не используете it
в своем примере, этот контекст с it-переменной все равно создается, и это влечет за собой некоторые накладные расходы.
Однако, как указывали другие, я думаю, что это тот случай, когда в данном случае лучше оптимизировать код для удобства чтения, а не для скорости. В тех случаях, когда let позволяет использовать более читаемый код (что обычно имеет место в IMO), это больший выигрыш, чем незначительный прирост производительности, который вы можете получить от использования if вместо этого.
Комментарии:
1. стоит отметить
let
, что это встроенная функция, что означает, что она вставляет как саму себя, так и лямбда-вызов. Если бы это было не так, возможно, были бы значительные накладные расходы на использованиеlet
вместо простогоif
. К счастью, все функции области видимости в Kotlininline