Häufige Errors, Exceptions und Warnings

Status
Nicht offen für weitere Antworten.
R

Roar

Gast
Die häufigsten Compiler Errors, Runtime Exceptions, Runtime Errors, Warnungen und der Stacktrace:

Der Unterschied zwischen Exception uns Errors
Exceptions sind Ausnahmefehler, die während der Laufzeit des Programms "repariert" werden können. Sie werden im weiteren Programmverlauf behandelt und vermeiden so z.B. einen Absturz des Programms. Das Programm bleibt meist normal weiter ausführbar.
Errors sind schwere Ausnahmefehler, die zur Laufzeit des Programms nicht behandelt werden können. Meist führen sie zum abrupten Programmende (Absturz).

Oft tauchen Probleme auf, weil man nicht weiß was eine Compiler Fehlermeldung bedeutet, oder weil man nicht weiß, was diese ellenlange komische Konsolenausgabe bedeutet (besonders bei Anfängern). Hier folgen also die häufigsten Errors und RuntimeExceptions:

Alles was in Spitzklammern (<>) steht sind variable Namen die von dem jeweiligen Problem abhängen.

Compiler-Errors:

- cannot read <filename>
Die Datei konnte nicht gelesen werden. Ist sie im CLASSPATH? Wurde der Dateiname richtig geschrieben?

- cannot resolve symbol <symbol>
Das Symbol (Methode, Klasse, Feld, Variable, Konstruktor) konnte nicht gefunden werden, d.h. es gibt dieses "Symbol" nicht. Ist es richtig geschrieben? ist evtl. die Parameterübergabe falsch gemacht? Es ist immer ein Parameter "Location"
bei der Fehlermeldung mit angegeben. An der kann man erkennen wo überhaupt nach dem Symbol gesucht wurde.
Wenn als Location die gleiche Klasse angegeben wurde und sie eigentlich in einer anderen Klasse ist dann wurde
wahrscheinlich vergessen das Paket/die Klasse zu importieren.

- <something> expected
Es wird irgendein syntaktisches Symbol erwartet. Meist ist das Semikolon oder eine Klammer. Bsp.:
Java:
String s1 = "Hallo Welt"
String s2 = "Hallo Duke";
Hier müssste nach der Instantiierung des ersten Strings ein Semikolon stehen. Der Compiler zeigt mit seinem '^' auf den Anfang der zweiten String Instantiierung, also nicht verwirren lassen.

- <variable> is already definded in ...
Das bedeutet dass man eine Variable zweimal in der selben Methode/Klasse deklariert hat; das darf man natürlich
nicht weil sich die Variablen sonst in die Quere kommen. Bsp:
Java:
// falsch!!
class Test {
  String aString;
  String aString = "Hello World";
  //...
}

// falsch!!
class Test {
  //...
  void test() {
    String aString;
    String aString = "Hello World";
  }
}

// funktioniert:
class Test {
  String aString = "Hello World";
  //..
  void test() {
    String aString = "Hello Duke";
    System.out.println(this.aString);
    System.out.println();
    System.out.println(aString);
    // Ausgabe:
    // Hello World
    // Hello Duke
  }
}

- <class> is not abstract and does not override abstract method <methode> in <interface>
Es müssen alle Methoden eines implementierten Interfaces überschrieben werden, wenn die Klasse nicht abstrakt ist. Beispiel:
Java:
class MyProgram extends JFrame implements ActionListener {

public MyProgram() {
  super("Huhu");
  JButton button = new JButton("Klick mich!");
  button.addActionListener(this);
    add(button);
  }
}

Damit dies funktioniert muss noch die Methode actionPerformed(ActionEvent e) (in dem Beispiel) überschrieben werden.

Variable <variable> might not have been intialized
Das ist eine Warnung an den Programmierer dass eine Variable die im späteren Programmverlauf nicht initialisiert worden ist. Der Fehler tritt nur bei lokalen variablen auf. Eine Lösung ist z.B. der Variable bei de deklarierung den Wert null zuzuweisen.

unreported exception <exception>; must be caught or declared to be thrown
In der angegebenen Zeile wird eine Methode aufgerufen die eine Exception wirft. Diese Exception muss abgefangen werden, oder mit "throws <exception>" in der methodensignatur weitergeleitet werden.

