# BufferedReader Verständnisproblem



## neoXxX (25. Dez 2008)

Hi Leute,

ich habe ein Problem den BufferedReader und den InputStreamReader zu verstehen. Insbesondere folgende Konstellation

```
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
```

1.Bedeutet System.in, dass er die Eingabe am Bildschirm ausließt? Was wäre an der Stelle noch möglich? Oder wofür steht System und wofür in?

2.Mit new InputStreamReader(System.in) erzeuge ich ein neues Objekt, das ich als Parameter an br-Objekt vom Typ BufferedReader übergebe.
Wie ist sowas generell möglich?? Heißt doch, dass ein Objekt in Java ohne Referenz gelöscht wird.

3.Landet der eingebene String im br-Objekt oder das InputStreamReader-Objekt?

Ich wäre echt dankbar, wenn jemand den BufferedReader und den InputStreamReader und wie sie genau zusammenhängen erklären könnte. Leider waren die Java-Online-Bücher da ganz und gar nicht aufschlussreich.

4.try "Schleife" ?

Wieso funktioniert der untenstehende Code nicht ohne die try "Schleife". Ist es eher so was wie if und else? Wie aber erklärt sich die Fehlermeldung im Compiler?


```
import java.io.*;

class ReadFromScreen {

  public static void main(String[] args) {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    System.out.print ("Jetzt bitte die Zeichenfolge: " );	
    String Eingabe=null;         // Stringobjekt zur Aufnahme der Eingabe
    try {
      Eingabe = br.readLine();
      System.out.println("Sie haben den folgenden Text eingegeben:");
      System.out.println(Eingabe);
 
    }  catch ( IOException ioe )
      {
      System.err.println(ioe);    // Meldung, falls Fehler beim Einlesen
      }
  }
}
```


Danke schon im vorraus!


----------



## musiKk (25. Dez 2008)

1. Erste Frage ja. Rest in der Dokumentation.
2. Innerhalb der Instanz der Klasse BufferedReader (die hier br heißt), gibt es auch eine Referenz auf deinen InputStreamReader. Ergo trifft "keine Referenz" nicht zu. Denn gibt es keine Referenz auf ein Objekt, wird es - wie du richtig sagst - früher oder später vom Garbage Collector freigegeben.
3. Das sind Implementierungsdetails, die den Nutzer der Klassen eigentlich nicht interessieren müssen. Aber natürlich ist es nicht verkehrt, sich auch mal dafür zu interessieren. Im Ordner des JDK liegt eine src.zip, da sind die Quellen für diese und andere Klassen vorhanden. Wenn du das in Eclipse einbindest, kannst du da auch sehr leicht hinspringen.
4. Schau mal in einem der Online-Bücher (z. B. dem Inselbuch, Punkt 8 dort) nach Fehlerbehandlung.


----------



## Ark (25. Dez 2008)

musiKk hat gesagt.:
			
		

> 2. Innerhalb der Instanz der Klasse BufferedReader (die hier br heißt), gibt es auch eine Referenz auf deinen InputStreamReader. Ergo trifft "keine Referenz" nicht zu. Denn gibt es keine Referenz auf ein Objekt, wird es - wie du richtig sagst - früher oder später vom Garbage Collector freigegeben.


Diese Referenz muss nicht unbedingt intern gespeichert werden (in diesem Fall ist es zwar nötig, aber das ist ein anderes Thema). Die Referenz wird nämlich bereits durch den Aufruf einer Variablen zugewiesen. Um genau zu sein, ist die linke Seite der Zuweisung die lokale Variable, die Parameter der Methode ist.

Ark


----------



## musiKk (25. Dez 2008)

Wie "intern"? Was wäre eine externe Speicherung?


----------



## Ark (25. Dez 2008)

musiKk hat gesagt.:
			
		

> Wie "intern"?


Damit meine ich das Speichern in einer Membervariablen des Objekts. Die Betonung lag dabei eigentlich mehr auf "gespeichert" und nicht auf "intern". Lokale Variablen sind für mich Platz zum Arbeiten, nicht zum Speichern.

Ark


----------



## neoXxX (26. Dez 2008)

Hi, danke erstmal für die Antworten.

Zu Punkt 2 habe ich keine Fragen mehr. Denke ich habe das verstanden.

Zu Punkt 1: Wo genau in der Doku muss ich gucken. Ich nehme an in der Klasse InputStreamReader. Nur blicke ich nicht
was dort die ganzen Parameter bedeuten.
Kann nicht jemand ein paar praktische Befehle schreiben, was man anstelle von System.in verwenden kann und sagen was die bedeuten? Wäre auch hilfreich zu erfahren unter welchen Parameterangaben sich das verbirgt.

Zu Punkt 3: Mit diesen riesigen java-Algorithmen kann ich leider wenig anfangen. Ich wäre für eine einfache Erklärung wie die beiden zusammenhängen bzw. was die Aufgabe der beiden Klassen ist, sehr dankbar.

Zu Punkt4: Kann man try mit der if/else-Abfrage vergleichen?? Wenn man davon ausgeht, dass kein Fehler eintritt, wieso läßt der Compiler eine Übersetzung ohne try nicht zu. Ich möchte doch lediglich den String aus "br" in die String-Variable Eingabe kopieren. Liegt es vielleicht daran, dass das Kopieren aus einem BufferedReader-Objekt zwingend die try-"Abfrage" erfordert?


----------



## musiKk (26. Dez 2008)

Zu 1. solltest du dir z. B. das Konzept der Polymorphie anschauen. Der InputStreamReader erwartet einen InputStream als Parameter (zumindest im zur Diskussion stehenden Konstruktor). Das ist ein Interface und alles, was das Interface implementiert, kann dann verwendet werden. System.in ist ein solcher InputStream, der beim Start der JVM automatisch initialisiert wird.

Für 3. lies wirklich mal irgendwo. Bei Sun ist das ganz gut erklärt. Streams sind recht flexibel. Das beste ist schon, wenn man das Konzept versteht.

Zu 4. verweise ich weiterhin auf o.g. Literatur. Exception-Handling ist ein Grundkonzept von Java und ein Forum ist meiner Meinung nach der Falsche Platz, solche Dinge zu erklären.


----------



## Ark (26. Dez 2008)

neoXxX hat gesagt.:
			
		

> Zu Punkt4: Kann man try mit der if/else-Abfrage vergleichen??


Nicht wirklich. Exceptions dienen eher zum Abbilden des Überschreitens des Defintionsbereichs. Wenn du beispielsweise die Ganzzahldivision nachbaust, wirst du, ganz egal, wie viel Mühe du dir gibst, feststellen müssen, dass der Algorithmus beim Versuch, durch 0 zu dividieren, entweder in eine Endlosschleife gerät oder (schlechter) falsche Ergebnisse liefert. Damit es gar nicht erst so weit kommt, kann man z.b. mit 
	
	
	
	





```
if(divisor==0) throw new IllegalArgumentException("Divisior ist 0");
```
 dem Aufrufer noch halbwegs sauber mitteilen, dass etwas schiefging bzw. schiefgehen würde (Selbstschutz der API).


			
				neoXxX hat gesagt.:
			
		

> Wenn man davon ausgeht, dass kein Fehler eintritt, wieso läßt der Compiler eine Übersetzung ohne try nicht zu. Ich möchte doch lediglich den String aus "br" in die String-Variable Eingabe kopieren. Liegt es vielleicht daran, dass das Kopieren aus einem BufferedReader-Objekt zwingend die try-"Abfrage" erfordert?


Es gibt grob zwei Arten von Exceptions: die vom Typ RuntimeException und alle anderen. RuntimeExceptions sind die, die man durch richtiges Programmieren verhindern könnte. Beispielsweise hätte man als Aufrufer ja vorher selbst testen können, ob der Divisor 0 ist. Anders sieht es bspw. bei IOExceptions aus (die auch keine RuntimeExceptions sind): Selbst wenn du mathematisch lückenlos und widerspruchsfrei zeigen kannst, dass dein Algorithmus zum Schreiben auf einen Stick funktioniert, kannst du nicht verhindern, dass irgendein dummer Nutzer im entscheidenden Augenblick den Stick abzieht.

Ark


----------



## Guest (26. Dez 2008)

Danke euch beiden für die Antworten! So lange kommt Licht ins dunkel   

Zu Punkt 1: Ok, System.in ist ein InputStream. Welche dieser InputStreams muss man als Anfänger denn kennen?
Es reicht mir absolut in der Form:
System.in = Tastatureingabe am Bildschrim

Zu Punkt 3: Danke für die Quelle. Nur ist die leider ist sie auf englisch und sehr umfangreich. Mit dem englischen würde ich ja evtl noch zurande kommen. Jedoch nicht mit der Menge. Mir fehlt leider die Zeit mich mit diesem Thema besonders auseinander zu setzen, da ich bald die prüfung schreibe. Ich will aber dieses Musterbeispiel aber auch nicht einfach so "auswendig" lernen, sondern möchte eine ungefähre Ahnung haben, was das bedeutet.

Soviel habe ich verstanden. Der InputStreamReader erwartet eine InputStream (z.B. System.in) der die Zeichenkette aufnimmt.
Nur was macht der BufferedReader?? Was macht er, wofür ist er zuständig? Ich muss nicht alles wissen, nur was er in etwa tut. 

Zu Punkt 4: Ich verstehe jetzt die Notwendigkeit der Exceptions und wie es funktioniert. 
So wie ich das interpretiere kann man "try" doch mit if/else vergleichen?? Nur, dass das "else" eben eine unbedingt notwendige Fehlerabsicherung/ Fehlermeldung bringt, wenn etwas schief geht und im "if" der Algorithmus steht.

Außerdem frage ich mich wieso man für das Kopieren eines Strings diese Absicherung braucht? Wenn man mit der for-Schleife zum Beipiel Objekte in einen Array kopiert, braucht man auch kein try.
Wieso funktioniert das nicht? --> String eingabe = br. readLine();

Ich weiß, es sind ne Menge fragen. Ich weiß nur nicht, wie ich mir in der Kürze der Zeit dieses Wissen sonst beschaffen soll.


----------



## neoXxX (26. Dez 2008)

Letzte Nachricht von mir --> neoXxX. Sorry, vergessen anzugeben.


----------



## musiKk (26. Dez 2008)

1. Das ist der einzige. Standard unter *nix und auch Windows sind die Streams stdin, stdout und stderr (in Java als System.in/out/err). Die drei werden beim Start automatisch geöffnet. Aber nur einer (in) davon ist für den Input (die anderen beiden für Ausgaben).

3.


> Ich will aber dieses Musterbeispiel aber auch nicht einfach so "auswendig" lernen, sondern möchte eine ungefähre Ahnung haben, was das bedeutet.


Das ist vernünftig. Aus diesem Grund habe ich das auch verlinkt. Ich habe eine ganze Weile mit Streams und Readern rumgefrickelt und geschaut, was mir die Autovervollständigung von Eclipse so alles anbot, bis ich mir doch irgendwann mal das Konzept angeschaut habe (zumal das noch ein einfaches ist).

4. Grob: I/O ist sehr unzuverlässig. Wenn du Daten über das Internet liest, kann die Verbindung abreißen. Wenn du Daten von der Festplatte liest, kann dir jemand die Datei löschen. Das sind alles Fehlermöglichkeiten, die durch eine IOException signalisiert werden, welche gezwungen gefangen (catch) oder weitergeworfen werden (throws) muss. Das ist völlig unabhängig davon, wo die Daten herkommen. Also auch, wenn du aus System.in liest, muss auf einen eventuellen Fehler reagiert werden. Es könnte sein, dass jemand System.in schließt (warum, sei mal dahingestellt) und schon kommt die IOException.

Es geht bei den Exceptions darum, was passieren _kann_ und dass Fehler auftreten können, die außerhalb deines Verantwortungsbereichs auftreten. Du kannst im Zweifel nicht verhindern, dass es Lesefehler gibt. Aber dir wird eine Chance gegeben, darauf zu reagieren. Analysen wie "an dieser Stelle kann logisch gar keine Exception auftreten" kann der Compiler nicht anstellen.


----------



## Ark (26. Dez 2008)

Anonymous hat gesagt.:
			
		

> Soviel habe ich verstanden. Der InputStreamReader erwartet eine InputStream (z.B. System.in) der die Zeichenkette aufnimmt.
> Nur was macht der BufferedReader?? Was macht er, wofür ist er zuständig? Ich muss nicht alles wissen, nur was er in etwa tut.


Also, ganz langsam noch mal und zum Mitschreiben Stoff aus dem ersten Lehrjahr des gemeinen Fachinformatikers:

Computer können nur mit natürlichen Zahlen arbeiten. Genauer gesagt muss alles, was von einem Rechner verarbeitet werden soll, in eine Form gebracht werden, die nur noch von endlich vielen natürlichen Zahlen abhängt. Wenn wir also etwas anderes darstellen wollen als die "rohe" natürliche Zahl, so müssen wir selbst in diese natürliche Zahl ein Symbol/Signal/Zeichen hineininterpretieren.

Viele natürliche Sprachen auf der Welt verwenden Buchstabenschriften, Silbenschriften oder Ideogramme, um das gesprochene Wort schriftlich festzuhalten. Eine Vorschrift, die jedem dieser Zeichen eine natürliche Zahl zuordnet, nennt sich Zeichensatz.

In Java sind InputStreams und OutputStreams Datenströme, wobei die Daten natürliche Zahlen zwischen 0 und 255 inkl. sind. Reader und Writer sind dagegen Datenströme für Zeichen aus natürlichen Sprachen (wie gerade genannt), also z.B. 'A', '?', 'd'. Um InputStreams mit Readern zu verbinden, gibt es InputStreamReader. Analog dazu gibt es OutputStreamWriter. Sie verlangen bei Konstruktion einen Zeichensatz, damit sie wissen, wie sie die Zeichen in natürliche Zahlen bzw. umgekehrt zu überführen haben.

BufferedReader sind Reader, die Zeichen aus natürlichen Sprachen puffern. Sie werden vor allem eingesetzt, wenn die Wahrscheinlichkeit hoch ist, dass du nicht nur ein einzelnes Zeichen lesen willst, sondern weitaus mehr. Wenn du bei einem BufferedReader ein read() ausführst, holt er nicht nur das eine Zeichen, das er dir dann wieder zurückgibt, sondern gleich einen ganzen Sack (Puffer) voll, damit er dir beim nächsten read() sofort antworten kann.

So, und wenn meine Ausführungen jetzt verständlich waren, kannst du mir auch sagen, warum ein BufferedReader ein readLine() hat, ein BufferedInputStream jedoch nicht.



			
				Anonymous hat gesagt.:
			
		

> Zu Punkt 4: Ich verstehe jetzt die Notwendigkeit der Exceptions und wie es funktioniert.
> So wie ich das interpretiere kann man "try" doch mit if/else vergleichen?? Nur, dass das "else" eben eine unbedingt notwendige Fehlerabsicherung/ Fehlermeldung bringt, wenn etwas schief geht und im "if" der Algorithmus steht.


try-catch-Blöcke sind nötig, wenn potentiell die Möglichkeit da ist, dass Code in eine Endlosschleife gerät, weil z.B. jeder Wert, den eine bestimmte Methode erzeugt, falsch wäre. Stell dir vor, du greifst lesend auf das 10. Element eines dreielementigen boolean-Arrays zu. Was soll dabei rauskommen? Zurückgegeben werden kann nur true oder false, aber beide Werte wären falsch. Einfache Lösung: Man entscheidet sich nicht, sondern antwortet einfach nicht auf den Lesezugriff (Endlosschleife). Da das aber nicht gerade die feine englische Art ist, die Unlösbarkeit der Aufgabe mitzuteilen, benutzt man in Java eine ArrayIndexOutOfBoundsException, um mitzuteilen, dass etwas nicht funktioniert hat.

Stellen wir uns jetzt also vor, es käme in einem try-Block eine solche Exception. Wie soll der Code dann weitermachen? Es geht einfach nicht. Das true oder false wäre vielleicht für ein if wichtig gewesen, um zu entscheiden, ob der Code nun links herum oder rechts herum soll. Aber leider wurde weder gesagt, dass es links herum gehen sollte, noch dass es rechts herum gehen sollte. Deswegen geht die Verarbeitung dann im catch-Block weiter. Hier steht normalerweise Code, der irgendwie die Situation behandelt. Dort steht sozusagen der Notfallplan: "Was tun, wenn in der U-Bahn das Licht ausgeht?"

Ark


----------



## neoXxX (27. Dez 2008)

Danke euch beiden nochmal für eure ausführlichen Antworten.
Ihr habt auf jedenfall Licht in die Finternis gebracht.  :toll:


----------

