2016-02-24 16 views
7

Poniższy fragment generuje ostrzeżenie o lintach w Android Studio.Dereferencja może spowodować "java.lang.NullPointerException"

Bundle extras = getIntent().getExtras(); 
    if (extras != null && extras.getString(REDIRECT_KEY) != null) { 
     switch (extras.getString(REDIRECT_KEY)) { ... 

extras.getString(REDIRECT_KEY) produkuje ostrzeżenia

enter image description here

dereference z 'extras.getString (REDIRECT_KEY)' może produkować 'java.lang.NullPointerException'

ale don nie widzisz żadnego scenariusza, w którym mogłoby to się zdarzyć. Czy jest to błąd w sprawdzaniu lint, że po prostu nie rozpoznaje moich zerowych sprawdzeń w poprzednim przypadku? Czy może czegoś nie przeoczyłem?

EDIT: zmiany kodu do następujących, nie usunąć ostrzeżenie

if(getIntent() != null && getIntent().getStringExtra(REDIRECT_KEY) != null){ 
     switch (getIntent().getStringExtra(REDIRECT_KEY)){ 
      ... 
     } 
    } 

ale to już tylko ze względu na sposób to działa check szarpie (przynajmniej sądzę). Jeśli pokazać więcej infos tej kontroli, to mówi się w jednym punkcie

zmienne, parametry metody i zwracania wartości oznaczone jako @Nullable lub @NotNull są traktowane jako pustych (lub nie-zerowy, odpowiednio), który używano w trakcie analiza sprawdzić opcje dopuszczania wartości null umów

Patrząc na kod źródłowy Bundle i intencyjnego pokazuje:

/** 
* Retrieve extended data from the intent. 
* 
* @param name The name of the desired item. 
* 
* @return the value of an item that previously added with putExtra() 
* or null if no String value was found. 
* 
* @see #putExtra(String, String) 
*/ 
public String getStringExtra(String name) { 
    return mExtras == null ? null : mExtras.getString(name); 
} 

i BaseBundle

/** 
* Returns the value associated with the given key, or null if 
* no mapping of the desired type exists for the given key or a null 
* value is explicitly associated with the key. 
* 
* @param key a String, or null 
* @return a String value, or null 
*/ 
@Nullable 
public String getString(@Nullable String key) { 
    unparcel(); 
    final Object o = mMap.get(key); 
    try { 
     return (String) o; 
    } catch (ClassCastException e) { 
     typeWarning(key, o, "String", e); 
     return null; 
    } 
} 

Jak widać, BaseBundle ustawia wartości zwracane na @Nullable, a Intent nie. Tak więc użycie getStringExtra usuwa tylko symoptomy, a nie przyczynę. Wciąż przypuszczam, że jest to spowodowane niewystarczającym sprawdzeniem linta, zamiast błędnego kodowania po mojej stronie. A może ktoś nadal widzi scenariusz, w którym można rzucić wskaźnik zerowy?

+0

Jaka linia nadaje ostrzeżenie? druga czy trzecia? – Ferrybig

+2

Myślę, że zamiast otrzymywać String za każdym razem z dodatków, powinieneś przypisać go do zmiennej. Ponieważ Twoje dodatki mogą stać się puste w pewnych sytuacjach. – Pragnani

+0

trzeci wiersz w fragmencie kodu lub linia 80 na obrazie. Sprawdzam dodatki == null i dla wyniku getString() == null. Zobacz If w drugim wierszu. – AlbAtNf

Odpowiedz

4

Spójrz na ten przykład pobranych z here

class Argument { 

    public final static int TOMAYTO = 0; 
    public final static int TOMAHTO = 1; 

    static void argue() { 

     int say = TOMAYTO; 

     while (true) { 

      switch (say) { 

      case TOMAYTO: 

       say = TOMAHTO; 
       break; 

      case TOMAHTO: 

       say = TOMAYTO; 
       break; 
      } 
     } 
    } 
} 

W bytecodes generowane przez javac dla metody twierdzą() przedstawiono poniżej:

0 iconst_0 // Push constant 0 (TOMAYTO) 
    1 istore_0 // Pop into local var 0: int say = TOMAYTO; 
    2 iload_0 // Push key for switch from local var 0 
          // Perform switch statement: switch (say) {... 
          // Low case value is 0, high case value is 1 
          // Default branch offset will goto 2 
    3 tableswitch 0 to 1: default=2 
      0: 24 // case 0 (TOMAYTO): goto 24 
      1: 29 // case 1 (TOMAHTO): goto 29 

          // Note that the next instruction starts at address 24, 
          // which means that the tableswitch took up 21 bytes 
    24 iconst_1 // Push constant 1 (TOMAHTO) 
    25 istore_0 // Pop into local var 0: say = TOMAHTO 
    26 goto 2 // Branch unconditionally to 2, top of while loop 
    29 iconst_0 // Push constant 1 (TOMAYTO) 
    30 istore_0 // Pop into local var 0: say = TOMAYTO 
    31 goto 2 // Branch unconditionally to 2, top of while loop 

Jak widać na switch z Typ danych typu String Przełącznik tabelaryczny jest wykonywany, a dla każdego przypadku wartość przekazywana do przełącznika jest porównywana z wartością sprawy, a więc oznacza to, że w twoim przypadku extras.getString można wywołać wiele razy bez Twojej poprzedniej if sprawdza, czy są wywoływane, i jako takie, ponieważ dodatki to pakiet, istnieje szansa, że ​​może zostać usunięty z listy i spowodować wyjątek nullpointer.

Zawsze dobrze jest utworzyć zmienną lokalną, zamiast wykonywać wiele wywołań metody, aby poznać przyczynę, można rzucić okiem na this presentation by Jake Wharton.

+1

Dziękuję, ponieważ jest to jedyna odpowiedź, która naprawdę odpowiada na moje oryginalne pytanie "czy coś mi umknęło". – AlbAtNf

Powiązane problemy