- Missing methode body
Ein typischer Anfängerfehler. Höchstwahrscheinlich wurde nach der Methodendeklaration ein Semikolon gesetzt.

- possible loss of precision
Wenn du 5.03 schreibst meint der Copmiler das ist ein double. In einer Methode in der float verlang wird, wird er deshalb diesen Error ausgeben, weil ein double nicht so einfach in ein float konvertiert werden kann. Wenn du 5.03f schreibst, kann der bereits der Compiler überprüfen ob das ein double wert ist. Dieser meldet dann z.B.: var (float) cannot be applied to (double)
danke an Illuvatar

- unclosed string literal
Bedeutet, dass ein String nicht geschlossen wurde (mit Anführungszeichen). Darauf muss man aufpassen wenn man mehrere Variablen in einen String einbaut.

- incompatible types
Hier wird versucht einer Variable den Wert einer anderen Variable zuzuweisen, aber diese beiden Typen sind nicht
kompatibel. Bsp.:
Java:
String s = "Hello World";
int i = s; // falsch!!

- <symbol> has private access in <class>
Das angesprochene Symbol, also Variable oder Methode ist als privat deklariert, d.h. man kann von der aktuellen
Klasse nicht darauf zugreifen.


Im Anschluss nun noch Kurzerklärungen zu den am häufigsten auftretenden Exceptions und Errors in Java
 
Zuletzt bearbeitet von einem Moderator:

eRaaaa

Top Contributor
Es kommt häufiger mal die Frage auf: “wieso fliegt hier in meinem Code eine ConcurrentModificationException, was ist das für eine Exception” usw. Um ein wenig Licht in die Sache zu bringen, habe ich hier mal einen kleinen Text verfasst:

Fail-Fast Iterator & ConcurrentModificationException

Warum erhalte ich diese Exception?

Laut Dokumentation sollte diese Exception geworfen werden, wenn unzulässige Veränderungen an einem Objekt erkannt werden.

Sie wird oft dann geworfen(bzw. die meisten Fragen im Zusammenhang mit dieser Exception entstehen…), wenn man mit einem Iterator (for-each, iterator(), etc.) über eine Collection läuft und dabei diese Collection direkt über Methoden der Collection verändert (dabei spielt es keine Rolle ob dies durch den selben Thread passiert(oder man sogar nur einen hat), oder aber ein anderer Thread eine Veränderung an ihr durchführt)
Das kommt daher, dass die Iteratoren als sogenannte fail-fast Iteratoren implementiert sind, das heißt, dass sie lieber sofort bei Änderungen reagieren(also eine RuntimeException wie diese werfen) , anstatt später irgendwann in ein willkürliches, nicht-deterministisches Verhalten zu laufen.

Die Datenstruktur ist nach Erfragen des Iterators also quasi gesperrt. Im JDK von SUN wurde dies durch die int-Variable modCount geregelt:

Beispiel-Auszug von Itr aus AbstractList

