Szkolenia programowania we Wrocławiu
Kurs Java Podstawy - rozszerzony

JavaTraps 002 - odpowiedź

Przypomnijmy sobie jak wyglądał kod:

import java.util.Random;

public class JavaTraps002 {
	public static void main(String args[]) {
		Random rand = new Random();
		boolean check = rand.nextBoolean();

		Number number = (check || !check)?
				new Integer(1) : new Double(2.0);

		System.out.println("Wynik: "+number);
	}
}

A poprawna odpowiedź to:

D) Inna odpowiedź. Wyświetlone zostanie Wynik: 1.0

Zastanawiacie się jak to możliwe? Już wyjaśniam.

W pierwszej kolejności tworzymy sobie obiekt random do wygenerowania jednej wartości typu boolean. Tutaj oczywiście nie ma żadnej pułapki. Następnie chcemy utworzyć obiekt typu Number i przypisać do niego, albo wartość Integer(1), lub Double(2.0). Ponieważ wyrażenie (check || !check) zawsze zwraca true. Spodziewamy się, więc, że do referencji number zostanie przypisany obiekt new Integer(1). No i w zasadzie tak się dzieje. Jest tylko jedno małe ale... Wyświetlając wartość number widzimy na ekranie 1.0. Jakim cudem?

W specyfikacji języka odnajdujemy odpowiedź dlaczego tak się dzieje. Konkretnie chodzi o zapis:

Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion (§5.1.8) and value set conversion (§5.1.13).

W naszym przypadku, kompilator przewiduje, że wynikiem zawsze będzie typ numeryczny: Integer, albo Double. Następuje więc unboxing do typów prostych int i double, a następnie promocja do najogólniejszego typu, w naszym przypadku int -> double. W następnej kolejności następuje boxing i w wyniku mamy dwie wartości typu Double.

Podobnego zachowania możemy się spodziewać w podobnych przypadkach np Integer, oraz Float, lub innych wymienionych w specyfikacji.

Jak się bronić przed tym zachowaniem?

Najlepiej nie używać conditional operatora w miejscach, gdzie nie jesteśmy pewni jak się zachowa. Bezpieczniej będzie użyć w takim przypadku zwykłego rozgałęzionego warunku if.

Komentarze