Macht die Simulation von Schließungen in Java Sinn?

8

Sprachen, die Closures enthalten, wie z. B. Ruby, ermöglichen elegante Konstrukte, Listen zu transformieren. Angenommen, wir haben eine Klasse

%Vor%

und eine Liste von Begriffen List<QueryTerm> terms , die wir in ihre Werteliste List<String> values transformieren wollen.

In Ruby könnten wir etwas schreiben wie:

%Vor%

Java zwingt uns, die Ergebnisliste zu konstruieren und selbst die Begriffe Kollektion zu durchlaufen (zumindest ist seit Einführung von foreach keine Iterator- oder Indexposition beteiligt):

%Vor%

Apache Commons und Google Sammlungen2 versuchen, Verschlüsse in Java zu emulieren, indem anonyme Klassen verwendet werden:

%Vor%

Das Seltsame ist, dass diese Version mehr Zeilen Code und mehr Zeichen als die Originalversion hat! Ich nehme an, dass es aus diesem Grund schwerer zu verstehen ist. Deshalb habe ich die Idee zurückgewiesen, als ich sie in Apache Commons sah. Nachdem ich es kürzlich in Google Collections gesehen habe, frage ich mich, ob ich etwas vermisse.

Daher meine Frage: Was ist Ihre Meinung zu den obigen Konstrukten? Halten Sie die Collections2.transform() -Version für lesbarer / verständlicher als die Standardversion? Fehle ich etwas komplett?

Mit freundlichen Grüßen, Johannes

    
Joe23 27.11.2009, 12:06
quelle

7 Antworten

4

IMO, sogar mit mehr Zeilen Code, die transform Version, in Ihrem speziellen Beispiel, sieht besser lesbar. Warum? Wegen dieses Wortes transform . Sie wissen sofort, dass eine Transformation in der Sammlung durchgeführt wird, während Sie bei der normalen Version den Codefluss verfolgen müssen, um zu verstehen, was die Absicht ist. Sobald Sie diese neuen Konstrukte in den Griff bekommen, sind sie besser lesbar.

    
bruno conde 27.11.2009, 12:15
quelle
5

Closures, wie sie hier verwendet werden, sind ziemlich genau dasselbe wie das Befehlsmuster . Ich vermute, dass einige der Gründe, warum Befehle nützlich sein können, hier gelten. A Command könnte auch etwas flügge sein als eine Schließung natürlich, da letztere nur auf der Funktionsebene ist. Aber eine wichtige Beobachtung ist, dass dies oft alles ist, was Sie brauchen.

Es gibt ein paar Vorteile, die mir sofort klar sind:

  • Funktioneller Stil, um Ihre Operations Maps leichter zu unserer Denkweise zu erklären, d. h. hier ist meine Funktion, wenden Sie sie bitte auf diese Daten an.
  • Die Verkettung von Transformationen erfolgt durch die transparente Verwendung verschiedener Aufrufe zum Anwenden / Filtern / Transformieren. Sie können sie einfach hintereinander ketten und Sie sehen alle Vorgänge nacheinander in einer Zeile. Sicher, es gibt immer noch eine Menge Standard, aber wenn es richtig gemacht wird, ist es für jeden Java-Programmierer hervorragend lesbar.
  • Inversion der Kontrolle: Angenommen, Sie möchten Ihre Operation über mehrere verschiedene Threads zerlegen. Wenn Sie Ihre eigene Schleife geschrieben haben, stecken Sie fest: Sie müssen sie selbst in mehrere verschiedene Schleifen zerlegen. Dies ist normalerweise hässlich und kompliziert, um Code zu schreiben, und Sie müssen mehrere Runnables erstellen, die Sie an andere Threads weitergeben. Also arbeitest du wirklich nur noch mit Schließungen.

    Einer der JDK7-Vorschläge, der es nicht machen wird, war anscheinend etwas, das genau das alles für Sie tat, wo Sie einfach Ihre Daten einreichen und definieren, welche Filter darauf ausgeführt werden sollen, und Sie lassen es seinen fröhlichen Weg gehen. Sie können den Code herunterladen (Paket extra166y). Alle Ops, die Sie in dem javadoc für dieses Paket sehen können, können eliminiert und durch Closures ersetzt werden . Das ist also ein gutes Beispiel, warum ein bestimmter Ansatz fehlschlägt, weil es keine echten Schließungen gibt, und die "Simulation" von Schließungen macht es nicht mehr ganz unmöglich.

Wirklich, es gibt Unmengen von Problemen, die Sie wirklich leicht lösen können, indem Sie einfach eine einfache Funktion übergeben, die das tut, was Sie mit den Daten machen wollen, und ein Framework den Rest ausfüllen lassen. Sie können dies jetzt mit anonymen Klassen tun, aber richtige Schließungen würden zumindest einen Großteil der Kesselplatte wegschneiden.

Einer der Rahmen, den ich benutzt habe, der etwas wie diesen Ansatz verwendet, um eine Menge des Boilerplate zu entfernen, ist Spring-Jdbc . Hier übergeben Sie dem JdbcTemplate eine einfache Funktion, die Ihre Objekte aus dem ResultSet herausholt und Sie zusammen mit Ihrer Abfrage an template.query() übergeben. Dies erspart viel Ärger und die Unlesbarkeit des üblichen JDBC-Codes. Ein eindeutiger Gewinn, wenn Sie so etwas beibehalten.

    
wds 27.11.2009 12:45
quelle
2

Ich mag sie und benutze sie sehr. Ich glaube, der Hauptvorteil ist nicht syntaktisch, sondern eher, dass Sie den oben deklarierten Code als anonyme Klassen vordefinieren und wiederverwenden können. Sie könnten zum Beispiel Standardtransformationen vordefinieren, die Sie an die Transformationsfunktion übergeben können, sogar eine NullTransform, die nichts tut, um einen Null-Objekt-Mustereffekt zu erhalten. Dies ermöglicht Ihnen einen deklarativen Codierungsstil.

    
Hannes de Jager 27.11.2009 12:23
quelle
1

Was bruno conde sagte. Außerdem können einige IDEs (z. B. Eclipse) anonyme Klassen verbergen und den Google Collection-Code auf eine einzige Zeile reduzieren. Jetzt das ist lesbar! :)

    
Bombe 27.11.2009 12:18
quelle
1

Bei der Software-Entwicklung ist das explizite und verständliche (lies: wartbar) wichtiger als die Kürze, es sei denn, Sie haben Spaß mit Wegwerf-Code oder Perl-Skript: -)

Wenn Sie eine Liste von Objekten in eine Liste von Objekten eines anderen Typs umwandeln möchten, ist Ihr erstes Java-Beispiel am deutlichsten in Bezug auf die Absicht des Codes, imho.

Im Google collecions-Beispiel wird auch explizit klar, was die Intention des Codes ist, obwohl ich, wie Hannes sagte, keine anonymen Klassen verwenden würde, sondern eine explizit definierte Klasse mit einem nützlichen Namen.

Der syntaktische Zucker, wie Sie ihn in Ruby haben, macht es einfach, Transformationen über den gesamten Code hinweg einzuführen, und wenn sie geändert werden müssen, könnte es leicht sein, einen zu verpassen. Transforming-Listen ist auch keine sehr billige Funktion und die Fähigkeit, sie leicht zu verwenden, kommt mit dem Risiko der Übernutzung.

    
rsp 27.11.2009 13:12
quelle
0

Es ist sehr hässlich und die Leute sehnen sich nach besserer Syntax. Man kann sich nach einer Weile daran gewöhnen, aber es ist für Anfänger einschüchternd.

Vergessen @Override - der Code ist bereits überladen. @Override löst ein Problem, das in der Realität nicht existiert, aber die Leute benutzen es jetzt, als wäre es ein kritisches semantisches Element.

    
irreputable 27.11.2009 16:09
quelle
0

Funktionelle Programmierung ist keine Frage von vielen Tastenanschlägen, die Sie speichern können, sondern hauptsächlich, um die Lesbarkeit Ihres Codes zu verbessern. Wenn Sie beispielsweise lambdaj verwenden, können Sie Ihr Code-Snippet verwenden:

%Vor%

in diesem:

%Vor%

Glauben Sie nicht, dass es auf diese Weise besser lesbar ist?

    
Mario Fusco 27.11.2009 18:05
quelle

Tags und Links