Ein paar (F)AQs, Teil 2

Wie kann man in Java einzelne Strings de/komprimieren. So wie man es in einem Zip-File machen kann nur eben ohne Zip.

Nehme ein String und trage es in einen ByteArray[Output|Input]Stream ein. Dann nehme den GZIPOutputStream/..InputStream und komprimiere den String in einen ByteArrayXXXStream. Diesen kannst du dann wieder zu einem Bytefeld konvertieren.

Kennt jemand eine einfache Möglichkeit in Java Dateien zu kürzen?

Du kannst eine Datei kürzen, indem du von RandomAccessFile die setLength() Methode nutzt. Leider kann man vorne keine Blöcke ausschneiden (und das möchte man ja eigentlich).

Ich möchte gerne mit JDOM ein XML-Dokument ohne Attribute ausgeben. Gibt es eine Möglichkeit, das mit dem Outputter einfach zu realisieren?

Baue eine Unterklasse von XMLOutputter. Dann kann man schön das Template-Pattern in Anwendung sehen, in dem man die Methode printAttributes() leer lässt:

protected void printAttributes( Writer out, List attributes,
                                Element parent, NamespaceStack namespaces)
  throws IOException { }

Anstatt dann den XMLOutputter einfach die eigene Klasse nehmen.

Der SAX Parser parst doch sequentiell immer die folgende Reihenfolge 1. startDocument(), 2. startElement(), 3. characters(), 4. endElement(), 5. endDocument(), oder?

Durch Character-Chunking kann characters() auch öfters hintereinander aufgerufen werden. Siehe dazu http://www.tutego.de/blog/javainsel/2007/01/character-%E2%80%9Echunking%E2%80%9C-bei-sax/. So etwas wie processingInstruction() kann natürlich auch noch kommen.

Ich würde gerne aus einer MySQL-Datenbank jeweils eine Zeile auslesen, manche Spalten davon bearbeiten und letztendlich alles wieder in eine andere Datenbank schreiben. Im Moment sieht’s ungefähr so aus: a) Verbindung zur Datenbank, b) ResultSet holen, c) Zeile verarbeiten und was machen. Jetzt hab ich aber beim Einlesen schon ein Problem. Ich bekomme  bei dem ResultSet (mit "SELECT * FROM DB") einen Speicherüberlauf. Die Datenbank besteht aus mehreren 100.000 Zeilen und ich weiß leider nicht, wie ich das sonst lösen sollte. Kann man zum Beispiel das ResultSet begrenzen? Also beispielsweise immer wieder 1000 Zeilen lesen oder so? Oder gibt’s noch eine elegantere Lösung?

MySQL kennt leider kein echtes Cursor-Konzept (früherer jedenfalls), sodass der JDBC-Treiber alle Daten auf die Client-Seite überträgt. Mit dieser Technik muss die Datenbank nicht gelockt werden und muss keine Transaktionen unterstützten. Das löst auf einfache Weise ein Problem wie: Der Abholer braucht 10 Stunden für das Lesen, die Tabelle wird aber beschrieben. Kopiert man alles, muss die Datenbank nur für die Übertragung gelockt werden. Schöne Optimierung-Parameter wie fetch-size oder so sind da völlig wertlos. Hier helfen

Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE );

// SENSITIVE ode INSENSITIVE gut überlegen

ResultSet uprs = stmt.executeQuery( "SELECT Bla FROM Blub" );

// Auf die passende Zeile steuern, dann etwa

uprs.updateFloat( "Groesse", 183f );
uprs.updateRow();

Warum bekomme ich bei Hibernate mit session.load(clazz, x) bei Sammlungen ein PersistentSet und kein normales Set?

Der Grund ist einfach: Hibernate verwaltet eine eigenes Set, um Lazy-Loading zu ermöglichen. Ist Lazy-Loading bei 1:n:-Assoziationen eingestellt (Standard), dann wird die Sammlung erst dann geladen, wenn es einen Zugriff auf die Sammlung gibt (Anfragen, add(), …). Der Punkt ist nun: Wie sollte ein Persistence-Provider mitbekommen, dass jmd. nun Daten aus der Sammlung lesen will? Daher fängt das PersistentSet (http://www.hibernate.org/hib_docs/v3/api/org/hibernate/collection/PersistentSet.html) von Hibernate als Proxy die Anfragen ab (PersistentSet ist ein waschechtes java.util.Set) und kann so vor dem tatsächlichen Zugriff auf die Sammlung die Daten schnell laden.

Übrigens hat man in der JPA auch nur die Basis-Collection-Schnittstellen wie Set, List, … aber keine konkreten Klassen wie HashSet, TreeSet,… Die PersistentSet-Doku schreibt aber: "The underlying collection is a HashSet."

Mit Hilfe des Parameters -exclude kann man bei Javadoc komplette Pakete von der Dokumentation ausschließen. Nun möchte ich allerdings nur einzelne Klassen innerhalb eines Pakets ausschließen. Ist das irgendwie möglich?

Wenn du ant (http://ant.apache.org/manual/CoreTasks/javadoc.html) benutzt, schau dir doch mal das FileSet (http://ant.apache.org/manual/CoreTypes/fileset.html) an.

<fileset dir="${server.src}" casesensitive="yes">
  <include name="**/*.java"/>
  <exclude name="**/*Test*"/>
</fileset>

Damit sollte das gehen, etwa so:

<javadoc
 packagenames="..."
 destdir="..."
 ...
  <fileset dir="...">
    <include name="**/*.java" />
    <exclude...>
  </fileset>
</javadoc>

Java 5 heiß ja lange Tiger. Gibt es auch für die anderen Java-Versionen solche Bezeichner?

Für fast jede Java-Version gibt es Code-Namen, etwa für 1.1.4 Sparkler (Diamant), 1.1.5 Pumpkin (Kürbis, auch Trottel), 1.1.6 Abigail (Zofe), 1.1.7 Brutus und 1.1.8 Chelsea . Java 1.2 hieß Playground, und für die folgenden Versionen nutzte Sun Tiernamen (http://java.sun.com/j2se/codenames.html): Cricket 1.2.2 (Grille), 1.3 Kestrel (Turmfalke), Ladybird 1.3.1 (Marienkäfer), 1.4.0 Merlin (Falke), 1.4.1 Hopper (Heuschrecke), 1.4.2 Mantis (Gottesanbeterin), 5 Tiger, 6 Mustang und 7 Dolphin (Delfin). Vielleicht finden wir demnächst auch Java-Flugfrosch, Java-Nashorn und Javaneraffe (lat. Macaca fascicularis, eine krabbenfressende Affenart) – diese Tiere gibt’s wirklich und einen Java-Tiger auch. (Der ist übrigens vom Aussterben bedroht.)

Ich benötige eine Routine zur Bestimmung aller Subklassen einer Klasse bzw. aller Klassen die ein Interface implementieren zur Laufzeit. Leider scheint mit Java Reflection (Class etc.) hier keine Lösung anzubieten (in SmallTalk-80 wäre das kein Problem gewesen 😉

Das Problem lässt sich allgemein auch in Java nicht lösen. Eine (suboptimale) Lösung ist, sich eine Liste aller Klassen zu besorgen (auch das funktioniert nur im Spezialfall) und dann jede Klasse zu fragen, ob sie Unterklasse ist. Dabei muss jedes Class-Objekt auch geladen werden — die Performance ist natürlich richtig schlecht. Dieser Ansatz wird etwa hier realisiert: http://freerails.cvs.sourceforge.net/freerails/jfreerails/src/jfreerails/util/ClassLocater.java?revision=1.2&view=markup. Die Idee ist, zu schauen, welcher Klassenlader die Klassen lädt, und dann über diesen an das Verzeichnis bzw. Jar-Archiv heranzukommen und das dann vollständig zu durchsuchen.

Eine andere Lösung, die oft vorgeschlagen wird, ist die, dass man jede Klasse in einem static {} Block an einer Zentrale anmeldet, sodass man später nur noch diese Zentrale als "Liste aller Klassen" durchsuchen muss. Wenn die Klassen über ein Framework wie JPA oder Spring verwaltet werden ist das auch wieder einfacher. Bei JPA/Hibernate kann zum Beispiel eine Anfrage auf Entity-Beans wie "select o from java.lang.Object o" helfen.

Aus einem Buch unter dem Kapitel "Sprachdesign und Compiler" habe ich folgenden Satz gefunden und als Zitat in meiner Diplomarbeit verwendet: "Variablen können bei der Initialisierung mit dem Schlüsselwort "final" gekennzeichnet werden, was bedeutet, dass sich der Wert dieser Variablen nicht mehr verändern kann." Der Kommentar meines Prof. war: "So einfach ist das nicht"! Ist es nicht so, dass eine mit final deklarierte Variable nicht mehr verändert werden kann?

Worauf dein Prof anspielt ist, dass man final Variablen nicht zwingend bei der Deklaration einen Wert zuweisen muss. Dies kann man später machen, dann aber nur einmal. Nun muss der Compiler durch Flussanalyse verfolgen, ob schon jemand schreibend zugegriffen hat. Und da hat sich der Javac damals in die Nesseln mit gesetzt und das mach den Jikes heute immer noch so. Das Problem war ein switch(). Wenn man den durchfallen lässt, kann man in beiden Teilen die Variable belegen. Ein Beispiel dafür findest du in der FAQ.

Das mit final Variablen und Zuweisungen führt manches mal zu sehr abgefahrenen Lösungen, etwa in der System Klasse. Dort sind die Konsolenströme (in,out,err) final und über einen Hack werden sie nativ bei einer Systeminitialisierung wieder geändert. Das musste man machen, da final Variablen prinzipiell inline gesetzt werden könnte. Das musste man verhindern.

Kennt jemand eine bessere Methode, in Java Potenzen von (kleinen) ganzen Zahlen zu berechnen, als java.lang.Math.pow() zu benutzen und dann von double auf int zu casten?

Wenn man nur 2^n braucht, dann tut es doch ein Shift. Man muss dann aber aufpassen, dass die Bits nicht rausrutschen.

int twoPow( long n )
{
  return 1 << n;
}

Kann mir jemand eine gute Erklärung geben warum ich eine abstrakte Methode nicht static deklarieren kann?

Eine abstrakte Methode ist ja eine Methode, die nicht implementiert ist, also etwa so etwas

abstract class A
{
 abstract void m();
}

Später wird dann die abstrakte Klasse erweitert und die Implementierung nachgeliefert. Wenn die Methode m() aber in A keine Implementierung hat, dann kann Sie auch keine Klassenmethode sein, da Klassenmethoden (statische Methoden) ja nicht an ein Objekt gebunden ist, sondern an die Klasse. Wenn sie statisch wäre, dann könnte man ja etwa

A.m();

schreiben. Doch was soll hier passieren? Also geht das nicht. Eine ähnliche Begründung gilt für private. Wenn die Methode nicht für andere sichtbar ist, dann kann sich aber auch nicht überschrieben werden, da sie keiner sieht. Auch mit final ist es das gleicht. final heißt ja, keiner darf überschreiben. Aber abstract muss man überschreiben.

Andere FAQs

Ähnliche Beiträge

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert