Hinweis : Ich arbeite an Version 2 dieses Handbuchs und benötige Ihre Hilfe! Bitte verwenden Sie dieses Formular, um mir Feedback zu geben, was Ihrer Meinung nach in der nächsten Version enthalten sein sollte. Danke!
Java ist eine der beliebtesten Programmiersprachen überhaupt, aber niemand scheint Freude daran zu haben, sie zu verwenden. Nun, Java ist eigentlich eine gute Programmiersprache, und da Java 8 vor kurzem herauskam, habe ich beschlossen, eine Liste von Bibliotheken, Praktiken und Tools zusammenzustellen, um die Verwendung von Java zu verbessern. „Besser“ ist subjektiv, daher würde ich empfehlen, die Teile zu nehmen, die Sie ansprechen, und sie zu verwenden, anstatt zu versuchen, sie alle auf einmal zu verwenden. Sie können jederzeit Pull-Requests einreichen, in denen Sie Ergänzungen vorschlagen.
Dieser Artikel wurde ursprünglich auf meinem Blog veröffentlicht.
Lesen Sie dies in anderen Sprachen: Englisch, 简体中文
Traditionell wurde Java in einem sehr ausführlichen JavaBean-Enterprise-Stil programmiert. Der neue Stil ist viel sauberer, korrekter und angenehmer für die Augen.
Eines der einfachsten Dinge, die wir als Programmierer tun, ist die Weitergabe von Daten. Der traditionelle Weg, dies zu tun, besteht darin, ein JavaBean zu definieren:
public class DataHolder {
private String data ;
public DataHolder () {
}
public void setData ( String data ) {
this . data = data ;
}
public String getData () {
return this . data ;
}
}
Das ist ausführlich und verschwenderisch. Auch wenn Ihre IDE diesen Code automatisch generiert hat, ist das eine Verschwendung. Also, tun Sie das nicht.
Stattdessen bevorzuge ich den C-Strukturstil zum Schreiben von Klassen, die lediglich Daten enthalten:
public class DataHolder {
public final String data ;
public DataHolder ( String data ) {
this . data = data ;
}
}
Dies ist eine Reduzierung der Anzahl der Codezeilen um die Hälfte. Darüber hinaus ist diese Klasse unveränderlich, sofern Sie sie nicht erweitern, sodass wir leichter darüber nachdenken können, da wir wissen, dass sie nicht geändert werden kann.
Wenn Sie Objekte wie Map oder List speichern, die leicht geändert werden können, sollten Sie stattdessen ImmutableMap oder ImmutableList verwenden, was im Abschnitt über Unveränderlichkeit erläutert wird.
Wenn Sie ein ziemlich kompliziertes Objekt haben, für das Sie eine Struktur erstellen möchten, ziehen Sie das Builder-Muster in Betracht.
Sie erstellen eine statische innere Klasse, die Ihr Objekt erstellt. Es verwendet einen veränderlichen Zustand, aber sobald Sie build aufrufen, wird ein unveränderliches Objekt ausgegeben.
Stellen Sie sich vor, wir hätten einen komplizierteren DataHolder . Der Builder dafür könnte so aussehen:
public class ComplicatedDataHolder {
public final String data ;
public final int num ;
// lots more fields and a constructor
public static class Builder {
private String data ;
private int num ;
public Builder data ( String data ) {
this . data = data ;
return this ;
}
public Builder num ( int num ) {
this . num = num ;
return this ;
}
public ComplicatedDataHolder build () {
return new ComplicatedDataHolder ( data , num ); // etc
}
}
}
Dann um es zu verwenden:
final ComplicatedDataHolder cdh = new ComplicatedDataHolder . Builder ()
. data ( "set this" )
. num ( 523 )
. build ();
Es gibt anderswo bessere Beispiele für Builders, aber dies sollte Ihnen einen Eindruck davon vermitteln, wie es ist. Dies führt zu einem Großteil der Grundbausteine, die wir vermeiden wollten, aber Sie erhalten dadurch unveränderliche Objekte und eine sehr flüssige Benutzeroberfläche.
Anstatt Builder-Objekte manuell zu erstellen, sollten Sie eine der vielen Bibliotheken verwenden, die Ihnen beim Generieren von Buildern helfen können.
Wenn Sie viele unveränderliche Objekte manuell erstellen, sollten Sie den Annotationsprozessor verwenden, um sie automatisch aus Schnittstellen zu generieren. Dies minimiert den Boilerplate-Code, verringert die Wahrscheinlichkeit von Fehlern und fördert die Unveränderlichkeit. In dieser Präsentation finden Sie eine interessante Diskussion einiger Probleme mit normalen Java-Codierungsmustern.
Einige großartige Bibliotheken zur Codegenerierung sind Immutables, Googles Auto-Value und Lombok.
Geprüfte Ausnahmen sollten, wenn überhaupt, mit Vorsicht verwendet werden. Sie zwingen Ihre Benutzer dazu, viele Try/Catch-Blöcke hinzuzufügen und Ihre Ausnahmen in eigene Blöcke einzuschließen. Besser ist es, Ihre Ausnahmen stattdessen RuntimeException erweitern zu lassen. Dies ermöglicht es Ihren Benutzern, Ihre Ausnahmen so zu behandeln, wie sie es möchten, anstatt sie zu zwingen, jedes Mal zu behandeln/zu deklarieren, dass sie ausgelöst werden, was den Code verunreinigt.
Ein raffinierter Trick besteht darin, RuntimeExceptions in die throws-Deklaration Ihrer Methode einzufügen. Dies hat keine Auswirkungen auf den Compiler, informiert Ihre Benutzer jedoch über die Dokumentation darüber, dass diese Ausnahmen ausgelöst werden können.
Dies ist eher ein Abschnitt zur Softwareentwicklung als ein Java-Abschnitt, aber eine der besten Möglichkeiten, testbare Software zu schreiben, ist die Verwendung von Dependency Injection (DI). Da Java das OO-Design stark fördert, müssen Sie DI verwenden, um testbare Software zu erstellen.
In Java erfolgt dies typischerweise mit dem Spring Framework. Es verfügt entweder über eine Code-basierte Verkabelung oder eine XML-Konfigurations-basierte Verkabelung. Wenn Sie die XML-Konfiguration verwenden, ist es wichtig, dass Sie Spring aufgrund seines XML-basierten Konfigurationsformats nicht überbeanspruchen. In XML sollte es absolut keine Logik- oder Kontrollstrukturen geben. Es sollten nur Abhängigkeiten eingefügt werden.
Gute Alternativen zur Verwendung von Spring sind die Dagger-Bibliothek von Google und Square oder Googles Guice. Sie verwenden nicht das XML-Konfigurationsdateiformat von Spring, sondern fügen die Injektionslogik in Annotationen und in Code ein.
Vermeiden Sie nach Möglichkeit die Verwendung von Nullen. Geben Sie keine Nullsammlungen zurück, wenn Sie stattdessen eine leere Sammlung hätten zurückgeben sollen. Wenn Sie null verwenden möchten, sollten Sie die Annotation @Nullable in Betracht ziehen. IntelliJ IDEA verfügt über integrierte Unterstützung für die @Nullable-Annotation.
Lesen Sie mehr darüber, warum Sie keine Nullen verwenden sollten, in „Der schlimmste Fehler der Informatik“.
Wenn Sie Java 8 verwenden, können Sie den hervorragenden neuen optionalen Typ verwenden. Wenn ein Wert vorhanden sein kann oder nicht, schließen Sie ihn wie folgt in eine optionale Klasse ein:
public class FooWidget {
private final String data ;
private final Optional < Bar > bar ;
public FooWidget ( String data ) {
this ( data , Optional . empty ());
}
public FooWidget ( String data , Optional < Bar > bar ) {
this . data = data ;
this . bar = bar ;
}
public Optional < Bar > getBar () {
return bar ;
}
}
Jetzt ist klar, dass die Daten niemals null sein werden, aber bar kann vorhanden sein oder auch nicht. Optional verfügt über Methoden wie isPresent , die den Eindruck erwecken können, dass sich nicht viel von der bloßen Überprüfung von null unterscheidet. Aber es erlaubt Ihnen, Aussagen zu schreiben wie:
final Optional < FooWidget > fooWidget = maybeGetFooWidget ();
final Baz baz = fooWidget . flatMap ( FooWidget :: getBar )
. flatMap ( BarWidget :: getBaz )
. orElse ( defaultBaz );
Das ist viel besser als verkettet, wenn Null überprüft wird. Der einzige Nachteil der Verwendung von Optional besteht darin, dass die Standardbibliothek keine gute Unterstützung für Optional bietet, sodass dort immer noch mit Nullen umgegangen werden muss.
Sofern Sie keinen guten Grund haben, sie anders zu gestalten, sollten Variablen, Klassen und Sammlungen unveränderlich sein.
Variablen können mit final unveränderlich gemacht werden:
final FooWidget fooWidget ;
if ( condition ()) {
fooWidget = getWidget ();
} else {
try {
fooWidget = cachedFooWidget . get ();
} catch ( CachingException e ) {
log . error ( "Couldn't get cached value" , e );
throw e ;
}
}
// fooWidget is guaranteed to be set here
Jetzt können Sie sicher sein, dass fooWidget nicht versehentlich neu zugewiesen wird. Das letzte Schlüsselwort funktioniert mit if/else-Blöcken und mit try/catch-Blöcken. Wenn das fooWidget selbst nicht unveränderlich ist, können Sie es natürlich leicht mutieren.
Sammlungen sollten, wann immer möglich, die Guava-Klassen ImmutableMap, ImmutableList oder ImmutableSet verwenden. Diese verfügen über Builder, sodass Sie sie dynamisch aufbauen und sie dann durch Aufrufen der Build-Methode als unveränderlich markieren können.
Klassen sollten unveränderlich gemacht werden, indem Felder unveränderlich deklariert werden (über final ) und unveränderliche Sammlungen verwendet werden. Optional können Sie die Klasse selbst endgültig machen, sodass sie nicht erweitert und veränderbar gemacht werden kann.
Seien Sie vorsichtig, wenn Sie einer Util-Klasse viele Methoden hinzufügen.
public class MiscUtil {
public static String frobnicateString ( String base , int times ) {
// ... etc
}
public static void throwIfCondition ( boolean condition , String msg ) {
// ... etc
}
}
Diese Klassen scheinen auf den ersten Blick attraktiv zu sein, weil die darin enthaltenen Methoden nicht wirklich an einen bestimmten Ort gehören. Sie werfen sie also alle hier ein, im Namen der Code-Wiederverwendung.
Die Heilung ist schlimmer als die Krankheit. Platzieren Sie diese Klassen dort, wo sie hingehören, und führen Sie eine aggressive Umgestaltung durch. Benennen Sie Klassen, Pakete oder Bibliotheken nicht zu allgemein, wie zum Beispiel „MiscUtils“ oder „ExtrasLibrary“. Dies ermutigt dazu, dort nicht verwandten Code abzulegen.
Formatierung ist so viel weniger wichtig, als die meisten Programmierer es darstellen. Zeigt Beständigkeit, dass Ihnen Ihr Handwerk am Herzen liegt, und hilft es anderen beim Lesen? Absolut. Aber verschwenden wir keinen Tag damit, Leerzeichen in if-Blöcke einzufügen, damit sie „übereinstimmen“.
Wenn Sie unbedingt einen Code-Formatierungsleitfaden benötigen, kann ich Ihnen den Java Style Guide von Google wärmstens empfehlen. Der beste Teil dieses Leitfadens ist der Abschnitt „Programmierpraktiken“. Auf jeden Fall eine Lektüre wert.
Es ist wichtig, Ihren benutzerorientierten Code zu dokumentieren. Und das bedeutet, Beispiele zu verwenden und sinnvolle Beschreibungen von Variablen, Methoden und Klassen zu verwenden.
Die Konsequenz daraus ist, nicht zu dokumentieren, was nicht dokumentiert werden muss. Wenn Sie nichts dazu sagen können, was ein Argument ist, oder wenn es offensichtlich ist, dokumentieren Sie es nicht. Eine Standarddokumentation ist schlimmer als gar keine Dokumentation, da sie Ihren Benutzern vorgaukelt, dass es eine Dokumentation gibt.
Java 8 hat eine schöne Stream- und Lambda-Syntax. Sie könnten Code wie diesen schreiben:
final List < String > filtered = list . stream ()
. filter ( s -> s . startsWith ( "s" ))
. map ( s -> s . toUpperCase ())
. collect ( Collectors . toList ());
Stattdessen:
final List < String > filtered = new ArrayList <>();
for ( String str : list ) {
if ( str . startsWith ( "s" ) {
filtered . add ( str . toUpperCase ());
}
}
Dadurch können Sie flüssigeren Code schreiben, der besser lesbar ist.
Die ordnungsgemäße Bereitstellung von Java kann etwas schwierig sein. Heutzutage gibt es zwei Hauptmethoden zur Bereitstellung von Java: die Verwendung eines Frameworks oder die Verwendung einer selbst entwickelten Lösung, die flexibler ist.
Da die Bereitstellung von Java nicht einfach ist, wurden Frameworks erstellt, die hilfreich sein können. Zwei der besten sind Dropwizard und Spring Boot. Das Play-Framework kann ebenfalls als eines dieser Bereitstellungs-Frameworks betrachtet werden.
Sie alle versuchen, die Hürde zu senken, die Sie daran hindern, Ihren Code herauszubringen. Sie sind besonders hilfreich, wenn Sie Java-Neuling sind oder Dinge schnell erledigen müssen. Einzelne JAR-Bereitstellungen sind einfach einfacher als komplizierte WAR- oder EAR-Bereitstellungen.
Allerdings können sie etwas unflexibel sein und eher eigensinnig sein. Wenn Ihr Projekt also nicht zu den Entscheidungen passt, die die Entwickler Ihres Frameworks getroffen haben, müssen Sie zu einer eher manuell erstellten Konfiguration migrieren.
Gute Alternative : Gradle.
Maven ist immer noch das Standardtool zum Erstellen, Verpacken und Ausführen Ihrer Tests. Es gibt Alternativen wie Gradle, aber sie haben nicht die gleiche Akzeptanz wie Maven. Wenn Sie neu bei Maven sind, sollten Sie mit Maven by Beispiel beginnen.
Ich möchte ein Root-POM mit allen externen Abhängigkeiten haben, die Sie verwenden möchten. Es wird ungefähr so aussehen. Dieses Root-POM hat nur eine externe Abhängigkeit, aber wenn Ihr Produkt groß genug ist, haben Sie Dutzende. Ihr Root-POM sollte ein eigenständiges Projekt sein: unter Versionskontrolle und freigegeben wie jedes andere Java-Projekt.
Wenn Sie der Meinung sind, dass es zu viel ist, Ihr Root-POM für jede externe Abhängigkeitsänderung zu kennzeichnen, haben Sie keine Woche damit verschwendet, projektübergreifende Abhängigkeitsfehler aufzuspüren.
Alle Ihre Maven-Projekte enthalten Ihr Root-POM und alle seine Versionsinformationen. Auf diese Weise erhalten Sie die von Ihrem Unternehmen ausgewählte Version jeder externen Abhängigkeit und alle korrekten Maven-Plugins. Wenn Sie externe Abhängigkeiten einbinden müssen, funktioniert das einfach so:
< dependencies >
< dependency >
< groupId >org.third.party</ groupId >
< artifactId >some-artifact</ artifactId >
</ dependency >
</ dependencies >
Wenn Sie interne Abhängigkeiten wünschen, sollten diese von jedem einzelnen Projekt verwaltet werden Abschnitt. Andernfalls wäre es schwierig, die Root-POM-Versionsnummer beizubehalten.
Einer der besten Aspekte von Java ist die riesige Menge an Bibliotheken von Drittanbietern, die alles können. Im Wesentlichen verfügt jede API oder jedes Toolkit über ein Java SDK und es ist einfach, es mit Maven einzubinden.
Und diese Java-Bibliotheken selbst hängen von bestimmten Versionen anderer Bibliotheken ab. Wenn Sie genügend Bibliotheken abrufen, kommt es zu Versionskonflikten, das heißt etwa so:
Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9
Welche Version wird in Ihr Projekt übernommen?
Beim Maven-Abhängigkeitskonvergenz-Plugin tritt beim Build ein Fehler auf, wenn Ihre Abhängigkeiten nicht dieselbe Version verwenden. Dann haben Sie zwei Möglichkeiten, den Konflikt zu lösen:
Die Auswahl hängt von Ihrer Situation ab: Wenn Sie die Version eines Projekts verfolgen möchten, ist das Ausschließen sinnvoll. Wenn Sie dies jedoch explizit angeben möchten, können Sie eine Version auswählen. Sie müssen diese jedoch aktualisieren, wenn Sie die anderen Abhängigkeiten aktualisieren.
Offensichtlich benötigen Sie eine Art kontinuierlichen Integrationsserver, der Ihre SNAPSHOT-Versionen und Tag-Builds basierend auf Git-Tags kontinuierlich erstellt.
Jenkins und Travis-CI sind natürliche Entscheidungen.
Die Codeabdeckung ist nützlich und Cobertura verfügt über ein gutes Maven-Plugin und CI-Unterstützung. Es gibt andere Code-Coverage-Tools für Java, aber ich habe Cobertura verwendet.
Sie benötigen einen Ort, an dem Sie Ihre JARs, WARs und EARs ablegen können, also benötigen Sie ein Repository.
Gängige Optionen sind Artifactory und Nexus. Beide funktionieren und haben ihre eigenen Vor- und Nachteile.
Sie sollten über eine eigene Artifactory/Nexus-Installation verfügen und Ihre Abhängigkeiten darauf spiegeln. Dadurch wird verhindert, dass Ihr Build kaputt geht, weil ein Upstream-Maven-Repository ausgefallen ist.
Jetzt haben Sie Ihren Code kompiliert, Ihr Repository eingerichtet und müssen Ihren Code in Ihrer Entwicklungsumgebung bereitstellen und ihn schließlich in die Produktion übertragen. Sparen Sie hier nicht, denn die Automatisierung wird sich noch lange auszahlen.
Chef, Puppet und Ansible sind typische Optionen. Ich habe eine Alternative namens „Squadron“ geschrieben, die Sie meiner Meinung nach unbedingt ausprobieren sollten, da es einfacher ist, sie richtig hinzubekommen als die Alternativen.
Unabhängig davon, für welches Tool Sie sich entscheiden, vergessen Sie nicht, Ihre Bereitstellungen zu automatisieren.
Das wahrscheinlich beste Merkmal von Java ist die große Anzahl an Bibliotheken. Dies ist eine kleine Sammlung von Bibliotheken, die wahrscheinlich für die größte Gruppe von Menschen anwendbar sind.
Javas Standardbibliothek, einst ein erstaunlicher Fortschritt, scheint nun mehrere wichtige Funktionen zu vermissen.
Das Apache Commons-Projekt verfügt über eine Reihe nützlicher Bibliotheken.
Commons Codec verfügt über viele nützliche Kodierungs-/Dekodierungsmethoden für Base64- und Hex-Strings. Verschwenden Sie nicht Ihre Zeit damit, diese neu zu schreiben.
Commons Lang ist die Anlaufstelle für die Bearbeitung und Erstellung von Zeichenfolgen, Zeichensätzen und einer Reihe verschiedener Hilfsmethoden.
Commons IO verfügt über alle dateibezogenen Methoden, die Sie sich nur wünschen können. Es verfügt über FileUtils.copyDirectory, FileUtils.writeStringToFile, IOUtils.readLines und vieles mehr.
Guava ist Googles hervorragende Bibliothek, in der Sie erfahren, was Java fehlt. Es ist fast schwierig, alles zusammenzufassen, was mir an dieser Bibliothek gefällt, aber ich werde es versuchen.
Cache ist eine einfache Möglichkeit, einen In-Memory-Cache zu erhalten, der zum Zwischenspeichern von Netzwerkzugriffen, Festplattenzugriffen, Speicherfunktionen usw. verwendet werden kann. Implementieren Sie einfach einen CacheBuilder, der Guava mitteilt, wie Sie Ihren Cache erstellen sollen, und schon sind Sie fertig!
Unveränderliche Sammlungen. Es gibt eine Menge davon: ImmutableMap, ImmutableList oder sogar ImmutableSortedMultiSet, wenn das Ihr Stil ist.
Ich schreibe auch gerne veränderliche Sammlungen auf Guava-Art:
// Instead of
final Map < String , Widget > map = new HashMap <>();
// You can use
final Map < String , Widget > map = Maps . newHashMap ();
Es gibt statische Klassen für Listen, Karten, Mengen und mehr. Sie sind übersichtlicher und leichter zu lesen.
Wenn Sie bei Java 6 oder 7 nicht weiterkommen, können Sie die Klasse Collections2 verwenden, die über Methoden wie Filter und Transform verfügt. Sie ermöglichen Ihnen das Schreiben flüssigen Codes ohne die Stream-Unterstützung von Java 8.
Guava verfügt auch über einfache Dinge, wie einen Joiner , der Zeichenfolgen an Trennzeichen verbindet, und eine Klasse, die Interrupts behandelt, indem sie sie ignoriert.
Die Gson-Bibliothek von Google ist eine einfache und schnelle JSON-Parsing-Bibliothek. Es funktioniert so:
final Gson gson = new Gson ();
final String json = gson . toJson ( fooWidget );
final FooWidget newFooWidget = gson . fromJson ( json , FooWidget . class );
Es ist wirklich einfach und es macht Freude, damit zu arbeiten. Das Gson-Benutzerhandbuch enthält viele weitere Beispiele.
Eines meiner ständigen Ärgernisse bei Java ist, dass in der Standardbibliothek keine Tupel integriert sind. Glücklicherweise behebt das Java-Tupelprojekt dieses Problem.
Es ist einfach zu bedienen und funktioniert großartig:
Pair < String , Integer > func ( String input ) {
// something...
return Pair . with ( stringResult , intResult );
}
Javaslang ist eine funktionale Bibliothek, die dazu dient, fehlende Funktionen hinzuzufügen, die Teil von Java 8 sein sollten. Einige dieser Funktionen sind es
Es gibt mehrere Java-Bibliotheken, die auf den ursprünglichen Java-Sammlungen basieren. Diese sind darauf beschränkt, mit Klassen kompatibel zu bleiben, die mit einem objektorientierten Fokus erstellt und veränderbar gestaltet wurden. Die Javaslang-Kollektionen für Java sind eine völlig neue Version, inspiriert von Haskell, Clojure und Scala. Sie sind funktional ausgerichtet und folgen einem unveränderlichen Design.
Code wie dieser ist automatisch Thread-sicher und Try-Catch-frei:
// Success/Failure containing the result/exception
public static Try < User > getUser ( int userId ) {
return Try . of (() -> DB . findUser ( userId ))
. recover ( x -> Match . of ( x )
. whenType ( RemoteException . class ). then ( e -> ...)
. whenType ( SQLException . class ). then ( e -> ...));
}
// Thread-safe, reusable collections
public static List < String > sayByeBye () {
return List . of ( "bye, " bye ", "collect" , "mania" )
. map ( String :: toUpperCase )
. intersperse ( " " );
}
Joda-Time ist mit Sicherheit die beste Zeitbibliothek, die ich je verwendet habe. Einfach, unkompliziert, leicht zu testen. Was können Sie sonst noch verlangen?
Sie benötigen dies nur, wenn Sie noch nicht mit Java 8 arbeiten, da dieses über eine eigene neue Zeitbibliothek verfügt, die nicht schlecht ist.
Lombok ist eine interessante Bibliothek. Durch Annotationen können Sie den Boilerplate reduzieren, unter dem Java so stark leidet.
Benötigen Sie Setter und Getter für Ihre Klassenvariablen? Einfach:
public class Foo {
@ Getter @ Setter private int var ;
}
Jetzt können Sie Folgendes tun:
final Foo foo = new Foo ();
foo . setVar ( 5 );
Und es gibt noch so viel mehr. Ich habe Lombok noch nicht in der Produktion verwendet, kann es aber kaum erwarten.
Gute Alternativen : Jersey oder Spark
Es gibt zwei Hauptlager für die Ausführung von RESTful-Webdiensten in Java: JAX-RS und alles andere.
JAX-RS ist der traditionelle Weg. Sie kombinieren Annotationen mit Schnittstellen und Implementierungen, um mithilfe von Jersey den Webdienst zu bilden. Das Schöne daran ist, dass Sie ganz einfach Clients nur aus der Interface-Klasse erstellen können.
Das Play-Framework ist eine völlig andere Sicht auf Webdienste auf der JVM: Sie haben eine Routendatei und schreiben dann die Klassen, auf die in diesen Routen verwiesen wird. Es handelt sich eigentlich um ein komplettes MVC-Framework, aber Sie können es problemlos nur für REST-Webdienste verwenden.
Es ist sowohl für Java als auch für Scala verfügbar. Es leidet etwas darunter, dass Scala zuerst verwendet wird, lässt sich aber immer noch gut in Java verwenden.
Wenn Sie mit Mikro-Frameworks wie Flask in Python vertraut sind, wird Ihnen Spark sehr vertraut sein. Es funktioniert besonders gut mit Java 8.
Es gibt viele Java-Protokollierungslösungen. Mein Favorit ist SLF4J, weil es extrem steckbar ist und Protokolle aus vielen verschiedenen Protokollierungs-Frameworks gleichzeitig kombinieren kann. Haben Sie ein seltsames Projekt, das java.util.logging, JCL und log4j verwendet? SLF4J ist für Sie.
Das zweiseitige Handbuch ist so ziemlich alles, was Sie für den Einstieg benötigen.
Ich mag schwere ORM-Frameworks nicht, weil ich SQL mag. Ich habe also viele JDBC-Vorlagen geschrieben und es war ziemlich schwierig, sie zu pflegen. jOOQ ist eine viel bessere Lösung.
Damit können Sie SQL typsicher in Java schreiben:
// Typesafely execute the SQL statement directly with jOOQ
Result < Record3 < String , String , String >> result =
create . select ( BOOK . TITLE , AUTHOR . FIRST_NAME , AUTHOR . LAST_NAME )
. from ( BOOK )
. join ( AUTHOR )
. on ( BOOK . AUTHOR_ID . equal ( AUTHOR . ID ))
. where ( BOOK . PUBLISHED_IN . equal ( 1948 ))
. fetch ();
Mit diesem und dem DAO-Muster können Sie den Datenbankzugriff zum Kinderspiel machen.
Tests sind für Ihre Software von entscheidender Bedeutung. Diese Pakete machen es einfacher.
Gute Alternative : TestNG.
jUnit braucht keine Einführung. Es ist das Standardtool für Unit-Tests in Java.
Aber Sie nutzen jUnit wahrscheinlich nicht in vollem Umfang aus. jUnit unterstützt parametrisierte Tests, Regeln, die Sie davon abhalten, so viel Textbausteine zu schreiben, Theorien zum zufälligen Testen bestimmter Codes und Annahmen.
Wenn Sie Ihre Abhängigkeitsinjektion durchgeführt haben, zahlt sich dies hier aus: Code, der Nebenwirkungen hat (z. B. die Kommunikation mit einem REST-Server), nachahmen und dennoch das Verhalten des Codes, der ihn aufruft, durchsetzen.
jMock ist das Standard-Mocking-Tool für Java. Es sieht so aus:
public class FooWidgetTest {
private Mockery context = new Mockery ();
@ Test
public void basicTest () {
final FooWidgetDependency dep = context . mock ( FooWidgetDependency . class );
context . checking ( new Expectations () {{
oneOf ( dep ). call ( with ( any ( String . class )));
atLeast ( 0 ). of ( dep ). optionalCall ();
}});
final FooWidget foo = new FooWidget ( dep );
Assert . assertTrue ( foo . doThing ());
context . assertIsSatisfied ();
}
}
Dadurch wird über jMock eine FooWidgetDependency eingerichtet und dann Erwartungen hinzugefügt. Wir gehen davon aus, dass die Call -Methode von dep einmal mit einem String aufgerufen wird und dass die optionalCall- Methode von dep null oder mehrmals aufgerufen wird.
Wenn Sie dieselbe Abhängigkeit immer wieder einrichten müssen, sollten Sie diese wahrscheinlich in ein Test-Fixture einfügen und „assesserIsSatisfied“ in ein @After -Fixture einfügen.
Machen Sie das jemals mit jUnit?
final List < String > result = some . testMethod ();
assertEquals ( 4 , result . size ());
assertTrue ( result . contains ( "some result" ));
assertTrue ( result . contains ( "some other result" ));
assertFalse ( result . contains ( "shouldn't be here" ));
Das ist nur ein nerviges Musterbeispiel. AssertJ löst dieses Problem. Sie können denselben Code wie folgt umwandeln:
assertThat ( some . testMethod ()). hasSize ( 4 )
. contains ( "some result" , "some other result" )
. doesNotContain ( "shouldn't be here" );
Diese flüssige Benutzeroberfläche macht Ihre Tests besser lesbar. Was will man mehr?
Gute Alternativen : Eclipse und Netbeans
Die beste Java-IDE ist IntelliJ IDEA. Es verfügt über eine Menge großartiger Funktionen und ist wirklich das Wichtigste, was die Ausführlichkeit von Java erträglich macht. Autocomplete ist großartig, die Inspektionen sind erstklassig und die Refactoring-Tools sind wirklich hilfreich.
Die kostenlose Community-Edition ist für mich gut genug, aber die Ultimate-Edition bietet jede Menge tolle Funktionen wie Datenbanktools, Spring Framework-Unterstützung und Chronon.
Eine meiner Lieblingsfunktionen von GDB 7 war die Möglichkeit, beim Debuggen in die Vergangenheit zu reisen. Dies ist mit dem Chronon IntelliJ-Plugin möglich, wenn Sie die Ultimate Edition erhalten.
Sie erhalten Variablenverlauf, Rückschritt, Methodenverlauf und mehr. Die erste Verwendung ist etwas seltsam, aber es kann helfen, einige wirklich komplizierte Fehler, Heisenbugs und dergleichen zu beheben.
Gute Alternative : DCEVM
Kontinuierliche Integration ist oft ein Ziel von Software-as-a-Service-Produkten. Was wäre, wenn Sie nicht einmal auf den Abschluss des Builds warten müssten, um Codeänderungen live zu sehen?
Das ist es, was JRebel tut. Sobald Sie Ihren Server mit Ihrem JRebel-Client verbinden, können Sie Änderungen auf Ihrem Server sofort sehen. Das ist eine enorme Zeitersparnis, wenn Sie schnell experimentieren möchten.
Das Typsystem von Java ist ziemlich schwach. Es unterscheidet nicht zwischen Strings und Strings, die tatsächlich reguläre Ausdrücke sind, und führt auch keine Taint-Prüfung durch. Das Checker Framework leistet jedoch dies und noch mehr.
Es verwendet Annotationen wie @Nullable, um Typen zu überprüfen. Sie können sogar Ihre eigenen Anmerkungen definieren, um die statische Analyse noch leistungsfähiger zu machen.
Selbst wenn man Best Practices befolgt, macht selbst der beste Entwickler Fehler. Es gibt eine Reihe von Tools, mit denen Sie Ihren Java-Code validieren können, um Probleme in Ihrem Code zu erkennen. Nachfolgend finden Sie eine kleine Auswahl einiger der beliebtesten Tools. Viele davon lassen sich in gängige IDEs wie Eclipse oder IntelliJ integrieren, sodass Sie Fehler in Ihrem Code schneller erkennen können.
Neben der Verwendung dieser Tools während der Entwicklung ist es oft sinnvoll, sie auch während der Build-Phase ausführen zu lassen. Sie können in Build-Tools wie Maven oder Gradle und auch in Tools für die kontinuierliche Integration eingebunden werden.
Selbst in Java kommt es zu Speicherlecks. Zum Glück gibt es dafür Tools. Das beste Tool, mit dem ich diese Probleme behoben habe, ist der Eclipse Memory Analyzer. Es erstellt einen Heap-Dump und ermöglicht es Ihnen, das Problem zu finden.
Es gibt mehrere Möglichkeiten, einen Heap-Dump für einen JVM-Prozess zu erhalten, aber ich verwende jmap:
$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152
Attaching to process ID 8152, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.25-b01
Dumping heap to heapdump.hprof ...
... snip ...
Heap dump file created
Dann können Sie die Datei heapdump.hprof mit dem Memory Analyzer öffnen und schnell sehen, was los ist.
Ressourcen, die Ihnen helfen, ein Java-Meister zu werden.