← Zurück
2022-11-07

Java-Fun #1 - Der etwas ungenaue Compound Assignment Operator

Die Java-Fun Serie behandelt komische oder fragwürdige Eigenheiten der Programmiersprache Java.

♨️

Eine häufiges Szenario in der Programmierung ist, dass man zu einer Variablen etwas dazuaddieren oder davon abziehen möchte:

int balance = 100;
int amount = 20;
// guthaben auf konto einzahlen
balance = balance + amount;
System.out.println("balance: " + balance);
// balance: 120

Um solche Statements abzukürzen, gibt es in vielen Programmiersprachen, darunter auch in Java, den Compound Assignment Operator (Verbundzuweisungsoperator).

// lange Variante:
balance = balance + amount;
// kurze Variante mit Compound Assignment Operator:
balance += amount;

Java ist eine streng typisierte Sprache und verhindert durch Typendefinitionen, dass wir als Programmierer offensichtliche Fehler machen. Ein Beispiel für einen solchen Fehler wäre das Addieren einer Dezimalzahl (float) zu einer Ganzzahl (int), da dies zum Verlust des Dezimalanteils führen würde. Java beschwert sich deshalb beim Kompilieren:

int balance = 100;
float amount = 10.5f;
// 💀 java: incompatible types: possible lossy conversion from float to int
balance = balance + amount;
System.out.println("balance: " + balance);

Im oberen Beispiel wurde die lange Variante der Addierung genutzt. Wie verhält sich der Compiler bei der kurzen Variante mit dem Compound Assignment Operator? Man würde erwarten, dass es ebenfalls zu einer incompatible types Fehlermeldung führt.

int balance = 100;
float amount = 10.5f;
// 💀?
balance += amount;
System.out.println("balance: " + balance);

Aber überraschenderweise funktioniert die Kompilierung 🤨 und das Ergebnis ist:

balance: 110

Die 0.5 sind also verloren gegangen.

Die Erklärung, warum dies funktioniert, findet sich in der JLS (Java Language Specification):

A compound assignment expression of the form

E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)),

where T is the type of E1, except that E1 is evaluated only once

Zusammengefasst: Compound Assignment Operators führen automatisch eine verdeckte Typenumwandlung durch.

int balance = 100;
float amount = 10.5f;
// so steht es im code
balance += amount;
// das macht der compiler daraus
balance = (int)(balance + amount);

Ein weiteres WTF Beispiel:

char c = 'A';
c *= 1.5;
System.out.println(c);
// 'a'

¯\_(ツ)_/¯

In anderen Sprachen wie C#, funktioniert das nicht so einfach.

Siehe auch: