29
Aug
14

Casts mit zusätzlichen Bounds in Java 8

Immer wieder beschert mir Java wundervolle WTF-Momente, so auch heute. Eine Syntaxerweiterung in Java 8, die komplett an mir vorbeigegangen ist, sind Casts mit zusätzlichen Bounds:

LinkedList<String> list = new LinkedList<>();
List<String> list1 = (List & Queue) list; //OK
List<String> list2 = (List & RandomAccess) list; //ClassCastException

Die JLS schreibt dazu recht lakonisch :

If the cast operator contains a list of types – that is, a ReferenceType followed by one or more AdditionalBound terms – then all of the following must be true, or a compile-time error occurs.

Stellt sich die Frage ist, wozu das Ganze gut sein soll. Der einzige sinnvolle Anwendungsfall, den ich gefunden habe, ist die Spezifizierung zusätzlicher Interfaces bei Lambdas:

Runnable r = (Runnable & Serializable) () -> System.out.println("Serializable!");

Lambdas haben ja eigentlich keinen Typ, sie sind ein wenig wie Schrödingers Katze: Erst wenn man etwas mit ihnen anstellt – etwa die Zuweisung zu einer Variablen – entscheidet sich, was ihr Typ ist. Durch den vorgelagerten Cast wird diese Typbestimmung vorgezogen, so dass das Objekt r nicht nur Runnable, sondern auch Serializable ist, und später auch problemlos serialisiert werden kann.

Wie findet ihr dieses etwas obskure Feature? Seht ihr noch andere sinnvolle Anwendungsmöglichkeiten?

02
Jun
14

Pattern-Matching in Java 8

In Scala ist Pattern-Matching ein beliebtes Feature mit fast unbegrenzten Anwendungsmöglichkeiten. Nicht umsonst wird es oft als “switch auf Steroiden” bezeichnet. Im Rahmen eines kleinen Projekts habe ich überlegt, ob man das nicht auch in Java 8 nachbauen kann.

Man kann, mit einigen Einschränkungen. Hier einmal ein kleines Anwendungsbeispiel:

String string = ...
String s = match(string,
   StartsWith("foo", () -> "found foo..."),
   EndsWith("bar", () -> "found ...bar"),
   Contains("baz", () -> "found ...baz..."),
   EqualsIgnoreCase("blubb", () -> "found blubb"),
   Default(() -> "nix gefunden")
);
System.out.println(s);

Wie funktioniert das? Zuerst braucht man für die einzelnen Fälle ein Interface:

import java.util.Optional;

public interface Case<T,R> {
    Optional<R> accept(T value);
}

Es ist im Prinzip eine Art Funktion, die für einem Ausgangswert ein Resultat liefert, allerdings in einem Optional. Wir haben also eine Art Funktion, die eventuell etwas zurückliefert – genau dann, wenn der zu überprüfende Wert “passt”. Hier eine der verwendeten Case-Implementierungen (man verzeihe mir bitte die an Scala angelehnte Großschreibung der Methodennamen):

public static <R> Case<String, R> StartsWith(String prefix, Supplier<R> supplier) {
    return t -> t.startsWith(prefix)
            ? Optional.of(supplier.get())
            : Optional.<R>empty();
}

Wir liefern also den durch den Supplier vorgegebenen Wert (in ein Optional verpackt) zurück, aber nur, wenn der zu testende String den richtigen Präfix hat.

Die match-Methode ist auch recht unspektakulär (MatchException ist eine gewöhnliche Laufzeit-Exception):

@SafeVarargs
public static <T,R> R match(T value, Case<T,R> ... cases) throws MatchException {
    for(Case<T,R> c : cases) {
        Optional<R> result = c.accept(value);
        if (result.isPresent()) {
            return result.get();
        }
    }
    throw new MatchException();
}

Interessanterweise kann dieser Mechanismus auch die Arbeit mit Optional vereinfachen. Wenn wir einmal so tun, als hätte Optional wie in Scala die Unterklassen Some (die einen Wert enthält) und None (die “leer” ist), könnte uns das zu dieser Verwendung anregen:

Optional<Integer> opt = ...
String s = match(opt,
        None(() -> "leer"),
        Some(42, () -> "die Antwort!"),
        SomeIf(a -> "gerade", a -> a % 2 == 0),
        Default(() -> "nix gefunden")
);

Selbst “geschachteltes” Pattern-Matching ist möglich:

Optional<Optional<Integer>> opt = ...
String s = match(opt,
        None(() -> "leer"),
        Some(None(() -> "leer eingetütet")),
        Some(SomeIf(a -> "gerade", a -> a % 2 == 0)),
        Default(() -> "nix gefunden")
);

Hier die verwendeten Case-Implementierungen:

import static java.util.Optional.*;
...

public static <T,R> Case<Optional<T>,R> None(Supplier<? extends R> supplier) {
    return t -> t.isPresent()
            ? Optional.<R>empty()
            : of(supplier.get());
}

public static <T,R> Case<Optional<T>,R> Some(T value, Supplier<? extends R> supplier) {
    return t -> t.isPresent() && t.get().equals(value)
            ? of(supplier.get())
             : Optional.<R>empty();
}

public static <T,R> Case<Optional<T>,R> Some(Case<T,R> caseT) {
    return t -> t.isPresent()
            ? caseT.accept(t.get())
            : Optional.<R>empty();
}

public static <T,R> Case<Optional<T>,R> Some(Function<? super T, ? extends R> fn) {
    return t -> t.isPresent()
            ? of(fn.apply(t.get()))
            : Optional.<R>empty();
}

public static <T,R> Case<Optional<T>,R> SomeIf(Function<? super T, ? extends R> fn, Predicate<T> predicate) {
    return t -> t.isPresent() && predicate.test(t.get())
            ? of(fn.apply(t.get()))
            : Optional.<R>empty();
}

public static <T,R> Case<T,R> Default(Supplier<R> supplier) {
    return value -> of(supplier.get());
}

Ich will nicht verhehlen, dass wir hier haarscharf an den Grenzen von Javas Typ-Inferenz operieren, und auch leicht Eindeutigkeitsprobleme bei gleichnamigen statischen Methoden mit Lambda-Argumenten auftreten können. Ob diese kleine DSL wirklich “brauchbar” ist, muss sich erst noch zeigen. Spaß macht es auf jeden Fall.

07
Mai
14

Typsicheres Builder-Pattern mit Java

Der folgende Code ist eine ziemlich direkte Übersetzung des typsicheren Builder-Patterns aus Scala nach Java. Es gibt mehrere Versionen, aber mir gefällt die Variante von Daniel Sobral am besten, weil damit auch bei der “Verkabelung” im Builder weniger Fehler möglich sind. Etwas kürzer ist die ursprüngliche Version von Rafael Ferreira, aber dort ist die Zuordnung von Typparametern zu den Werten “willkürlich”, so dass man beim Builder-Schreiben eher etwas falsch machen kann.

Zuerst zu unserer zu bauenden Klasse und einem kleinen Anwendungsbeispiel:

public class Person {

  private String firstName;
  private String lastName;
  private int age;

  public Person(String firstName, String lastName, int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }

  public String getFirstName() { return firstName; }

  public String getLastName() { return lastName; }

  public int getAge() { return age; }

  @Override
  public String toString() {
    return "Person{" +
      "firstName='" + firstName + '\'' +
      ", lastName='" + lastName + '\'' +
      ", age=" + age +'}';
  }
}

...

Person person = build(NEW.withLastName("Mustermann").withAge(62).withFirstName("Heinz"));

//das compiliert *nicht*
Person person = build(NEW.withLastName("Mustermann").withAge(62));

Zentral für Daniel Sobrals Idee ist ein Wrapper-Typ mit zwei Ausprägungen (“da” und “nicht da”) für die zu sammelnden Werte. Leider hat Optional in Java 8 keine Unterklassen wie Option in Scala, deshalb brauchen wir unsere eigene kleine Hierarchie. Und dann können wir auch gleich andere Namen verwenden, die unserem Zweck eher entsprechen:

public interface Value<T> {}

public final class Without<T> implements Value<T> {
  private final static Without<?> WITHOUT = new Without<>();

  private Without(){}

  @SuppressWarnings("unchecked") 
  public static <T> Without<T> without() { 
    return (Without<T>) WITHOUT; 
  }
}

public final class With<T> implements Value<T> {
  private final T t;

  public With(T t) { this.t = t; }

  public T get() { return t; }
}

Man könnte die Without-Klasse auch hübscher (also ohne Cast) schreiben, aber mit meiner Variante kommt man mit einem einzigen Objekt aus. Nun zur eigentlichen Magie, dem Builder. Ich bitte zu beachten, dass die Klasse mit ihrem Generic-Verhau zwar ziemlich länglich aussieht, der Nutzer davon aber nichts mitbekommt (siehe Anwendungsbeispiel oben).


import static builder.Without.without;

public class PersonBuilder<FirstName extends Value<String>,
          LastName extends Value<String>,
          Age extends Value<Integer>> {

  public static final PersonBuilder<Without<String>, Without<String>, Without<Integer>> NEW =
    new PersonBuilder<Without<String>, Without<String>, Without<Integer>>(without(), without(), without());

  private FirstName firstName;
  private LastName lastName;
  private Age age;

  private PersonBuilder(FirstName firstName, LastName lastName, Age age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }

  public PersonBuilder<With<String>, LastName, Age> withFirstName(String firstName) {
    return new PersonBuilder<>(new With<>(firstName), lastName, age);
  }

  public PersonBuilder<FirstName, With<String>, Age> withLastName(String lastName) {
    return new PersonBuilder<>(firstName, new With<>(lastName), age);
  }

  public PersonBuilder<FirstName, LastName, With<Integer>> withAge(int age) {
    return new PersonBuilder<>(firstName, lastName, new With<>(Integer.valueOf(age)));
  }

  public static Person build(PersonBuilder<With<String>, With<String>, With<Integer>> builder) {
    return new Person(builder.firstName.get(), builder.lastName.get(), builder.age.get());
  }
}

Das Prinzip ist trotz der Generic-Orgie recht einfach zu verstehen: Ausgehend von einem Builder mit lauter Withouts werden letztere schrittweise durch With-Typparameter mit den zugehörigen Werten ersetzt. Und nur ein Builder mit lauter With-Typparametern kann verwendet werden, um am Ende eine Person zu erzeugen (deshalb muss das auch eine statische Methode statt wie üblich eine Instanzmethode sein). Man sieht in der build-Methode, wie die Generics (im Gegensatz zu Rafael Ferreiras Version) wirklich mit den internen Werten gekoppelt sind: Nur mit With als Typparametern sind die get-Methoden verfügbar.

Natürlich erscheint der vorgestellte Code erst einmal ziemlich umfangreich. Dabei sollte man aber berücksichtigen, dass der Unterschied zu einem “normalen” Builder ohne Compilezeit-Test von erforderlichen Argumenten nicht besonders groß ist: Da die Value-Hierarchie wiederverwendet werden kann, kommen im Prinzip nur die Generics im Builder hinzu. Ich denke, wenn man sich sowieso schon dazu entschieden hat, einen Builder zu verwenden, ist es naheliegend, gleich diese Version zu verwenden, wenn es in der zu erzeugenden Klasse “Pflichtfelder” gibt.

19
Apr
14

zipWith in Java 8

Heute einmal ein ziemlich einfaches Beispiel, wie Lambdas das Leben in Java 8 leichter machen. In Haskell und Scala gibt es die Funktione zipWith, mit der zwei Datenstrukturen wie Listen durch elementweise Verknüfung zu einer neuen “zusammengeklebt” werden. Dabei muss man aufpassen: Ist eine der Ausgangsstrukturen länger als die andere, werden die “überflüssigen” Elemente einfach ignoriert. In Java bietet sich so eine Funktion an mindestens zwei Stellen an: Bei Iterables und bei den neuen Streams. Da ich mich mit letzteren (noch) nicht so gut auskenne, will ich heute den einfacheren ersten Fall behandeln.

Ein besonders nützlicher Anwendungsfall für zipWith ist, wenn man mit der erweiterten for-Schleife zwei Collections gleichzeitig durchgehen will – vorher musste man meist auf andere Sprachmittel (z.B. Indexe oder Iteratoren) ausweichen. Wie könnte nun so eine Schleife aussehen?

List<String> strings = Arrays.asList("a","b","c");
List<Integer> ints = Arrays.asList(6,9,14,32);
for(String result : zipWith(strings, ints, (s,i) -> s + i)) {
   System.out.println(result);
}

Das erwartete Ergebnis wären hier die Zeilen “a6″, “b9″ und “c14″. Natürlich wäre auch eine anonyme Klasse an Stelle des Lambda-Ausdrucks möglich gewesen, aber erst durch diesen wird das ganze Konstrukt lesbar. Die Umsetzung ist trivial:

import java.util.function.BiFunction;
...
public static <A,B,C> Iterable<C> zipWith(Iterable<A> iterableA, Iterable<B> iterableB, BiFunction<A,B,C> fn) {
    return () -> new Iterator<C>() {
        private Iterator<A> itA = iterableA.iterator();
        private Iterator<B> itB = iterableB.iterator();

        public boolean hasNext() {
            return itA.hasNext() && itB.hasNext();
        }

        public C next() {
            return fn.apply(itA.next(), itB.next());
        }
    };
}

Wer sich wundert, wo das “new Iterable” geblieben ist: Da das Interface nur eine Methode (nämlich iterator()) besitzt, können wir es durch einen Lambda-Ausdruck ersetzen. Wir brauchen auch die remove-Methode von Iterator nicht zu implementieren, es gibt in Java 8 eine Default-Methode dafür (die eine UnsupportedOperationException wirft). Und als letztes fällt auf, dass wir aus dem Lambda-Ausdruck heraus auf iterableA und iterableB zugreifen konnten, ohne dass wir diese final machen mussten. Da beide Argumente nicht (weder in der Methode noch im Lambda-Ausdruck) verändert werden, sind sie “effektiv final” und benötigen keinen entsprechenden Modifikator.

Das war jetzt etwas leichtere Kost, aber ich hoffe trotzdem ein wenig nützlich.

Wer weiß, wie man das Gleiche mit Streams anstellt, darf seine Lösung hier gerne vorstellen, ich bin gespannt darauf…

[Update]

Für Streams habe ich auf Stackoverflow diesen Schnipsel gefunden:

public static<A, B, C> Stream<C> zip(Stream<? extends A> a,
                                     Stream<? extends B> b,
                                     BiFunction<? super A, ? super B, ? extends C> zipper) {
    Objects.requireNonNull(zipper);
    @SuppressWarnings("unchecked")
    Spliterator<A> aSpliterator = (Spliterator<A>) Objects.requireNonNull(a).spliterator();
    @SuppressWarnings("unchecked")
    Spliterator<B> bSpliterator = (Spliterator<B>) Objects.requireNonNull(b).spliterator();

    // Zipping looses DISTINCT and SORTED characteristics
    int both = aSpliterator.characteristics() & bSpliterator.characteristics() &
            ~(Spliterator.DISTINCT | Spliterator.SORTED);
    int characteristics = both;

    long zipSize = ((characteristics & Spliterator.SIZED) != 0)
            ? Math.min(aSpliterator.getExactSizeIfKnown(), bSpliterator.getExactSizeIfKnown())
            : -1;

    Iterator<A> aIterator = Spliterators.iterator(aSpliterator);
    Iterator<B> bIterator = Spliterators.iterator(bSpliterator);
    Iterator<C> cIterator = new Iterator<C>() {
        @Override
        public boolean hasNext() {
            return aIterator.hasNext() && bIterator.hasNext();
        }

        @Override
        public C next() {
            return zipper.apply(aIterator.next(), bIterator.next());
        }
    };

    Spliterator<C> split = Spliterators.spliterator(cIterator, zipSize, characteristics);
    return (a.isParallel() || b.isParallel())
           ? StreamSupport.stream(split, true)
           : StreamSupport.stream(split, false);
}

Der Original-Code war wohl in der Stream-Implementierung im Lambda-Projekt dabei und ist später unverständlicherweise rausgeflogen.

05
Apr
14

Java 8 und der Y-Kombinator

So schön Lambda-Ausdrücke auch sind, sie haben wenigstens eine Achillesferse: Rekursion. Betrachten wir folgendes Beispiel, das schon seit Java 5 funktionieren würde (ein entsprechendes Function-Interface einmal vorausgesetzt):

...
Function<Integer, Long> fac = new Function<Integer, Long>() {
    @Override
    public Long apply(Integer n) {
        return n == 0 ? 1L : n * apply(n-1);
    }
};

System.out.println(fac.apply(10)); //--> 3628800
...

So weit, so gut und auch so langweilig: Die gute alte Fakultät. Aber wie lässt sich die Definition der anonymen Klasse durch einen Lambda-Ausdruck ersetzen? Hier zwei Beispiele dafür, wie es schon einmal nicht geht:

//Compiler-Fehler: "Variable fac might not have been initialized"
Function<Integer, Long> fac = n -> n == 0 ? 1L : n * fac.apply(n-1);  

//this verweist hier auf die umgebende Klasse, nicht auf den Lambda-Ausdruck selbst
Function<Integer, Long> fac = n -> n == 0 ? 1L : n * this.apply(n-1);  

Wir müssen also tiefer in die Trickkiste greifen. Man bräuchte einen Weg, um die Rekursion sozusagen “explizit” zu machen. Erfreulicherweise ist dieses Problem schon lange gelöst und gehört zur Folklore der funktionalen Sprachen: Man verwendet einen Fixpunkt-Kombinator wie den Y-Kombinator. Ich will an dieser Stelle nicht genauer auf die Funktionsweise eingehen, hauptsächlich um zu verhindern, dass mein Gehirn schmilzt, aber auch, weil man unter Magiern keine Tricks verrät. Deshalb hier eine sehr direkte Umsetzung dieses Konzepts (z.B. ohne weitere Vorkehrungen, um einen Stacküberlauf zu verhindern):

...
public static <X,Y> Function<X,Y> yCombinator(Function<Function<X,Y>,Function<X,Y>> f) {
   return x -> f.apply(yCombinator(f)).apply(x);
}
...

Function<Integer,Long> fac = yCombinator(f -> n -> n == 0 ? 1L : n * f.apply(n-1));

System.out.println(fac.apply(10)); //--> 3628800

Wer mehr dazu erfahren will, sollte sich den Wikibook-Eintrag zu Haskell’s fix-Funktion anschauen. Aber selbst wenn man die “Magie” nicht im Detail nachvollziehen kann oder will, ist es nützlich zu wissen, dass es diesen Trick gibt. Es ist auch ein schönes Beispiel dafür, dass es sich lohnen kann, einmal über den objektorientierten Tellerrand zu schauen, um die tollen neuen Features von Java 8 auch wirklich ausnutzen zu können.

Update

Vielleicht ist folgende Schreibweise mit BiFunction lesbarer:


public static <X,Y> Function<X,Y> yCombinator(BiFunction<X,Function<X,Y>,Y> f) {
    return x -> f.apply(x, yCombinator(f));
}
...
//Anwendung
Function<Integer,Long> fac = yCombinator((n,f) -> n == 0 ? 1L : n * f.apply(n-1));
System.out.println(fac.apply(10));
30
Mär
14

Kann Java abstrakte Typ-Member simulieren?

Scala kennt von Anfang an abstrakte Typ-Member als Alternative zu Generics. Eine Übersicht findet sich hier, und ich habe auch schon damit herumgespielt. Die Kurzfassung: Während generische Klassen ihre Parameter nach außen bekanntmachen, und diese überall mit “durchgeschleift” werden (müssen), werden abstrakte Typ-Member eher als eine Art Implementierungsdetail angesehen und somit sozusagen als “innere Angelegenheit” behandelt.

Und gestern abend dämmerte mir, das Java zumindest prinzipiell etwas Ähnliches erlaubt – und nicht erst seit Java 8. Ich habe keine Ahnung, wie weit diese “Technik” trägt – und ganz sicher ist sie nicht so flexibel wie Scalas Ansatz, der ja “dafür gebaut” worden ist. Aber ich werde gleich zwei Instanzen mit unterschiedlichen Member-Typen in ein und dieselbe Liste packen – ohne Wildcards, Raw-Types, Casts oder Compiler-Warnungen. Sozusagen “innen generisch, außen nicht” – ähnlich wie bei abstrakten Typ-Membern:

public class Outer<T> {

    public class Inner {
        public final T t;

        public Inner(T t) {
            this.t = t;
        }
    }

    public static void main(String[] args) {
        List<Outer.Inner> list = new ArrayList<>();
        list.add(new Outer<String>().new Inner("blubb"));
        list.add(new Outer<Integer>().new Inner(42));
        for(Outer.Inner inner : list) {
            System.out.println(inner.t);
        }
    }
}

Tadaaaaa! Das ist also der Trick: Innere Klassen, die die Generics von ihren äußeren Klassen “benutzen”. Übrigens: Wer solche seltsamen Konstruktoraufrufe wie im Beispielcode noch nicht gesehen hat, ist nicht allein – ich kannte die Syntax auch nicht, bis ich für die “Java Programmer”-Zertifizierung von Oracle lernen musste (daher auch die “Inspiration” für diesen etwas kranken Code). Ich muss erst einmal sehen, in wie weit dieses Konstrukt überhaupt sinnvoll ist, und wie groß die Beschränkung durch die erzwungene “Innerklassigkeit” in der Praxis ist. Falls ihr auch damit herumspielt, würden mich natürlich die Ergebnisse eurer Experimente brennend interessieren.

[Update]
Ich bin darauf hingeweisen worden, dass der “volle” Typ meiner Liste eigentlich etwas wie List<Outer<String>.Inner> sein müsste, ich hier also doch mit Raw-Types arbeite (auch wenn ich keine Warnung sehe). Das macht das Ganze natürlich hinsichtlich der Typsicherheit obsolet, weil damit kein Unterschied zu einer normalen generischen Top-Level-Klasse, die als Raw-Typ verwendet wird, besteht. Schade…

12
Feb
14

Continuations in Java 8

Mit Java 8 in den Startlöchern bietet sich an, mal zum Vergleich ältere Blog-Beiträge zu “lambdafizieren”. Hier ist der aktualisierte Code zu Continuations in Java, der deutlich die Mächtigkeit der Lambdas und Default-Methoden zeigt:

import java.util.function.Function;

public interface Cont<R,A> {

    R runCont(Function<A,R> fn);

    public default <B> Cont<R,B> bind(final Function<A,Cont<R,B>> f){
        return k -> Cont.this.runCont(a -> f.apply(a).runCont(k));
    }

    public static <R,T> Cont<R,T> Return(final T t) {
        return fn -> fn.apply(t);
    }
}

Und das Beispiel:

import java.util.function.BiFunction;

public class PythExample {

    public static <R> BiFunction<Integer, Integer, Cont<R, Integer>> pythCont() {
        return (x, y) -> Cont.<R, Integer>Return(x * x).bind(
                a -> Cont.<R, Integer>Return(y * y).bind(
                        b -> Cont.<R, Integer>Return(a + b)));
    }

    public static void main(String... args) {
        PythExample.<Void>pythCont().apply(3, 4).runCont(
                r -> { System.out.println(r);  return null; });
    }
}

Aus der abstrakten Klasse ist (dank Default-Methode) ein Interface geworden, um die Lambda-Syntax nutzen zu können. Auch das Anwendungsbeispiel wurde deutlich gestrafft. Wie man schön sehen kann, sind die einstigen Monstrositäten jetzt tatsächlich “benutzbar”, auch wenn man sich sicher erst an die Syntax gewöhnen muss.




Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.