Java:
/**
* The modCount value that the iterator believes that the backing
* List should have.  If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
 
.......
 
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
 
......
 
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}

und
Beispiel-Auszug von der Methode remove() aus ArrayList()

Java:
public E remove(int index) {
RangeCheck(index);
 
modCount++;
//.....usw
}

Wird nun also die Sammlung verändert(z.B. durch einen Aufruf von remove() , wodurch modCount erhöht wird) und danach ein next() aufgerufen, führt dies durch checkForComodification(); zu einer ConcurrentModificationException!


Wie kann man dennoch über Collections iterieren und bei Bedarf Änderungen vornehmen?

Es gibt mehrere Möglichkeiten! Je nach Anwendungsfall kann/muss man sich für eine entscheiden.

  1. Man merkt sich alle Elemente welche man löschen oder hinzufügen möchte in einer separaten temporären Collection und ruft am Ende Methoden wie removeAll(…) oder addAll(..) auf der “echten” Sammlung auf.
  2. Man erstellt sich eine Kopie der Collection
  3. Man benutzt die normale for-Schleife.
    Simples Beispiel: Wir haben eine Liste “list” mit Strings “Java”,”Javascript”,”C++”,”FORTRAN”
    Wir wollen nun alle Programmier/-Skriptsprachen löschen, welche länger als vier Zeichen lang ist. Iterieren wir nun mit einem Iterator über die Collection und rufen beim Fund solch eines Strings list.remove() auf – wie nicht anders erwartet – erhalten wir eine ConcurrentModificationException.
    Wir können aber zum Iterieren auch die normale for-Schleife nutzen:
    Java:
    		for (int i = list.size() - 1; i >= 0; i--) {
    			if (list.get(i).length() > 4) {
    				list.remove(i);
    			}
    		}
    Auf eines müssen wir bei dieser Variante aber achten: Da wir jetzt das Element löschen, verschieben sich natürlich alle Elemente in der Liste. Daher bietet es sich beim Löschen an, die Liste rückwärts zu durchlaufen(so wie hier) oder wir müssen den Zähler i entsprechend mit ändern (z.B. direkt beim Löschen den Zähler zu dekrementieren – list.remove(i–);
  4. Man benutzt die Methoden des Iterators! Anstelle also direkt auf der Collection remove() aufzurufen, holen wir uns zunächst einen Iterator (.iterator() ) und rufen wann immer wir ein Element löschen wollen, remove() auf dem Iterator auf!
    Je nach Collection gibt es noch weitere Iteratoren, so bietet z.B. das Interface List, welches unter anderem. von Vector, ArrayList oder LinkedList implementiert wird, auch die Möglichkeit sich einen ListIterator zu holen( .listiterator() – ListIterator (Java Platform SE 6) welcher eine add-/und set-Methode bereitstellt!
    Simples Beispiel: (gegeben ist wieder die Liste mit den Programmiersprachen aus 3.))
    Java:
    		for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    			String string = iterator.next();
    			if (string.length() > 4) {
    				iterator.remove();
    			}
    		}

    Möchten wir anstelle etwas zu löschen, auch beim Iterieren etwas einfügen, brauchen wir wie schon angesprochen den ListIterator:

    Java:
    for (ListIterator<String> iterator = list.listIterator(); iterator.hasNext();)

    Anmerkung/Tipp:
    Eclipse: Schreibt man for und drückt anschließend CTRL+Space bietet einem Eclipse die Auswahlmöglichkeit “for- iterate over collection” an, mit der uns automatisch ein Schleifenkonstrukt mit Iterator erstellt werden kann.

    Netbeans: Schreibe forc und drücke [TAB]

Es gibt noch jede Menge weitere Möglichkeiten, die hier vorgestellten Probleme/Lösungen betrafen alle auch Single-Thread-Anwendungen ! Sind mehrere Threads im Spiel, muss man wie gewöhnlich Zugriffe o.ä. an der Collection synchronisieren. Dafür gibt es z.B. in java.util.Collections nützliche statische Methoden wie synchronizedList, die einen thread-sicheren “Wrapper” zurückliefert. Das Iterieren über diese Liste muss dennoch synchronisiert werden(siehe API Doc). Eine weitere Möglichkeit wäre, direkt eine thread-sichere Collection aus dem java.concurrent-Package zu benutzen.

Links:
ConcurrentModificationException (Java Platform SE 6)
ListIterator (Java Platform SE 6)
java.util.Collections
java.concurrent-Package
 
R

Roar

Gast
Runtime Exceptions:

- NullPointerException
Hier wird auf ein nicht-initialisiertes Objekt zugegriffen. Bsp.:
Java:
String s;
if(s.equals("Hello World")) // geht nicht, weil s nicht initialisiert ist
//...

Wobei dieses Beispiel nicht korrekt ist, da bereits beim Kompilieren ein Fehler gemeldet wird (s.o).

- IllegalArgumentException
Diese Exception wird geworfen wenn ein übergebenes Argument an eine Methode oder Konstruktor nicht gültig ist. Folgendes ist ein Beispiel welches eine Methode implementiert die eine IllegalArgumentException werfen kann.
Java:
public void list(int start, int end) throws IllegalArgumentException {
  if(end < start) throw new IllegalArgumentException("end-index is lesser that start-index!");
  for(int i = start; i < end; i++) {
    System.out.println(i);
  }
}

Wenn diese Methode dann so aufgerufen wird:
Java:
list(3,2);

dann wird eine IllegalArgumentException geworfen, da das Ende ja nicht vor dem Start sein kann.

- IndexOutOfBoundsException ( bzw. ArrayIndexOutOfBoundsException)
Dieser Fehler tritt häufig bei Arrays auf. Er zeigt an, dass man auf einen Index im Array gezeigt hat, der über den

Grenzen des Arrays liegt. Bsp.:
Java:
String[] array = new String[5]; // 5 elemente in Arrays, Indezies von 0-4
System.out.println(array[5]); // index 5 gibt es nicht

- StringIndexOutOfBounds
Das ist der gleiche Fehler wie der obige, nur innerhalb eines Strings. Er tritt z.B. bei der Benutzung von substring() auf. Bsp.:
Java:
String s = "Hello World";
System.out.println("Hello "+ s.substring(6, s.length()) );
// falsch!!, weil s.length(); die länge zurückgibt, doch die Index Angabe erfolgt wie immer von 0 an.
System.out.println("Hello "+ s.substring(6, s.length()-1) ); // richtig

- ArithmeticException
Wird geworfen wenn ein Arithmetischer Aunahmefall auftritt, z.B. bei der Division durch 0.

- ClassCastException
Wird geworfen wenn versucht wir ein Objekt in ein anderes zu casten, die beiden Typen aber nicht kompatibel sind.
Bsp.:
Java:
Vector v = new Vector();
v.add("Hello World");
v.add(new MyObject());
String s1 = (String) v.elementAt(0); // richtig, weil das Element ein String ist.
String s2 = (String) v.element(1);
// Exception!! Element ist von Typ MyObject, darum kann man ihn nicht zum String casten.
Seit Java 1.5 gibt es Generics in der Sprachspezifikation, welche durch Typisierung u.a. dabei helfen können, Fehler beim Umgang mit Collections zu vermeiden.
 
R

Roar

Gast
Runtime Errors:

- NoClassDefFoundError
Wird geworfen wenn man versucht eine Klasse (per java.exe oder ClassLoader) zu laden, aber keine solche Klasse ist gefunden wurden. Ist die Klasse im CLASSPATH ?

Dieser Fehler tritt bei Anfängern oftmals auf.

Java:
//aufruf per shell:
C:\MyApps> java MyApp.class // falsch!!
Exception in thread "main" java.lang.NoClassDefFoundError: MyApp/class
// Der Punkt wird als packageseparator geführt

Auch bei richtiger Namensangabe kann es zu diesem Fehler kommen.
becstift hat gesagt.:
Beim Aufruf der Klasse kommt es oft zu diesem Fehler. Mögliche Ursachen könnten folgende sein:


:arrow: Die Klasse muss als
Code:
public
gesetzt sein. z.B.
Code:
public class MeineKlasse

:arrow: Die Classpath - Umgebungsvariable muss den Ordner der Klasse bzw. des Pakets enthalten.

:arrow: Wenn die Klasse in einem Paket ist, muss sie über den Paketnamen aufgerufen werden, z.B.
Code:
java paket.Klasse

:arrow: Der Aufruf der Datei erfolgt ohne die Dateiendung ".class"

Ergänzung von SlaterB:
:arrow: während javac tatsächlich mit Dateien und Pfaden arbeitet (+ CLASSPATH), kennt java allein packages/Klassennamen und CLASSPATH

:arrow: damit die Klasse gefunden wird, entweder ins entsprechende Grundverzeichnis relativ zu den packages wechseln,

:arrow: oder das Grundverzeichnis in den CLASSPATH aufnehmen, sei es in der globalen Umgebungsvariable oder als -cp Parameter beim Aufruf

- OutOfMemoryError
Wird geworfen wenn die VirtualMachine versucht eon Objekt zu allokieren, aber kein Speicherplatz mehr der VM zur
Verfügung steht.

- StackOverflowError
Wird geworfen wenn der Stack "überläuft". Das ist meistens der Fall, wenn eine Methode rekursiv aufgerufen wird,
aber keine Endbedingung existiert.

- UnsupportedClassVersionError
Wird geworfen wenn versucht wird eine Klasse zu laden, das Format des Bytecodes aber nicht mit dem, der aktuellen Java Version übereinstimmt. Beispiel:
Exception in thread "main" java.lang.UnsupportedClassVersionError: <Klasse>
(Unsupported major.minor version 49.0)

In diesem Fall wurde die Klasse mit Java 1.5 kompiliert, aber versucht mit Java 1.4 auszuführen.

Der Stacktrace:
Jede Exception und Error erbt von java.lang.Throwable, d.h. jede Exception beinhaltet in sich einen sogenannten Stacktrace. Dieser wird bei RuntimeExceptions auf System.err ausgegeben, und bei abgefangenen Exceptions kann man ihn per exception.printStackTrace(); ausgeben lassen. Der Stacktrace ist eine zurückverfolgung der Exception von wo sie herkommt. Meisten sind nur die ersten Zeilen wichtig, da bei GUI Anwendungen der großteil des Stacktraces aus der Ausgabe der AWT event dispatching threads besteht. Im Folgenden ist nun ein Stacktrace der bei einer NullPointerException geworfen wird:

Exception in thread "main" java.lang.NullPointerException
at Test5.main(Test5.java:7)

Der Code dazu:

Java:
class Test5 {

  static String s1;
                                 
  public static void main(String[] args) {
    String s2 = "Hello";
    if(s1.equals(s2)) {
      System.out.println("Hello!");
    }
  }
	
}

Jetzt zur Erklärung:

in der ersten Zeile steht die Angabe des Threads, und die Art der Exception: java.lang.NullPointerException
In allen anderen Zeilen steht die Zurückverfolgung der Ausnahme, also in welcher Methode sie verursache wurde, und welche Methode diese Methode aufgerufen hat usw., die ganze Schlange. Hier ist nur ein Eintrag zu sehen:
at Test5.main(Test5.java:7)

Hier wird die Methode angegeben (Test5.main), die Angabe der Quelldate (Test5.java) und die Zeilennummer (7).
In Zeile 7 in Test5.java steht folgendes:
if(s1.equals(s2)) {

Dort wird also die RuntimeException geworfen. Zum Debugen muss man also nachschauen, welche Variablen dort verwendet werden, und welche der Variablen evtl. noch uninitialisiert ist. Hier kommt nur eine in Frage und zwar s1, und genau dort wird auch die Ausnahme geworfen.
s1 wurde bisher nur deklariert, aber nirgends initialisiert. Die Variable hat also noch keinen Initialwert und hat somit den Wert null (nichts), was dann beim Zugriff zu einer NullPointerException führt.


-The serializable class <Klasse> does not declare a static final serialVersionUID field of type long
Die Warnung bekommt man zu sehen, wenn das Interface java.io.Serializable im Spiel ist. Bis Java 1.4.2 war es nicht Pflicht (keine Warnung), eine spezielle Variable in den Code einzufügen. Dann kam es manchmal beim Deserialisieren zu nicht behebbaren Fehlern, die auf unterschiedliche Klassenversionen eines Objektes zurückzuführen waren. Seit Java 1.5 muss diese Variable eingefügt werden, um dieses Problem zu umgehen.
Ist aber nichts Schlimmes, wenn der Code in Ordnung ist und alle Objekte die gleiche Klassenversion haben (komplett neu kompiliert und serialisierte Objekte gelöscht), wird das Programm trotzdem funktionieren, weil die Serialization Runtime einen Standardwert für diese Variable erzeugt.

Das Problem kann umgangen werden, wenn die Klasse, die das Serializable-Interface implementiert, ein statisches, finales Feld mit dem Namen "serialVersionUID" vom Typ long eingesetzt wird.
Serializable (Java 2 Platform SE 5.0)
Code:
static final long serialVersionUID = 1L;

Alternativ kann man z.B. Eclipse so einstellen, dass sie diese Warnung ignoriert.
Preferences -> Java -> Compiler -> Errors/Warning -> Potential programming problems -> Serializable
 
Zuletzt bearbeitet von einem Moderator:
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben