2017-10-24 11 views
10

Ja osobiście lubię składnię when, ponieważ powoduje to, że identyfikacja jest dużo jaśniejsza. Obawiam się jednak "kar", które mogę wprowadzić w ten sposób.Kotlin używając, gdy dla prostych warunków

Nie jestem ekspertem od kodu bajtowego, ale widzę, że dla tej samej "logiki", klauzula when zabiera więcej operacji na bajtodzie.

Prosty plik z 3 różnych funkcji Kotlin

package com.whatever 

fun method1(): String { 
    return if (BuildConfig.DEBUG) "something" else "else" 
} 

fun method2(): String { 
    return if (BuildConfig.DEBUG) { 
    "something" 
    } else { 
    "else" 
    } 
} 

fun method3(): String { 
    return when (BuildConfig.DEBUG) { 
    true -> "something" 
    else -> "else" 
    } 
} 

Wygenerowany kod bajtowy

// access flags 0x19 
    public final static method1()Ljava/lang/String; 
    @Lorg/jetbrains/annotations/NotNull;() // invisible 
    L0 
    LINENUMBER 4 L0 
    GETSTATIC com/whatever/BuildConfig.DEBUG : Z 
    IFEQ L1 
    LDC "something" 
    GOTO L2 
    L1 
    LDC "else" 
    L2 
    ARETURN 
    L3 
    MAXSTACK = 1 
    MAXLOCALS = 0 

    // access flags 0x19 
    public final static method2()Ljava/lang/String; 
    @Lorg/jetbrains/annotations/NotNull;() // invisible 
    L0 
    LINENUMBER 8 L0 
    GETSTATIC com/whatever/BuildConfig.DEBUG : Z 
    IFEQ L1 
    L2 
    LINENUMBER 9 L2 
    LDC "something" 
    L3 
    GOTO L4 
    L1 
    LINENUMBER 11 L1 
    LDC "else" 
    L5 
    LINENUMBER 8 L5 
    L4 
    ARETURN 
    L6 
    MAXSTACK = 1 
    MAXLOCALS = 0 

    // access flags 0x19 
    public final static method3()Ljava/lang/String; 
    @Lorg/jetbrains/annotations/NotNull;() // invisible 
    L0 
    LINENUMBER 16 L0 
    GETSTATIC com/whatever/BuildConfig.DEBUG : Z 
    ISTORE 0 
    L1 
    LINENUMBER 17 L1 
    ILOAD 0 
    ICONST_1 
    IF_ICMPNE L2 
    L3 
    LDC "something" 
    GOTO L4 
    L2 
    LINENUMBER 18 L2 
    LDC "else" 
    L5 
    LINENUMBER 16 L5 
    L4 
    ARETURN 
    L6 
    MAXSTACK = 2 
    MAXLOCALS = 1 

Czy ktoś może wskazać, jak istotne jest to koszt? A czy powinniśmy starać się trzymać z daleka od tego schematu dla prostych operacji?

Dzięki

Odpowiedz

9

Jedyną różnicą jest to, że w method3BuildConfig.DEBUG wartość zostanie zapisana w zmiennej lokalnej pierwszy. Podczas dekompilowania kodu bajtowego do Java, widzisz:

@NotNull 
    public static final String method2() { 
     return BuildConfig.DEBUG?"something":"else"; 
    } 

    @NotNull 
    public static final String method3() { 
     boolean var0 = BuildConfig.DEBUG; 
     return var0?"something":"else"; 
    } 

To jest pomijalne.


Jeśli rozszerzyć klauzule if/else, możemy skonstruować następujące:

fun method4(a: Int): String { 
    if (a == 1) { 
     return "1" 
    } else if (a == 2) { 
     return "2" 
    } else if (a == 3) { 
     return "3" 
    } else { 
     return "4" 
    } 
} 

fun method5(a: Int): String { 
    when (a) { 
     1 -> return "1" 
     2 -> return "2" 
     3 -> return "3" 
     else -> return "4" 
    } 
} 

dekompilować kodu bajtowego na to:

@NotNull 
public static final String method4(int a) { 
    return a == 1?"1":(a == 2?"2":(a == 3?"3":"4")); 
} 

@NotNull 
public static final String method5(int a) { 
    switch(a) { 
    case 1: 
    return "1"; 
    case 2: 
    return "2"; 
    case 3: 
    return "3"; 
    default: 
    return "4"; 
    } 
} 

Zatem prosta when stwierdzenie sprowadza się do instrukcja switch w języku Java. Zobacz 'Why switch is faster than if' dla porównania między tymi dwoma.

+0

Jest interesujące, że klauzula 'when' staje się klauzulą' if' po kompilacji do kodu bajtowego i ponownym kompilowaniu z powrotem do Javy. Chyba niektóre optymalizacje kompilatora są na miejscu dla tej logiki. Dziękuję za odpowiedź. –

Powiązane problemy