Delegates vs. Anonyme Klassen vs. Blöcke

Posted September 14, 2007

Im Moment wird heftig diskutiert, ob Properties und die sogenannte Closures in Java SE 7 aufgenommen werden sollen. Befürworter meinen, dass dieses Konzept in fast allen Scriptsprachen und auch in C# vorkommt und Java hinterherhinkt. Gegner meinen, dass Java glücklicherweise eher konservativ ist, wenn es um neue Programmier-Trends geht, was die Sprache einfach hält und schließlich hat man bisher ja auch keine Closures gebraucht.

Ein typischer Smalltalk-Programmierer würde für eine Suche in einer Collection aufgrund der "Blöcke" nicht mehr als drei Zeilen brauchen:

| s t |
s := (OrderedCollection newFrom: #('Hallo' 'du' 'wie' 'geht' 'es' 'dir')).
t := s select: [:each | each beginsWith: 'ge'].
Transcript show: (t at: 1).

Bei C# bedient man sich in solchen Fällen der Delegates. Das sind Typdefintionen für Methoden, sodass diese dann als Parameter oder als Variable gehalten und auch aufgerufen werden können. Damit ist eine event-getriebene Programmierung besondern einfach und kurz. In diesem Fall muss man also erst sein generisches TestCondition-Delegate definieren und dann erweitert man seine Kollektion um einen Suchaufruf und kann dann eine Methoden-Implementierung als Parameter übergeben.

public delegate bool TestCondition<E>(E entity);
 
class ListWithFinding<E> : List<E> {
    public E Find(TestCondition<E> test) {
        foreach(E e in this) {
            if (test(e)) {
                return e;
            }
        }
        return default(E);
    }
}
 
public bool TestString(string entity) {
    return entity.StartsWith("ge");
}
 
public void Main() {
    ListWithFinding<string> l = new ListWithFinding<string>();
    l.Add("Hallo");  l.Add("du");  l.Add("wie");
    l.Add("geht");    l.Add("es");  l.Add("dir");
    string res = l.Find(TestString);
    Console.WriteLine(res);
}

In Java gibt es weder Blöcle noch Delegates. Daher gibt es eine Nachfrage nach einen entsprechenden Konzept. Dennoch sind die vorgeschlagenen Closures gar nicht notwendig, da Java ein anderes Konzept, dass es in C# und Smalltalk nicht gibt: Anonyme Klassen. Wenn man nun eine Suche braucht, dann kann man diese Methode als Interface definieren und dann seine Collection um eine Suche bereichern. Im Code selbst kann man dann dieser Suche seinen Test als anonyme Klasse, die das TestInterface implementiert, übergeben. Abgesehen von den etwas überflüssigen und unnötig aufwändigen Code, ist also in Java alles möglich, was man auch mit Blöcken und Delegates erreichen kann.

interface TestCondition<T> {
    public boolean test(T type);
}
 
class ArrayListWithFinding<E> extends ArrayList<E> {
    public E find(TestCondition<E> tester) {
        for (E entity : this) {
            if (tester.test(entity)) {
                return entity;
            }
        }
        return null;
    }
}
 
public static void main(String[] args) {
    ArrayListWithFinding<String> l = new ArrayListWithFinding<String>();
    l.add("Hallo");   l.add("du");  l.add("wie");
    l.add("geht");    l.add("es");  l.add("dir");
    String res = l.find(new TestCondition<String>() {
        public boolean test(String type) {
            return type.startsWith("ge");
        }
    });
    System.out.println(res);
}

(originally posted on 2007-09-15)