Łączenie łańcuchów null w Javie

Dlaczego następujące działania? Spodziewałbym się, że NullPointerException zostanie wyrzucony.

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Author: yavoh, 2010-11-23

5 answers

Dlaczego musi działać?

The JLS 5, Sekcja 15.18.1.1 JLS 8 § 15.18.1 "String concatenation Operator +" , prowadzący do JLS 8, § 5.1.11 "String Conversion" , wymaga, aby operacja ta powiodła się bez porażki:

...Obecnie należy wziąć pod uwagę tylko wartości referencyjne. jeśli odniesienie jest null, jest konwertowane na łańcuch "null" (cztery znaki ASCII n, u, l, l). W przeciwnym razie konwersja jest wykonywane tak, jakby przez wywołanie metody toString obiektu odniesienia bez argumentów; ale jeśli wynikiem wywołania metody toString jest wartość null, to zamiast niej zostanie użyty łańcuch "null".

Jak to działa?

Spójrzmy na kod bajtowy! Kompilator pobiera kod:

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"

I kompiluje go w bajtowym kodzie tak, jakbyś zamiast tego napisał to:

String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"

(możesz to zrobić samodzielnie za pomocą javap -c)

Metody dodawania StringBuilder wszystkie obsługują null dobrze. W tym przypadku, ponieważ null jest pierwszym argumentem, String.valueOf() jest wywoływany zamiast tego, ponieważ StringBuilder nie ma konstruktora, który przyjmuje dowolny dowolny typ odniesienia.

Gdybyś zrobił s = "hello" + s zamiast tego, równoważny kod byłby:

s = new StringBuilder("hello").append(s).toString();

Gdzie w tym przypadku metoda append pobiera null i następnie przekazuje ją do String.valueOf().

Note: String konkatenacja jest w rzeczywistości jednym z rzadkich miejsc, w których kompilator decyduje, które optymalizacje należy wykonać. Jako taki," dokładny odpowiednik " kodu może się różnić w zależności od kompilatora. Ta optymalizacja jest dozwolona przez JLS, Section 15.18.1.2:

Aby zwiększyć wydajność powtarzającej się konkatenacji łańcuchów, kompilator Javy może użyć klasy StringBuffer lub podobnej techniki, aby zmniejszyć liczbę pośrednich obiektów łańcuchowych, które są tworzone przez ewaluację wyrazu.

Kompilatorem, którego użyłem do określenia "kodu równoważnego" powyżej był kompilator Eclipse, ecj.

 163
Author: Mark Peters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-06 08:36:49

Patrz sekcja 5.4 oraz 15.18 specyfikacja języka Java:

Konwersja ciągu dotyczy tylko operandów operatora binarnego+, gdy jednym z argumentów jest łańcuch znaków. W ten pojedynczy przypadek specjalny, drugi argument do + jest konwertowany na Ciąg, oraz nowy ciąg, który jest konkatenacja dwóch ciągów jest wynik+. Konwersja łańcuchów jest szczegółowo określona w opis łańcucha konkatenacja + operator.

I

Jeśli tylko jedno wyrażenie operandowe jest wpisz String, wtedy konwersja string jest wykonywany na drugim operandie do tworzy ciąg w czasie wykonywania. Na wynik jest odniesieniem do ciągu znaków obiekt (nowo utworzony, chyba że wyrażenie jest stałą czasową kompilacji wyrażenie (§15.28)), czyli konkatenacja dwóch operandów struny. Postacie z operand lewostronny poprzedzają znaki prawej ręki operand w nowo utworzonym łańcuchu. Jeśli operand typu String jest null, wtedy ciąg "null" jest używany zamiast ten operand.

 23
Author: Jonathon Faust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 20:53:03

Drugi wiersz przekształca się w następujący kod:

s = (new StringBuilder()).append((String)null).append("hello").toString();

Metody append mogą obsługiwać argumenty null.

 11
Author: Roland Illig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 20:49:31

Nie używasz "null" i dlatego nie dostajesz wyjątku. Jeśli chcesz nullpointer, po prostu wykonaj

String s = null;
s = s.toString() + "hello";

I myślę, że to, co chcesz zrobić, to:

String s = "";
s = s + "hello";
 10
Author: krico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 20:50:35

Jest to zachowanie określone w Java API String.valueOf(Object) metoda. Kiedy wykonujesz konkatenację, valueOf jest używany do uzyskania reprezentacji String. Istnieje specjalny przypadek, jeśli obiektem jest null, w którym to przypadku używany jest ciąg znaków "null".

public static String valueOf(Object obj)

Zwraca reprezentację łańcuchową argumentu obiektu.

Parametry: obj-obiekt.

Zwraca:

Jeśli argument jest null, to łańcuch równy "null"; w przeciwnym razie wartość obj.zwracana jest metoda toString ().

 7
Author: wkl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 20:50:27