Deutsch
Springe zu
Dein Feedback:
Hat die Seite Deine Erwartung erfüllt? vote3 Ja
vote2 Teilweise
vote1 Nein
Noch ein Kommentar?

Nur falls, Du eine Antwort erwartest, Deine E-Mailadresse

Gegebenenfalls noch Dein Name

Do not change this:
Feedback
Suchen

Java

18-03-2010 01.36

Links und Literatur


Java Aufruf

Java mit mehr Speicher starten

java -Xmx512m

Bestimmte Java Version erzwingen

java -version:1.4

Java Programm compilieren und ausführen

Achtung, das Trennzeichen unter Windows ist nicht ":" sondern ";".

So erzeugt man aus einer .java Datei eine .class Datei
javac -classpath "foo/bar.jar:foo/tests.jar:../foo.jar" MyClass.java
Dabei muss man alle jar Dateien angeben, die direkt von der Klasse genutzt werden (also nicht die, die nur von Klassen genutzt werden, die wir aufrufen).

So erzeugt man jar Dateien
jar cf MyJar.jar MyClass.java
Siehe auch die JAR Dateien erzeugen Anleitung.

So führt man das Java Programm dann aus (jetzt muss man wirklich all jars auflisten die zur Ausführung gebraucht werden)
# java -classpath "foo/bar.jar:foo/tests.jar:../foo.jar:../misc.jar" MyClass

Java debuggen

So kann man auf einem entfernten Rechner Java so starten, dass es im lokalen Debugger untersucht werden kann
java -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n ...
Dabei sorgt
suspend=y
dafür, dass das Programm erst losläuft, wenn der Debugger verbunden ist.
Um den Debugger einzurichten, in Eclipse
open debug digalog
remote java application
new
Rechnername und Port des Java Programms

Kleines Beispiel

Ein Interface, darf nur abstrakte Methoden und Konstanten enthalten
/**
* My Interface
*/
package mypackage;

/**
* @author John Doe
*
*/
public interface MyInterface
{

/**
* @param number The number which is added
* @return The new sum
*/
public double add(final int number);

/**
* The limit for the result after the mathematical operations
*/
final static double maxValue=10000;
}
Eine abtrakte Klasse, enthält mindestens eine abstrakte Methode
/**
* An abstract class which will be used for things which are
* not allowed in an Interface
*/package mypackage;

/**
* @author John Doe
*
*/
public abstract class MyAbstractClass
{

/**
* Constructor
*/
public MyAbstractClass()
{
this.value=0;
}

/**
* This is the current value which will be modified by the
* mathematical operations which are offered
*/
protected double value;

}
Eine normale Klasse, darf höchsten von einer anderen Klasse erben, aber von beliebig vielen Interfaces implementieren.
/**
* This class shows that you can implement multiple Interfaces
*/
package mypackage;

/**
* @author John Doe
*
*/
public class MyClass extends MyAbstractClass
implements MyInterface, MyOtherInterface
{

/* (non-Javadoc)
* @see mypackage.MyInterface#add(int)
*/
public double add(final int number)
{
System.out.println("The maxvalue is " + AdderInterface.maxValue);
double res=this.value+=number;
this.value=res;
return res;
}
}


Variablen

TypeGrößeVon bis
boolean1
char2
byte1-128...127
short2-32768...32767
int4-2147483648 ... 2147483647
long8-9223372036854775808...9223372036854775807
float41,40239846 * 10^-45 ... 3,40282347 * 10^38
double84,94065645841246544 * 10^-324 ... 1,79769131486231570 * 10^308

Autoboxing

int i     = 4711;
Integer j = i; // j = Integer.valueOf(i)
int k = j; // k = j.intValue()

instanceof

String str = "HELLO WORLD";
b = ( str instanceof String ); // (1)
b = ( str instanceof Object ); // (2)
b = ( str instanceof Foo ); // (3)

(1) und (2) sind beide wahr, (3) nicht

Gleichheit

int x,y;
Foo a, b;

x==y // (1)

a==b // (2)

a.equals(b); (3)

(1) Bei Basistypen ein normaler Test auf Gleichheit
(2) Ansonsten Test ob beides eine Referenz auf das gleiche Objekt ist
(3) Inhaltliche Gleichheit mit equals() testen

Wenn man equals nicht selbst implementiert sieht es so aus:
und equals selbst implementieren, default ist das:

public boolean equals( Object obj ) 
{
return ( this == obj );
}

Eine mögliche Implementierung:
public boolean equals( Object obj ) 
{
if ( obj instanceof Foo ) {
Foo tmp = (Foo) obj;
return (bar == tmp.bar)
}
return super.equals( obj );
}

Als Parameter aber Object erwarten und nicht die Klasse für die die Methode gedacht ist. Also nicht:
//public boolean equals(Foo fooObj) {...};

Achtung, wenn man equals ändert, darauf achten, dass aus a.equals(b) auch a.hashcode()==b.hashcode() folgen muss (umgekehrt aber nicht).
Eclipse kann für equals() und hashcode() sinnvolle Vorschläge machen.

Achtung, die Reihenfolge beim equals() Vergleich ist z.B. dann relevant, wenn einer der beiden Objekte null werden kann.
Ist z.B. a potentiell null, b hingegen nicht, kann man das equals von a natürlich nicht aufrufen
// a.equals(b);
b.equals(a);
Können beide null sein, diesen Fall vorher extra abfangen (sonst gibt es eine Exception wenn versucht wird equals auf null aufzurufen).

Conditional Expressions

Kurzschreibweise für bedingte Zuweisung
//if(ungerade) max=l; else max=l-1;
int max=(ungerade) ? l : l-1;

Kurzschlußoperatoren

boolean b1 = true || foo(); // (1)
boolean b2 = true | foo(); // (2)
boolean b3 = false & foo(); // (3)
(1) foo() wird nicht aufgerufen
(2) foo() wird aufgerufen
(3) foo() wird aufgerufen

Arrays

int i[];   // == int [] i;
Foo[] x;

int i[][]; // == int [][] i == int[] i[]
int[] i, x[], y; // == int [] i; int [][]x; int[] y;

int[] prim = { 5, 7, 7 + 4, };

Array mit vorgegebener Größe:
// int hundredElements[ 100 ];  <-- ERROR
int[] hundredElements;
hunderdElements = new int[ 100 ];

int[] prim;
prim = new int[]{ 5, 7, 11, };

Arraygröße

System.out.println( hunderedElements.length );

Mehrdimensionale Arrays

Rechteckiges Array
int i[][]=new int[3][4];

Beliebiges mehrdimensionales Array
int i[][]=new int[3][];
i[0]=new int[7];
i[1]=new int[19];
i[2]=new int[2];
i[3]=new int[100];

Anonyme Arrays

foo( new double[]{ 1.1, 2,5, 3.2 } );

Arrays durchlaufen


double sum = 0;
double[] myarray;
List<Double> mylist=new LinkedList<Double>();

// (1)
for ( int i = 0; i < myarray.length; i++ )
{
sum += myarray[i];
}

// (1b)
for ( double n : mylist )
{
sum += n;
}

// (2)
for (ListIterator<Double> i = mylist.listIterator(); i.hasNext(); )
{
sum+=i.next();
}

// (2b)
for ( double n : myarray )
{
sum += n;
}
(1) Normaler Array Durchlauf
(1b) Kurzschreibweise für (1)
(2) Durchlauf eines Containers mit einem Iterator
(2b) Kurzschreibweise für (2). Man verliert aber den Vorteil gegebenfalls einen Iterator zur Hand zu haben (z.B. zum Löschen von Elementen).

Unnötige Methodenaufrufe in for Schleifen sparen
Häufig sehen for Schleifen so aus
for(int a=0; a<getMaxA(); a++)
Wenn sich der Rückgabewerte der Methode aber für die Dauer des Schleifendurchlaufes nicht ändert und die Methode eine nennenswerte Laufzeit hat, kann man die Schleife über eine weitere Variable deutlich beschleunigen
for(int a, int b=getMaxFoo();
a<b;
a++);

Teile eines Arrays in einen anderen Array oder in sich selbst kopieren

static void arraycopy( Object src, int srcPos, Object dest, int destPos, int length );

int[] y = Arrays.copyOfRange( x, 6, 9 );

Einen Array in einen Vector wandeln

So kann man einen String Array in einen String Vector wandeln
String [] myArray;
...
Vector<String> myVector = new Vector<String>(Arrays.asList(myArray));

Array Vergleichen

Arrays.equals( a1, a2 ) );   // (1)
Arrays.deepEquals( a1, a2 ); // (2)
// (1) Referenzen der Elemente im Array müssen gleich sein
// (2) Inhalt muss gleich sein // (2)

Undefinierte Parameter Anzahl

Methoden können eine undefinierte Anzahl an Parametern erwarten, ansprechbar wie ein Array
int max( int... x)
{
System.out.println(x.lenght);
}

Clone

Foo x,y;
x=new Foo();
y=x.clone();
Flache Kopie von Objekten erzeugen:


Überdeckte Namen

void foo(int x)
{
x = 12; // (1)
this.x = 12; // (2)
this.x=x;
}

(1) Zuweisung an lokale Variable x
(2) Zuweisung an Objektvariable x

enum

public enum Weekday
{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

Der Zugriff erfolgt so:
Weekday.MONDAY

In den case Statements einer switch Anweisung dagegen so:
MONDAY

Über Enums kann man iterieren
for (Tag tag:Weekday.values()) { }

Override

Optional erklären dass man eine Methode des Vaters überschreibt (Fehler falls nicht)
@Override
public void foo( int alter )

Konstruktor

Anderen Konstruktor der eigenen Klasse aufrufen
this(5);
muss die erste Anweisung des Konstruktors sein, keine Objektvariablen übergebbar

Wenn man eine Klasse hat, von der es nur wenige Ausprägungen gibt, wie z.B. Boolean.
Dann macht es oft keinen Sinn, dass man mit new beliebig viele verschiedene Objekte dieser Klasse erzeugen kann. Eine besser Variante ist es dann, statt einem Konstruktor eine valueOf() Methode anzubieten
public static valueOf(boolean b)

Diese liefert dann immer wieder die wenigen Objekte zurück die es geben kann, hier z.B. entweder Boolean.TRUE oder Boolean.FALSE. Es darf dann natürlich keine Methode geben, ob den Wert eines solchen Objektes zu verändern, weil sonst auch alle anderen Nutzer dieses Objektes davon betroffen wären.

Exemplarinitialisierern

Initialisieren von Variablen in allen Konstruktoren
class Foo
{
int j=1; // (1)

Foo()
{
this.k=0;
}

Foo( int i )
{
this.k = j;
}
}

entspricht
class Foo
{
int j; // (1)

Foo()
{
this.j=1; // (1)
this.k=0;
}
Foo( int i )
{
this.j = 1; // (1)
this.k = i;
}
}

Bei statischen Variablen
public class Foo
{
static int x = 2;
}

entspricht

public class InitStaticVariable 
{
static int x;
static
{
x = 2;
}
}


Super

Konstruktor des Vaters aufrufen
super(5);

Methode des Vaters aufrufen
@Override
public void foo( int alter ) {
super.foo();
...
}


final

Variable nicht änderbar (wohl aber Methoden aufrufbar die sie ändern)
final int x=3;
final Foo y=new Foo();
y.reset();

Erben nicht möglich
final class Bar
{
// ...
}

Überschreiben nicht möglich
class Foo
{
final void bar();
}


Innere Klassen

class Foo
{
class Bar
{
}
}
Zum Erzeugen eines Objekts der inneren Klasse, braucht man ein Objekt der äußeren Klasse. Versucht man z.B. in einer statischen Methode der äußeren Klasse ein Objekt der inneren Klasse zu erzeugen würde das fehlschlagen
No enclosing instance of type foo is accessible. Must qualify the allocation with an enclosing instance of type foo (e.g. x.new Bar() where x is an instance of foo).
Nur innere Klassen dürfen Private oder Protected sein. Wenn sie es sind, hat es Einfluss darauf, wer sie benutzen darf.

Statische Klasse

public class Foo
{
static String s = "HELLO WORLD";
int i = 1;

static class Bar
{
void test()
{
System.out.println(s);
// System.out.println( i ); // (1)
}
}
}


Mitglieds- oder Elementklassen
public class Foo
{
String s = "Hello World";

class Bar
{
void test1()
{
System.out.println( s );
}

//static void test2() { } // (2)
}
}

Von aussen erzeugen
Foo a = new Foo();
Bar b = a.new Bar();


Lokale Klassen

public class Foo
{
public static void main( String[] args )
{
int i = 1;
final int j = 2;

class Bar
{
Bar() {
System.out.println( j );
//System.out.println( i ); // (3) Fehler, da i nicht final
}
}
new Bar();
}
}

Anonyme innere Klassen

Anonyme innere Klassen erben entweder von einer anderen Klasse oder implementieren eine Schnittstelle
class Foo()
{
// ...
}

interface Bar()
{
// ...
}

class Blub{}
{
new Foo()
{
...
}
new Bar()
{
...
}
}

Generische Datentypen

class Foo<T>
{
private T val;

void setValue( T val )
{
this.val = val;
}

T getValue()
{
return val;
}
}

Foo<String> stringFoo = new Foo<String>();
Foo<Integer> intFoo = new Foo<Integer>();
Foo<Point> pointFoo = new Foo<Point>();

class Bar
{
public static <T> T myMethod( T a, T b )
{
//...
}
}

Comparable

Wenn man Comparable implementiert ist es oft sehr störend, dass man dann als Parameter jede beliebige andere Klasse akzeptieren muss. So kann man es nur für eine Bestimmte Klasse implementieren
public class Foo implements Comparable<Foo>
{
public int compareTo(Foo pOther)
{
}
}

Javadoc

/**
* @see Bar
* @link Bar
* @version 1.01
* @author John Doe
* @param x A number
* @param y Another number
* @return This method always returns 5
* @exception NumberFormatException
* @throws NumberFormatException
* @category Setter
* @deprecated Since yesterday
*/
public int foo(int x, float y)
{
return 5;
}

Exceptions

try
{
// ...
return 5;
}
catch ( Exception e )
{
System.err.println( "Error");
}
finally
{
... // (1)
// return 7; (2)
}
(1) auf jeden Fall, auch nach dem return
(2) keine Exception kann nach oben durchgereicht werden

Eigene Exceptions

public class ClubException extends RuntimeException
{
public ClubException()
{
}

public ClubException( String s )
{
super( s );
}
}

Stacktrace

kill -3 PID
jstack PID;
Thread.dumpStack();

Assert

Sicherstellen dass die gegebene Bedingung erfüllt ist
assert(i>0);
Überwachung der Assertions aktivieren
java -enableassertions      foo
java -enableassertions:bar foo

Multithreading

Erste Variante

Von der Klasse
Thread
erben und die Methode run überschreiben.
public class Foo extends Thread
{
@Override
public void run()
{
// ...
}
}

Jetzt einfach ein Objekt dieser Klasse erzeugen und die Methode
start()
und nicht
run()
aufrufen.
final int nrOfThreads=4;
Foo [] f=new Foo[nrOfThreads];
for(int i=0; i<nrOfThreads; i++)
{
f[i]=new Foo();
f[i].start();
}

Zweite Variante

Das Interface
Runnable
implementieren
public class Bar implements Runnable
{
public void run()
{
// ...
}
}

final int nrOfThreads=4;
Thread [] f=new Thread[nrOfThreads];
for(int i=0; i<nrOfThreads; i++)
{
f[i]=new Thread(new Bar());
f[i].start();
}

Auf das Ende eines Threads warten

try
{
for(int i=0; i<nrOfThreads; i++) f[i].join();
}
catch (InterruptedException e) {};
Normalerweise läuft ein Programm so lange weiter, bis auch der letzte Thread sich beendet hat. Ruft man auf einem Thread die Methode
setDaemon(true);
auf, wird auf das Ende dieses Threads nicht mehr gewartet.

Threads von außen beenden

Um einen Thread von außen beenden zu können, ist es hilfreich, wenn dieser auf
!isInterrupted()
testet und
InterruptedException
Exceptions fängt und dann selbst
interrrupt()
aufruft. Z.B.
while (!isInterrupted())
{
try
{

...

}
catch ( InterruptedException e )
{
interrupt();
}
}
Jetzt kann man den Thread von außen mit
interrupt()
beenden.

Synchronized

Methode darf nur von einem Thread gleichzeitig betreten werden
public class Foo
{
synchronized public static void bar()
{
// ...
}
}

Pro Objekt darf Methode nur von einem Thread gleichzeitig betreten werden
public class Foo
{
synchronized public void bar()
{
// ...
}
}

Entspricht
public class Foo
{
public void bar()
{
synchronized(this)
{
// ...
}
}
}

Alternative:
lock.lock();
// ...
lock.unlock();

ThreadLocal

Variablen auf die nur der entsprechenden Thread Zugriff hat (auf private Attribute hätte alle Objekte der entsprechenden Klasse Zugriff).
ThreadLocal foo = new ThreadLocal()
{
protected int bar()
{
return 5;
}
};

Datencontainer

Entweder für beliebige Objekte
Collection c = new LinkedList(); 
c.add("Hello");
c.add("World");
for ( Object x : c ) System.out.println( x );

Oder für spezielle
Collection<String> c = new LinkedList<String>();
for ( String x : c ) System.out.println( x );

Listen

ArrayList, LinkedList

Mengen

HashSet, TreeSet, LinkedHashSet

Assoziativspeicher

HashMap, TreeMap, LinkedHashMap, WeakHashMap

  • man hat ein Object O
  • und einen Key K
  • Von dem Key K gibt es ein H(K)
Die HashMap fügt im Hash dann unter H(K) alle Objekte O ein. Es kann mehrere Objekte O geben, die den gleichen Wert für H(K) haben, aber unterschiedliche Werte für K. Ist auch K gleich, wird der vorherige Eintrag überschrieben.
Für die Klasse Integer gilt z.B. H(K)=K, das muss aber nicht so sein.

Queue

LinkedList, ArrayBlockingQueue, PriorityQueue

Sortieren von Datencontainern

So kann man eine Collection sortieren lassen:
public class MyFooComparator implements Comparator<Foo>
{
...

@Override
public int compare(Foo o1, Foo o2)
{
...
}

...
}

List<Foo> myList;
Collections.sort(myList);

Comparator myComparator=new MyFooComparator();
Collections.sort(myList, myComparator);
Im ersten Fall muss Foo Comparable implementieren, im zweiten Fall kann man seine(n) eigenen Comparator(en) schreiben.
Die Sortierung arbeitet direkt auf dem Container selbst, gegenfalls vorher klonen.

Bei Sortieren kann man leicht das Problem bekommen, dass man zwei Elemente a, b hat, die nicht gleich sind (!a.equals(b)). Allerdings könnten beide Objekte bezüglich einer Sortierung weder kleiner noch größer sein. Beispielsweise bei der Sortierung von Personen nach Schuhgröße. a und b können ganz verschiedene Menschen sein und dennoch genau die selbe Schuhegröße haben. In diesem Fall muss man besonders mit einem TreeSet Container aufpassen. Dieser speichert jedes Objekt höchstens ein mal und aus a.compareTo(b)==0 schließt er (fälschlicherweise?) nur eines der beiden Objekte muss im Container gespeichert werden. Lösung: compareTo() auf mehr Attribute ansetzten oder statt TreeSet eine andere Datenstruktur benutzen (TreeBag?)

Dateien und Verzeichnisse

Dateien und Verzeichnisse

Datum

Zahlreiche Methoden der Date Objekte sind seit einiger Zeit deprecated. Mit der Hilfe der Calendar Klasse kann man weiterhin auf die entsprechenden Datumsfelder zugreifen:

Date lCurrentDate=new Date();
Calendar lCal=Calendar.getInstance();
lCal.setTime(lCurrentDate);
lCal.get(Calendar.YEAR);
lCal.get(Calendar.MONTH);
lCal.get(Calendar.DAY_OF_MONTH);

Und entsprechend lässt sich das Datum auch manipulieren

Calendar lToday = new GregorianCalendar();
lToday.set(Calendar.HOUR_OF_DAY, 23);
lToday.set(Calendar.MINUTE, 59);
lToday.set(Calendar.MINUTE, 0);
lToday.set(Calendar.SECOND, 0);
lToday.set(Calendar.MILLISECOND, 0);
Date lNewDate=lToday.getTime();

Möchte man von einem gegeben Datum einige Tage abziehen oder addieren geht das so
Calendar calendar = new GregorianCalendar();
calendar.add(Calendar.DAY_OF_MONTH, -14);
Date lNewDate=calendar.getTime();

So kann man ein Datum in einen schönen String umwandeln (format()) oder aus einem beliebigen String ein Datum erzeugen (parse())
Date d;
...
SimpleDateFormat f = new SimpleDateFormat("MMddyyyy");
String s=f.format(d);

Reflection

Class c=null;
try
{
c = Class.forName("foo");
} catch (ClassNotFoundException ex)
{
// ...
}

Apache Commons/

Nützliche Java Komponenten Apache Commons.

Objekte in Strings umwandeln

ToStringBuilder
ToStringBuilder.reflectionToString(this);

new ToStringBuilder(this).append("Name: ", name).append("ID: ", id).toString();

one-jar

Mit one-jar kann man mehrere jars in ein großes jar packen und über one-jar selbststartend machen.

JAD Decompiler

Mit dem JAD Java Decompiler aus class-Dateien wieder lesbaren Quellcode machen. Mit dem Eclipse Plugin JADClipse sogar vollautomatisch öffnen der entsprechenden Klassen.

String in Zahl konvertieren

Integer.parseInt("042", 10);

0 Padding

So kann man den String year mit führenden Nullen auf 4 Stellen auffüllen:
String s=String.format("%04d",year);
Syntax:
%[flags][width]conversion

Flags '0' (0 Padding)
Conversion 'd' Integer, 'f' Float, 't' date, 'T' Time

BigDecimal

Ein BigDecimal erzeugen
BigDecimal x=new BigDecimal("1.123456789");

Ein BigDecimal runden
BigDecimal y=x.setScale(2, BigDecimal.ROUND_HALF_UP);
(x bleibt dabei unverändert)

Mit BigDecimal teilen
BigDecimal a=new BigDecimal("1").setScale(0);
BigDecimal b=new BigDecimal("1.2345");
BigDecimal r=a.divide(b, RoundingMode.HALF_UP);
Achtung, die Genauigkeit beim Teilen zweier BigDecimal wird durch das Objekt festgelegt, dessen divide Methode aufgerufen wird. Das kann zu überraschenden Ergebnissen führen! Daher überlegen, die Genauigkeit beim Teilen anzugeben
BigDecimal r=a.divide(b, 7, RoundingMode.HALF_UP);

Gibt man beim teilen zweier BigDecimal Zahlen keine Roundsart an, und passt das Ergebnis nicht in ein BigDecimal (z.B. 1/3), gibt es eine Exception
java.lang.ArithmeticException: Non-terminating decimal expansion; noexact representable decimal result.
Deshalb beim Teilen immer eine Rundungsart angeben!

JMX

jconsole

Kleine Java Tools

jvisualvm

OutOfMemoryError: Java heap space

Als erstes den Heap Speicher hochsetzen
-Xmx512m
Falls das nicht hilft, aktuellen heap Speicherverbrauch des Programms mit der genannten PID ausgeben
jmap -histo PID
Oder aber abwarten bis es nicht mehr gereicht hat und dann erst auswerten
# java -XX:+HeapDumpOnOutOfMemoryError -jar foo.jar
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid29731.hprof ...
Heap dump file created [1271286324 bytes in 143.266 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
...

Und die Datei dann auswerten
jhat -J-Xmx512m java_pid29731.hprof
...
Started HTTP server on port 7000

31-07-2011 00.07

Swing

Links

Architektur

Nach dem Model-View-Controller Prinzip werden eigentlich Model, View und Controller getrennt. Swing Anwendungen fassen dagegen View und Controller zusammen. Das wird auch Model View Presenter genannt.

Beispiel

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
* @see <a href="http://java.sun.com/docs/books/tutorial/uiswing/learn/example2.html">Swing Tutorial</a>
*/
public class MySwingApplication implements ActionListener
{
private static String labelPrefix = "Number of button clicks: ";
private int numClicks = 0;
final JLabel label = new JLabel(labelPrefix + "0 ");

public Component createComponents()
{
JButton button = new JButton("Hit me!");
button.setMnemonic(KeyEvent.VK_I);
button.addActionListener(this);
label.setLabelFor(button);

JPanel pane = new JPanel(new GridLayout(0, 1));
pane.add(button);
pane.add(label);
pane.setBorder(BorderFactory.createEmptyBorder(
30, //top
30, //left
10, //bottom
30) //right
);

return pane;
}

public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText(labelPrefix + numClicks);
}

private static void initLookAndFeel()
{
String lookAndFeel = null;

lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
try
{
UIManager.setLookAndFeel(lookAndFeel);
}
catch (Exception e)
{
System.err.println("Couldn't get specified look and feel");
}
}

private static void createAndShowGUI() {
initLookAndFeel();
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("My Swing Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

MySwingApplication app = new MySwingApplication();
Component contents = app.createComponents();
frame.getContentPane().add(contents, BorderLayout.CENTER);

frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Wer hat den Event ausgelöst

Wenn man mit einer Klasse die Events von mehreren Swing Komponenten verarbeiten will, kann man über den ActionCommand unterscheiden was gemacht werden muss:

private final static String CMD_OK="Yes!"
private final static String CMD_NO="No :-(";

...

JButton buttonOK = new JButton("OK");
buttonOK.setActionCommand(CMD_OK);
buttonOK.addActionListener(this);

JButton buttonNo = new JButton("Cancel");
buttonNo.setActionCommand(CMD_NO);
buttonNo.addActionListener(this);

...

@Override
public void actionPerformed(ActionEvent e)
{
if(CMD_OK.equals(e.getActionCommand()))
{
...
}
else if(CMD_NO.equals(e.getActionCommand()))
{
...
}
}

Swing Layout

Die Platzierung von GUI Elementen via Spring kann man mithilfe verschiedener Layout Manager erreichen.

Kein Layout Manager

Without a Layout Manager (Absolute Positioning)
Für jede Komponente muss über setBounds genau angegeben werden, wo der Knopf hin soll und wie breit er sein soll.

public class Example extends JFrame
{
...
setLayout(null);
JButton demo = new JButton("OK");
demo.setBounds(posX, posY, sizeX, sizeY);
add(demo);
pack();
...
}


FlowLayout Manager

FlowLayout Manager
Die Komponenten werden reihenweise hinzugefügt, sobald die Reihe voll ist, wird die nächste Reihe angefangen.

public class Example extends JFrame
{
...
LayoutManager layManager=new FlowLayout(FlowLayout.LEFT);
setLayout(layManager);
JButton demo = new JButton("OK");
add(demo);
...
pack();
...
}

GridLayout Manager

GridLayout Manager
Die Komponenten werden automatisch nacheinander in einem x/y Raster abgelegt. Auf die Platzierung der Objekte kann kein direkter Einfluss genommen werden.

public class Example extends JFrame
{
...
LayoutManager layManager=new GridLayout(5, 4);
setLayout(layManager);
JButton demo = new JButton("OK");
add(demo);
...
pack();
...
}

GridBagLayout Manager

GridBagLayout Manager
Wie der GridLayout Manager, man kann aber über sogenannte GridBagConstraints direkten Einfluss darauf nehmen, wo die Komponenten platziert werden.

public class Example extends JFrame
{
...
LayoutManager layManager=new GridBagLayout();
setLayout(layManager);
JButton demo = new JButton("OK");
GridBagConstraints c = new GridBagConstraints();
c.gridx=1;
c.gridy=3;
add(demo, c);
...
pack();
...
}

BorderLayout Manager

BorderLayout Manager
Trennt in 5 Bereiche ab. Zwei sehr breite oben und unten (NORTH, SOUTH), einen großen Bereich in der Mitte (CENTER) und je nach eines links und rechts von der Mitte (WEST, EAST). Sehr praktisch, wenn man z.B. eine Toolbar oder eine Statusleiste platzieren möchte.

public class Example extends JFrame
{
...
LayoutManager layManager=new BorderLayout();
setLayout(layManager);
JToolBar toolbar = new JToolBar();
...
add(toolbar, BorderLayout.NORTH);
...
}

BoxLayout Manager

BoxLayout Manager
Ernöglicht es, Komponenten in eine Reihe oder einer Spalte anzuordnen. Die Komponenten werden dabei nicht größer dargestellt als unbedingt notwendig.

public class Example extends JFrame
{
...
JPanel panel=new JPanel();
LayoutManager layManager=new BoxLayout(panel, BoxLayout.Y_AXIS);
panel.setLayout(layManager);
JButton demo = new JButton("OK");
panel.add(demo);
...
this.add(panel);
...
pack();
...
}

CardLayout Manager

CardLayout Manager
Beinhaltet mehrere alternative Container, die jeweils über einen String identifiziert werden und zwischen denen dann über diesen String hin und her geschaltet werden kann.

public class Example extends JFrame
{
...
JPanel panelCards;
...
panelCards=new JPanel();
LayoutManager layManager=new CardLayout();
panelCards.setLayout(layManager);

JPanel panel1=new JPanel();
panel1.add(new JButton("Demo1_1"));

JPanel panel2=new JPanel();
panel2.add(new JButton("Demo2_1"));
panel2.add(new JButton("Demo2_2"));

JPanel panel3=new JPanel();
panel3.add(new JButton("Demo3_1"));

panelCards.add(panel1, "CARD1");
panelCards.add(panel2, "CARD2");
panelCards.add(panel3, "CARD3");

add(panelCards);
...
pack();
...

public void switchToCard2()
{
((CardLayout) panelCards.getLayout()).show(panelCards, "CARD2");
}

...

}

Tabbed Panes
Tabbed Pane Tabbed Panes gehören zwar eigentlich nicht zu den Layout Managern, haben aber eine ähnliche Funktionalität wie der CardLayout Manager. Sie nehmen alternative Container auf, zwischen denen der User dann über Tabs hin und her schalten kann.

public class Example extends JFrame
{
...
JTabbedPane tabbedPane = new JTabbedPane();

JPanel panel1=new JPanel();
panel1.add(new JButton("Demo1_1"));

JPanel panel2=new JPanel();
panel2.add(new JButton("Demo2_1"));
panel2.add(new JButton("Demo2_2"));

JPanel panel3=new JPanel();
panel3.add(new JButton("Demo3_1"));

tabbedPane.addTab("First tab", panel1);
tabbedPane.addTab("Second tab", panel2);
tabbedPane.addTab("Third tab", panel3);

...
add(tabbedPane);
...
pack();
...
}

GroupLayout Manager

GroupLayout Manager Für diesen Layout Manager, betrachtet man alle Komponenten von links nach rechts und einmal alle Komponenten von oben nach unten. Für jede Komponente und beide Betrachtungsweise gibt man dann an, welche Komponenten nebeneinander und welche in Reihe zueinander stehen.

public class Example extends JFrame
{
...
JPanel panel=new JPanel();
GroupLayout layout=new GroupLayout(panel);
panel.setLayout(layout);

layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);

JButton ok=new JButton("OK");
JButton ca=new JButton("Cancel");
JLabel lName=new JLabel("Name:");
JTextField fName=new JTextField("Your name? ....");
JLabel lAge=new JLabel("Age:");
JTextField fAge=new JTextField("Your age? ....");

/* Layout:
*
* Name: ______ OK
* Age: ______ Cancel
*/

// horizontal
{
GroupLayout.ParallelGroup columnLeft = layout.createParallelGroup(). addComponent(lName). addComponent(lAge);
GroupLayout.ParallelGroup columnMiddle = layout.createParallelGroup(). addComponent(fName). addComponent(fAge);
GroupLayout.ParallelGroup columnRight = layout.createParallelGroup(). addComponent(ok). addComponent(ca);
GroupLayout.SequentialGroup leftToRight= layout.createSequentialGroup().addGroup(columnLeft).addGroup(columnMiddle).addGroup(columnRight);
layout.setHorizontalGroup(leftToRight);
}

// vertical
{
GroupLayout.ParallelGroup rowTop = layout.createParallelGroup(). addComponent(lName).addComponent(fName).addComponent(ok);
GroupLayout.ParallelGroup rowMiddle = layout.createParallelGroup(). addComponent(lAge). addComponent(fAge). addComponent(ca);
GroupLayout.SequentialGroup topToBottom = layout.createSequentialGroup().addGroup(rowTop). addGroup(rowMiddle);
layout.setVerticalGroup(topToBottom);
}
add(panel);
pack();
...
}

Swing GroupLayout
Was in diesem Beispiel erreicht wird:
  • Horizontal
    • die beiden Labels sind parallel zueinander
    • die beiden Eingabefelder sind parallel zueinander
    • die beiden Buttons sind parallel zueinander
    • alle drei sind in Reihe zueinander
  • Vertikal
    • Name Label, Eingabefeld und OK Button sind parallel zueinander
    • Alter Label, Eingabefeld und Cancel Button sind parallel zueinander
    • beide sind in Reihe zueinander

Wenn man nicht aufpasst, kann man versehentlich zu schwache Einschränkungen definieren. Ändern man z.B. im Beispiel den horizontalen Abschnitt so ab:

 // horizontal
{
SequentialGroup hs1=layout.createSequentialGroup().addComponent(lName).addComponent(fName).addComponent(ok);
SequentialGroup hs2=layout.createSequentialGroup().addComponent(lAge). addComponent(fAge). addComponent(ca);
ParallelGroup hp1=layout.createParallelGroup(GroupLayout.Alignment.CENTER).addGroup(hs1).addGroup(hs2);
layout.setHorizontalGroup(hp1);
}

erreicht man für den horizontalen und den vertikalen Teil die gleichen Einschränkungen:
  • Name Label, Eingabefeld und OK Button sind parallel zueinander
  • Alter Label, Eingabefeld und Cancel Button sind parallel zueinander
  • beide sind in Reihe zueinander

Keiner von beiden erzwingt, dass auch z.B. die beiden Eingabefelder zueinander parallel sind.
Swing Group Layout broken
Das ist vermutlich nicht gewünscht.


SpringLayout Manager

SpringLayout Manager (Für GUI Builder gedacht)
Die Komponenten werden relativ zum Rand benachbarter Komponenten angegeben.

public class Example extends JFrame
{
...
JPanel panel=new JPanel();
SpringLayout layout=new SpringLayout();
panel.setLayout(layout);

JButton ok=new JButton("OK");
JButton ca=new JButton("Cancel");
JLabel lName=new JLabel("Name:");
JTextField fName=new JTextField("Your name? ....");

/* Layout:
*
* Name: ______ OK
* Cancel
*/
panel.add(lName);
panel.add(fName);
panel.add(ok);
panel.add(ca);

// the left edge of lName starts 5 pixel right of the left edge of the surrounding panel
layout.putConstraint(SpringLayout.WEST, lName, 5, SpringLayout.WEST, panel);
// the top edge of the lName starts 20 pixel beneath the top edge of the surrounding panel
layout.putConstraint(SpringLayout.NORTH,lName, 20, SpringLayout.NORTH, panel);

// the left edge of fName starts 5 pixel right of the right edge of it neighbour the lName
layout.putConstraint(SpringLayout.WEST, fName, 5, SpringLayout.EAST, lName);
layout.putConstraint(SpringLayout.NORTH, fName, 20, SpringLayout.NORTH, panel);

layout.putConstraint(SpringLayout.WEST, ok, 5, SpringLayout.EAST, fName);
layout.putConstraint(SpringLayout.NORTH, ok, 20, SpringLayout.NORTH, panel);

// the left edge of the ca starts exactly where the left edge of ok does
layout.putConstraint(SpringLayout.WEST, ca, 0, SpringLayout.WEST, ok);
// the top edge of the ca is 5 pixels beneath the ok's bottom edge
layout.putConstraint(SpringLayout.NORTH, ca, 5, SpringLayout.SOUTH, ok);

// now the panel itself needs to be stretched:

// the right edge of the panel should be 5 pixels right of the end of the right edge of the ca
layout.putConstraint(SpringLayout.EAST, panel, 5, SpringLayout.EAST, ca);
// the bottom edge of the panel should be 5 pixels beneath the bottom of the ca
layout.putConstraint(SpringLayout.SOUTH, panel, 20, SpringLayout.SOUTH, ca);

add(panel);
pack();
...
}

Swing SpringLayout

Was läuft in Swing in welchem Thread

Concurrency in Swing
Es gibt 3 Arten von Threads die man für die Swing Programmierung beachten muss:

Initial threads

Der oder die Threads, die das Top GUI Objekt erzeugen und seine Ausführung (in einem neuen Thread) veranlassen. Das ist im einfachsten Fall die Klassen mit der main Methode, die irgendwo ein SwingUtilities.invokeLater mit einem GUI Objekt aufruft und damit zu Ende ist.

Event Dispatch Thread

Die Swing Klassen sind per se nicht thread sicher. Alle Interaktionen mit den Swing Komponenten (z.B. Klick auf einen Button) laufen daher in einem einzigen Thread ab, dem Event Dispatcher Thread. Daher sollte Code, der durch ein Event ausgelöst wird, nicht lange laufen, sonst wird die GUI träge bzw. scheint gar nicht mehr zu reagieren, da solange keine andere Interaktion (z.B. ein anderer Knopf wird gedrückt) möglich ist. Wenn ein Event eine längere Verarbeitung notwendig macht, sollte man einen Worker Thread starten. Wenn man an der GUI Veränderungen durchführen möchte, sollte man das immer aus dem Event Dispatcher Thread heraus durchführen, weil die Änderungen dann sofort sichtbar werden.

Worker Threads

Hier sollten länger laufenden Arbeitsschritte ablaufen. Seit Java 1.6 gibt es die elegante Möglichkeit lang laufenden Threads aus dem Even Dispatcher Thread über SwingWorker zu starten.

Beispiel:

Eine Klasse mit 3 Buttons und einer ProgressBar:

Swing long running tasks
public class MyGUIWithLongRunningTask extends JFrame
{
private static final Integer NR_OF_ENTRIES=30000;

protected JButton buttonShuffle;
protected JButton buttonSort;
protected JButton buttonQuit;
protected JProgressBar progressBar;

List<Integer> unsortedListData;
List<Integer> sortedListData;

private void initGUIElements()
{
// Button, action behind the button will block GUI
buttonShuffle=new JButton("Shuffle");
buttonShuffle.addActionListener(new ShuffleIt(NR_OF_ENTRIES));

// Button, action behind the button will not block GUI
buttonSort=new JButton("Sort");
buttonSort.setVisible(false);
buttonSort.addActionListener(new SortIt());

// Button, immediate action
buttonQuit=new JButton("Quit");
buttonQuit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}});

// progress bar
progressBar=new JProgressBar();
progressBar.setVisible(false);
}
...

Durch einen Klick auf den Shuffle Button wird ein Event ausgelöst und die Methode actionPerformed in der folgenden Klasse ausgeführt. Der gesamte Code läuft wie der Rest der GUI im Event Dispatch Thread, die GUI "hängt" also, bis der Code abgearbeitet ist:

       /**
* Inner class to created a random unsorted List of Integers.
* This class is added as an ActionListener to the Shuffle button
*/
private class ShuffleIt implements ActionListener
{
private int mMaxNrOfEntries;

public ShuffleIt(int pMaxNrOfEntries)
{
this.mMaxNrOfEntries=pMaxNrOfEntries;
}

@Override
public void actionPerformed(ActionEvent e)
{
List<Integer> data=new ArrayList<Integer>();
Random rand=new Random();
for(int i=0; i<mMaxNrOfEntries; i++)
{
int r=rand.nextInt();
data.add(r);
}
unsortedListData=data;

// now offer a sort button
buttonSort.setVisible(true);
pack();
}
};


Durch einen Klick auf den Sort Knopf wird ebenfalls ein Event ausgelöst und ebenfalls eine actionPerformed Methode ausgeführt. Dort wird allerdings eine SwingWorker Klasse gestartet, die im Hintergrund in einem Worker Thread abläuft.

 private class SortIt implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
if(unsortedListData!=null)
{
SortItWorker s=new SortItWorker(new ArrayList<Integer>(unsortedListData));
progressBar.setValue(0);
progressBar.setVisible(true);
pack();
s.execute();
}
}
}

Durch den Aufruf von execute() wird die Methode doInBackground() in einem Worker Thread gestartet. Die GUI bleibt für den Benutzer weiterhin benutzbar. Sobald doInBackground() fertig ist, wird die Methode done() aufgefrufen, und zwar wieder im Event Dispatch Thread. Aber auch schon während der Abarbeitung kann mit dem parallel laufenden Worker Thread kommuniziert werden:
  • Mit setProgress() kann der Worker Thread seinen Fortschritt setzen. Über die propertyChange() Methode wird der Event Dispatch Thread bei jeder Änderung des Fortschritts aufgerufen und kann den Fortschritt auslesen und z.B. einen Fortschrittsbalken anzeigen.
  • Über publish() kann der Worker Thread Zwischenergebnisse veröffentlichen, die alle gesammelt und gespeichert werden. Daraufhin wird die Methode process() innerhalb des Event Dispatch Threads aufgerufen. Dort kann dann z.B. das aktuellste Zwischenergebniss dargestellt werden.
  • Solange der SwingWorker ab und zu isCancelled() ausliest, und abbricht sobald das true ist, kann der Event Dispatcher Thread über cancel() den Prozess abbrechen.
  • Der Event Dispatcher Thread kann auch jederzeit mit get() auf das Ergebnis warten. Dann blockiert die GUI aber wieder, bis das Ergebnis geliefert wird. Alternativ kann mit get(5, TimeUnit.SECONDS); auch eine bestimmte Zeit gewartet werden, danach läuft der Event Dispatcher Thread dann wieder parallel zum Worker Thread.

Achtung: Jedes Objekt der SwingWorker Klasse kann nur einmal ablaufen, danach muss das Objekt verworfen werden und ein neues erzeugt werden.

       /**
* This is another inner class which will sort an unsorted List.
* This class runs in the background and does not block the GUI
*
*/
private class SortItWorker extends SwingWorker<List<Integer>, List<Integer> > implements PropertyChangeListener
{
private List<Integer> toBeSorted;

public SortItWorker()
{
super();
addPropertyChangeListener(this);
}

@Override
protected List<Integer> doInBackground() throws Exception
{
this.setProgress(0);

// simple bubble sort
for(int i=0; i<toBeSorted.size(); i++)
{
for(int j=i+1; j<toBeSorted.size(); j++)
{
if(toBeSorted.get(i)>toBeSorted.get(j))
{
Integer tmp=toBeSorted.get(j);
toBeSorted.set(j, toBeSorted.get(i));
toBeSorted.set(i, tmp);
}
}

// set the current progress in percent
int lCurrentProgress=Math.min(100, ( (int) ( i * 100 / (toBeSorted.size()-1)) ));
this.setProgress(lCurrentProgress);

// publish what is already finished so the GUI can already display something
List<Integer> alreadySortedSubList=toBeSorted.subList(0, i);
publish(alreadySortedSubList);

// allow others to cancel us
if(isCancelled())
{
break;
}
}
return toBeSorted;
}

/**
* This method is called within the Event Dispatch Thread when this SwingWorker is finished
* @see javax.swing.SwingWorker#done()
*/
@Override
public void done()
{
progressBar.setVisible(false);
pack();
try
{
sortedListData=get();
} catch (Exception e)
{
e.printStackTrace();
sortedListData=null;
}

}

/**
* This class is called within the Event Dispatch Thread when a new result was published
* @see javax.swing.SwingWorker#process(java.util.List)
*/
@Override
protected void process(List<List<Integer>> soFarProcessed)
{
if(soFarProcessed!=null && soFarProcessed.size()>0)
{
sortedListData=soFarProcessed.get(soFarProcessed.size()-1);
}
}

@Override
public void propertyChange(PropertyChangeEvent evt)
{
if ("progress" == evt.getPropertyName())
{
int lNewProgress = (Integer) evt.getNewValue();
progressBar.setValue(lNewProgress);
}
}

}

...

Java in Internetseiten

Java Applet

Java wird beim Client ausgeführt
Sun Java Applet Tutorial
import javax.swing.JApplet;
import java.awt.Graphics;

public class HelloWorld extends JApplet
{
private static final long serialVersionUID = 1L;

public void init() {};

public void start() {};
public void stop() {};

public void paint(Graphics g)
{
g.drawRect(20, 20, getSize().width - 40, getSize().height - 40);
g.drawString("Hello world!", 40, 40);
}

public void destroy() {};

}
Wird so in HTML eingebettet
<applet width=300 height=300 code="HelloWorld.class"> </applet>

JavaServer Pages und Servlets

Java wird auf dem Server ausgeführt
JavaServer Pages und Servlets

Verteilte Programmierung mit RMI und WebServices

Verteilte Programmierung mit RMI und WebServices
07-08-2011 18.37

Bound Properties / PropertyChangeListener

Bound Properties
Man möchte Code ausführen, wann immer sich in einer anderen Klasse (einer Bean) ein bestimmtes Attribut ändert. Dazu nimmt man sich die ganz normale Bean Klasse mit ihren Settern und Gettern. Die Klasse wird um ein PropertyChangeSupport Attribut ergänzt und in allen betroffenen Settern wird über diese Attribut in jedem relevanten Setter ein firePropertyChange ausgeführt. Außerdem wird noch die Möglichkeit geschaffen, dass man von außen einen PropertyChangeListener in dem PropertyChangeSupport Attribut registrieren kann.

public class MyBean
{
private Long id;
private String name;
private Integer age;

private final PropertyChangeSupport myPropertyChangeSupport = new PropertyChangeSupport( this );

public void addPropertyChangeListener( PropertyChangeListener listener )
{
this.myPropertyChangeSupport.addPropertyChangeListener( listener );
}

public void removePropertyChangeListener( PropertyChangeListener listener )
{
this.myPropertyChangeSupport.removePropertyChangeListener( listener );
}

public Long getId()
{
return id;
}
public void setId(Long pId)
{
this.id = pId;
}

public String getName()
{
return name;
}
public void setName(String pName)
{
String lOldName=this.name;
this.name = pName;
this.myPropertyChangeSupport.firePropertyChange("name", lOldName, this.name);
}

public Integer getAge()
{
return age;
}
public void setAge(Integer pAge)
{
Integer lOldAge=this.age;
this.age = pAge;
this.myPropertyChangeSupport.firePropertyChange("age", lOldAge, this.age);
}
}

So sieht z.B. ein PropertyChangeListener aus, der nur ermittelt, wie das Attribut hieß, dass geändert wurde.

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class AttributeStalker implements PropertyChangeListener
{
@Override
public void propertyChange(PropertyChangeEvent evt)
{
String attributeName=evt.getPropertyName();
...
}
}

Und so benutzt man die Bean mit dem PropertyChangeListener

MyBean b=new MyBean();
AttributeStalker s=new AttributeStalker();
b.addPropertyChangeListener(s);
b.setId(5l);
b.setName("Foo");


13-07-2011 21.25

junit


Man erzeugt eine neue Klasse, in der mit @Test markierte Methoden einzelne Tests ausführen

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class MyCTestClass
{
@Before
public void Myinit()
{
...
}

@Test
public void TestAddMethod()
{
assertTrue(a.add(ZERO).equals(a));
assertTrue(a.add(b).equals(b.add(a)));
}

@Test
public void isDivOK()
{
assertTrue(a.div(ONE).equals(a));
assertTrue(a.mult(b).div(b).equals(a));
}

@Test(expected=NullPointerException.class)
public void nullParameter()
{
a.add(null);
}

}

Die Tests können entweder über die Kommandozeile ausgeführt werden
java org.junit.runner.JUnitCore MyCTestClass
oder aber auch direkt über die IDE, wie hier in Eclipse
Eclipse JUnit
18-03-2010 01.36

Log4j


Komponenten

In Log4j gibt es 3 (4) Komponenten
  • Loggers
  • Layouts
  • Appenders
  • (und aus Gründen der Rückwärtskompatibilität noch Category)


Loggers

Der Root Logger hat keinen Namen und existiert implizit. Man erhält ihn über die statische Methode
Logger.getRootLooger();

Alle anderen Logger werden über
Logger.getLogger(name);
bezogen.

Logger sind hierarchisch über ihren Namen aufgebaut. Der Logger foo ist der Vater von foo.bar, welcher der Vater von foo.bar.blub ist, usw. Das kann z.B. so benutzt werden, dass man als Namen für den Logger den vollständigen Klassennamen de.foo.class1 oder nur den Paketnamen de.foo benutzt.

Logger ohne Vater haben automatisch den Root Logger als Vater.

Levels

Alle Logger haben einen Log Level. Es gibt folgende Level
  • FATAL
    • ERROR
      • WARN
        • INFO
          • DEBUG

Wird für einen Logger kein Level konfiguriert, erhält er den Level des nächsten übergeordneten Vorgängers, der einen Level gesetzt hat. Der Root Logger hat immer ein Log Level gesetzt.

Geloggt wird im Java Code so:
Logger logger=...;
logger.debug("Hello World");
logger.info("Hello World");
logger.warn("Hello World");
logger.error("Hello World");
logger.fatal("Hello World");

Die Meldung erscheint aber nur, wenn der Log Level mindestens auf dem Level steht, welches der Log Methode entspricht. Also logger.info() wirkt nur, wenn logger mindestens auf DEBUG oder INFO steht.
Baut man den Text zum Loggen erst aufwendig zusammen, lohnt es sich oft, erst zu prüfen, ob dieses Level überhaupt geloggt werden soll (ansonsten lohnt sich dieser extra Test aber nicht):

if( logger.isDebugEnabled())
{
String text="foo bar";
logger.debug("a"+"b"+r*s/t+"c"+text);
}

Appenders

Jedem Logger kann ein oder mehrere Appenders zugewiesen werden. Dorthin werden die Log Meldungen geschrieben. Appenders können z.B. Dateien (FileAppender, DailyRollingFileAppender), die Konsole, syslog, E-Mail (SMTPAppender) oder sogar eine Datenbanktabelle (JDBCAppender) sein.
Der Log Text erscheint in allen Appenders des benutzten Loggers plus in allen Appenders aller Vorgänger inklusive dem Root Logger. Möchte man das nicht, kann man das sogenannte Additivity Flag setzen:
log4j.additivity.MyLogger=false

Layout

Ausgaben können formatiert werden. Interessant sind SimpleLayout, PatternLayout, HTMLLayout

Konfiguration

Wenn die Konfiguration über eine Properties Datei durchgeführt wird, gibt man diese Datei entweder über
-Dlog4j.configuration=
beim Starten der VM an, oder man nennt die Datei log4j.properties, Log4j durchsucht alle Ordner im Klassenpfad nach einer solchen Datei.

Beispiel
log4j.appender.MyAppender1=org.apache.log4j.ConsoleAppender

log4j.appender.MyAppender2=org.apache.log4j.RollingFileAppender
log4j.appender.MyAppender2.file=logfile.log
log4j.appender.MyAppender2.MaxFileSize=10MB
log4j.appender.MyAppender2.MaxBackupIndex=1
log4j.appender.MyAppender2.layout=org.apache.log4j.PatternLayout
log4j.appender.MyAppender2.layout.ConversionPattern=%-5p [%t] (%F:%L) - %m%n
# send logs via mail
#log4j.appender.MyAppender2.layout.ConversionPattern=ROOT %d{ABSOLUTE} [%-30.30C{1}] [%-17t] %-5p %x - %m%n
log4j.appender.MyAppender3 = org.apache.log4j.net.SMTPAppender
log4j.appender.MyAppender3.To = foo@example.com <mailto:foo@example.com>
log4j.appender.MyAppender3.From = bar@example.com
log4j.appender.MyAppender3.SMTPHost <mailto:bar@example.comlog4j.appender.MyAppender3.SMTPHost> = mail.example.com
log4j.appender.MyAppender3.Subject = New Mail from your logger
log4j.appender.MyAppender3.LocationInfo = false
log4j.appender.MyAppender3.layout = org.apache.log4j.PatternLayout
log4j.appender.MyAppender3.layout.ConversionPattern=%m%n
log4j.appender.MyAppender3.EvaluatorClass = foo.bar.MailEventTriggerEvaluatorClass
log4j.rootLogger = DEBUG, MyAppender1

log4j.logger.MyLogger1 = ERROR, MyAppender2
log4j.additivity.MyLogger1=false

log4j.logger.MyLogger1.Foo = DEBUG, MyAppender2, MyAppender3

Achtung, der SQL Appender von log4j hat ein Limit an Zeilen, die geloggt werden. Sonst schneidet er die älteren Zeilen einfach ab

# max nr of log messages (default seems to be 512)
log4j.appender.BusinessMailAppender.BufferSize=2048

Alternative zu log4j: Java Logging


Beispiel

private Logger mLogger;

...

private Logger getLogger()
{
if(mLogger==null)
{
Level minLevel=Level.FINE;
mLogger=Logger.getLogger(this.getClass().toString());
mLogger.setLevel(minLevel);
Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(minLevel);
mLogger.addHandler(consoleHandler);
}
return mLogger;
}

...

getLogger().warning("Oh oh!");
31-07-2011 00.35

ANT

Das Apache ANT Werkzeug. Vergleichbar mit Makefiles, Schwerpunkt liegt aber nicht auf Abhängigkeiten (das kann Java selbst) sondern auf der Bereitstellung plattformunabhängiger Befehle (z.B. zum Kopieren von Dateien).

Links

Kleines ANT Beispielprojekt

<project name="MyProject" default="compile" basedir=".">

<!-- set global properties for this build -->
<property name="src" location="src" />
<property name="build" location="build" />
<property name="dist" location="dist" />
<property name="mainclass" value="de.tgunkel.Test.Foo" />
<property name="distjarname" value="MyProject" />

<!-- path for compiling the code -->
<path id="compilepath">
<fileset file="../../src/lib/foo_1.5.0.jar" />
<fileset dir="../../src/lib/">
<include name="**/*.jar"/>
</fileset>
</path>

<!-- path for running the code -->
<path id="runpath">
<path refid="compilepath"/>
<pathelement location="build"/>
<pathelement location="etc"/>
<fileset file="../../lib/otherlib/foo-2.0.0.jar" />
</path>

<!-- clean -->
<target name="clean" description="clean">
<!-- <delete dir="${build}" /> -->
<delete includeemptydirs="true">
<fileset dir="${build}" includes="**/*"/>
</delete>
</target>

<!-- Some initial stuff -->
<target name="init" description="init">
<!-- Create the time stamp -->
<tstamp/>
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
</target>

<!-- compile it -->
<target name="compile" description="compile the source" depends="init">
<javac srcdir="${src}" destdir="${build}">
<classpath refid="runpath">
</classpath>
</javac>
</target>

<!-- run the compiled code -->
<target name="run" depends="compile" description="Run the program" >
<java classname =3D "${mainclass}">
<arg value="foo" />
<arg value="bar" />
<arg value="42" />
<classpath refid="runpath" />
</java>
</target>

<!-- create a jar -->
<target name="jar" description="makes a jar" depends="compile">
<jar basedir="${build}" compress="true" jarfile="${dist}/${distjarname}">
<manifest>
<attribute name="Built-By" value="Thorsten Gunkel" />
<attribute name="Main-Class" value="${mainclass}" />
<!-- You need the whole run time path here for an executable jar
<attribute name="Class-Path" value="../../../src/lib/foo_1.0.0.jar" />
-->
</manifest>
</jar>
</target>

</project>

Variablen mit Werten aus anderen Dateien füllen

<property file="my-extra-variables.properties"/>
<property name="JAVA_HOME" value="${YOUR_JAVA_HOME}" />

Warnungen des Compilers wie Fehler behandeln lassen

Wenn man erreichen möchte, dass sich kein Code eingebaut wird, der nur mit Warnungen übersetzt wird, kann man diese nützlich Option setzen:
-Xlint -Werror
Bzw. über ant

 %lt;javac ....>
...
%lt;compilerarg value="-Xlint" />
%lt;compilerarg value="-Werror" />
%lt;/javac>

Jede Warnung wird dann wie ein Fehler behandelt und führt zum Abbruch des Compilers. So werden Warnungen sehr früh bemerkt.

Textersetzung

So kann man mit ANT in Dateien Textersetzung durchführen
<project basedir=".">
<target name="build" description="Replace some strings">

<replace dir=".">
<include name="myfiles/**" />
<replacefilter token="__FOO__" value="BAR" />
<replacefilter token="__43__" value="42" />
</replace>

</target>
</project>

Java Debug

<jvmarg value="-Xdebug"  />
<jvmarg value="-Xnoagent" />
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y" />
13-07-2011 21.38

Maven

Maven Buch: Better Build With Maven
Erster Test, geht Maven?

mvn -version

Maven so einstellen, dass es ein Proxy benutzt wird

~/.m2/settings.xml

<settings>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>my.proxy.foo.bar</host>
<port>8080</port>
<!--
<username>your-username</username>
<password>your-password</password>
-->
</proxy>
</proxies>
</settings>

Ein neues Projekt erzeugen
mvn archetype:create   -DgroupId=bar.foo.main -DartifactId=MyFirstMavenApplication
Oder so
mvn archetype:generate -DgroupId=bar.foo.main -DartifactId=MyFirstMavenApplication

Compile
cd MyFirstMavenApplication
mvn compile

Man kann auch nur mal ausprobieren, ob es kompilieren würde
mvn test-compile

So führt man Surefire Tests für das Projekt durch
mvn test

So erstellt man ein Package
mvn package

Clean
mvn clean

Eclipse Konfigurationsdateien erzeugen
mvn eclipse:eclipse

Das m2eclipse Maven Eclipse Plugin
Eine Webseite über das Projekt erzeugen lassen
mvn site

Style Fehler finden (landet in checkstyle-result.xml)
mvn checkstyle:checkstyle

Liste aller verfügbaren Maven Plugins
Wie fügt man Dateien in das erzeugte jar?

Alles was unter
src\main\resources
steht wird 1:1 in das jar übernommen (also z.B. auch jars von Drittanwendungen, die dort hineinkopiert werden).

Für die Tests gilt entsprechend
src\test\resources

Wie erklärt man Abhängigkeiten?
<project>
[...]
<version>1.42</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>foo.bar</groupId>
<artifactId>blub</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>foo.other</groupId>
<artifactId>X</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
</dependencyManagement>
[...]
</project>

Junit kann man so einbauen
<project>
[...]
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
[...]
</project>

Hier kann man Einstellungen festlegen (z.B. Umgebungspezifische Parameter)
<user_home>/.m2/settings.xml
profiles.xml

So kann man das Projekt gleich an den Zielort kopieren lassen (deploy)
<project>
[...]
<distributionManagement>
<repository>
<id>foo</id>
<name>My Foo Repository</name>
<url>scp://foo.example.com/deploy</url>
</repository>
</distributionManagement>
[...]
</project>

Wie fügt man 3rdparty libs hinzu? Entweder die Libs werden bereits auf http://mvnrepository.com gelistet. Dann reicht es, eine entsprechende Abhängigkeit zu benennen
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
Die jars stehen dann automatisch zur Verfügung.

Alternativ kann man auch ein lokales jar referenziere

<dependency>
<groupId>foo</groupId>
<artifactId>blub</artifactId>
<version>1.2.3</version>
<scope>system</scope>
<systemPath>${basedir}/lib/foo-1.2.3.jar</systemPath>
</dependency>

Letzteres wird aber nicht empfohlen.

Wenn man mit Maven solche Fehler bekommt:

generics are not supported in -source 1.3
(use -source 5 or higher to enable generics)
annotations are not supported in -source 1.3
(use -source 5 or higher to enable annotations)
for-each loops are not supported in -source 1.3
(use -source 5 or higher to enable for-each loops)

Kann man so einstellen, welche Version man beim Compilieren benutzen möchte:

<project ...>
...
<dependencies>
...
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

...
</project>
13-08-2011 12.12

Eclipse

So kann man an ein jar das Javadoc anhängen: Das Projekte anklicken, Menü, Project, Properties, Libraries, [jar], aufklappen, javadoc location.

Shortcuts

downcase:
STRG SHIFT y
UPCASE:
STRG SHIFT x

Breakpoints

Breakpoints können nur den aktuellen Thread anhalten, oder gleich die ganze VM. Den Default kann man so festlegen
Preferences -> Java -> Debug -> [ Suspend Execution | Suspend Thread ]
In der Debug View kann man mit dem J! Symbol Brakepoints setzen, die nur bei Exceptions aktiv werden
Eclipse Java Exception Brakepoint

Code formatieren

Preferences -> Java -> Code -> Style -> Formater

Dort New anklicken und ein eigenes anlegen.

Mit
CTR SHIFT F

anwenden lassen

Eclipse stürzt ab

Das Eclipse Error Log liegt im Workspace Ordner und endet auf .log.

Eclipse 3.1.1 und PermGen zu klein? In der eclipse.ini das hier mal mit mehr Speicher probieren
--launcher.XXMaxPermSize 256m

Wenn Eclipse in Dialogen abstürzt, in denen man durch das lokale Dateisystem navigiert (File open...) hilft seltsamerweise der eclipse.exe explizit den Pfad zur Java Installation mitzugeben.
C:\Programme\eclipse\eclipse.exe -vm C:\Programme\Java\jdk1.6.0_24\bin\java.exe

Quellen mit einem JAR verknüpfen

Java Eclipse jar Quellcode verknüpfen

Eclipse Plugin für hprof Dateien (Speicherverbrauch)

Eclipse Memory Analyzer Plugin (MAT)

Eclipse UML Plugin

The ObjectAid UML Explorer for Eclipse UML of Java class

Eclipse @author

Eigentlich setzt Eclipse z.B. bei generierten Kommentare für neue Klassen automatisch eine @author Annoation. Allerdings ermittelt Eclipse dann je nach Systemkonfiguration nicht den richtigen Namen. So kann man das in der eclipse.ini reparieren

-Duser.name=John Doe (JD)
13-08-2011 11.26

Netbeans

build Ordner

Man kann in Netbeans kein vorhandenes Projekt importieren, wenn man es dort bereits einen build Ordner gibt.

Fehlermeldung:
Cannot place the project in a Project Folder that already contains "build" folder.

Workarround:
  • Den vorhanden Ordner build Ordner temporär umbennen
  • Das Projekt normal importieren
  • CTRL 2 drücken, Projekt aufklappen, nbproject, project.properties, build.dir, diesen Wert abändern
  • Temporär umbennaten buidl Ordner wieder build nennen
  • Fertig

JDK

So kann man das JDK in Netbean umstellen:
Rechtsklick auf das Projekt, Libraries (!), Java Platform.
Falls das JDK noch nicht eingerichtet wurde: Manage Platforms (es können nur JDK ausgewählt werden, keine JRE).

Falls das Source Level sich auch ändert (z.B. von 1.4 auf 1.6) geht das so:
Rechtsklick auf das Projekt, Sources, Source / Binary Format.
31-07-2011 00.37

Performancemessungen / Profiler


JRat

JRat
So startet man das zu messende Programm

java -javaagent:shiftone-jrat.jar ...

So kann man sich die Ergebnisse mit dem mitgelieferten Viewer ansehen

java -Xmx256M -jar shiftone-jrat.jar

JRat hatte allerdings Probleme mit Hibernate und Annotations.

JIP

JIP
So startet man das zu messende Programm

java -javaagent:[DIR]\profile.jar ...

Am einfachsten ist es, wenn [DIR] ein absoluter Pfad ist.

Andere Variante

java -javaagent:[DIR]\profile.jar -Dprofile.properties=[DIR2]\profile.properties

Auch hier ist es einfacher, wenn [DIR] und [DIR2] absolute Pfade sind.

Im Paket ist ein Beispiel für eine profile.properties enthalten. Damit man sich die Ergebnisse visualisieren lassen kann, muss man in der properties mindestens
output=both
setzen. Wenn man in der properties den Eintrag
file
auf einen Ordner zeigen lässt, dann wird jeder neue Lauf in eine neue Datei geschrieben.
Ebenfalls nützlich ist der Eintrag
output-method-signatures=yes

So kann man sich die Ergebnisse schließlich visualisieren lassen

java -jar jipViewer.jar [DIR3]/profile.xml
Wobei hier [DIR3] der Ordner ist, in den JIP die Messwerte Schreiben sollte.
05-08-2010 20.48
Powered by PHP Created with Xemacs Valid XHTML 1.0! Valid CSS!