Remarque : je travaille sur la version 2 de ce guide et j'ai besoin de votre aide ! Veuillez utiliser ce formulaire pour me faire part de vos commentaires sur ce qui, selon vous, devrait figurer dans la prochaine version. Merci!
Java est l’un des langages de programmation les plus populaires, mais personne ne semble aimer l’utiliser. Eh bien, Java est en fait un bon langage de programmation, et depuis la sortie récente de Java 8, j'ai décidé de compiler une liste de bibliothèques, de pratiques et d'outils pour améliorer l'utilisation de Java. "Mieux" est subjectif, je recommanderais donc de prendre les parties qui vous parlent et de les utiliser, plutôt que d'essayer de toutes les utiliser en même temps. N'hésitez pas à soumettre des pull request suggérant des ajouts.
Cet article a été initialement publié sur mon blog.
Lisez ceci dans d'autres langues : anglais, 简体中文
Traditionnellement, Java était programmé dans un style JavaBean d'entreprise très verbeux. Le nouveau style est beaucoup plus propre, plus correct et plus agréable pour les yeux.
L’une des choses les plus simples que nous faisons en tant que programmeurs est de transmettre des données. La manière traditionnelle de procéder consiste à définir un JavaBean :
public class DataHolder {
private String data ;
public DataHolder () {
}
public void setData ( String data ) {
this . data = data ;
}
public String getData () {
return this . data ;
}
}
C’est verbeux et inutile. Même si votre IDE génère automatiquement ce code, c'est du gaspillage. Alors, ne fais pas ça.
Au lieu de cela, je préfère le style de structure C pour écrire des classes qui contiennent simplement des données :
public class DataHolder {
public final String data ;
public DataHolder ( String data ) {
this . data = data ;
}
}
Cela représente une réduction de moitié du nombre de lignes de code. De plus, cette classe est immuable à moins que vous ne l'étendiez, nous pouvons donc en raisonner plus facilement car nous savons qu'elle ne peut pas être modifiée.
Si vous stockez des objets comme Map ou List qui peuvent être modifiés facilement, vous devez plutôt utiliser ImmutableMap ou ImmutableList, qui est abordé dans la section sur l'immuabilité.
Si vous souhaitez créer une structure pour un objet plutôt compliqué, considérez le modèle Builder.
Vous créez une classe interne statique qui construira votre objet. Il utilise un état mutable, mais dès que vous appelez build, il émettra un objet immuable.
Imaginez que nous ayons un DataHolder plus compliqué. Le constructeur pourrait ressembler à ceci :
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
}
}
}
Ensuite pour l'utiliser :
final ComplicatedDataHolder cdh = new ComplicatedDataHolder . Builder ()
. data ( "set this" )
. num ( 523 )
. build ();
Il existe de meilleurs exemples de constructeurs ailleurs, mais cela devrait vous donner un avant-goût de ce à quoi cela ressemble. Cela aboutit à une grande partie du passe-partout que nous essayions d'éviter, mais cela vous donne des objets immuables et une interface très fluide.
Au lieu de créer des objets de création à la main, envisagez d'utiliser l'une des nombreuses bibliothèques qui peuvent vous aider à générer des générateurs.
Si vous créez manuellement de nombreux objets immuables, envisagez d'utiliser le processeur d'annotations pour les générer automatiquement à partir des interfaces. Cela minimise le code passe-partout, réduit la probabilité de bogues et favorise l'immuabilité. Voir cette présentation pour une discussion intéressante sur certains des problèmes liés aux modèles de codage Java normaux.
Certaines excellentes bibliothèques de génération de code sont immuables, la valeur automatique de Google et Lombok.
Les exceptions vérifiées doivent être utilisées avec prudence, voire pas du tout. Ils obligent vos utilisateurs à ajouter de nombreux blocs try/catch et à intégrer vos exceptions dans les leurs. Mieux vaut plutôt faire en sorte que vos exceptions étendent RuntimeException. Cela permet à vos utilisateurs de gérer vos exceptions comme ils le souhaitent, plutôt que de les forcer à gérer/déclarer qu'elles sont levées à chaque fois, ce qui pollue le code.
Une astuce astucieuse consiste à mettre RuntimeExceptions dans la déclaration throws de votre méthode. Cela n'a aucun effet sur le compilateur, mais informera vos utilisateurs via la documentation que ces exceptions peuvent être levées.
Il s'agit plus d'une section de génie logiciel que d'une section Java, mais l'un des meilleurs moyens d'écrire des logiciels testables est d'utiliser l'injection de dépendances (DI). Étant donné que Java encourage fortement la conception OO, pour créer des logiciels testables, vous devez utiliser DI.
En Java, cela se fait généralement avec Spring Framework. Il dispose soit d'un câblage basé sur le code, soit d'un câblage basé sur la configuration XML. Si vous utilisez la configuration XML, il est important de ne pas abuser de Spring en raison de son format de configuration basé sur XML. Il ne devrait y avoir absolument aucune logique ou structure de contrôle en XML. Il ne devrait injecter que des dépendances.
De bonnes alternatives à l'utilisation de Spring sont la bibliothèque Dagger de Google et Square ou Guice de Google. Ils n'utilisent pas le format de fichier de configuration XML de Spring et placent plutôt la logique d'injection dans les annotations et dans le code.
Essayez d'éviter d'utiliser des valeurs nulles lorsque vous le pouvez. Ne renvoyez pas de collections nulles alors que vous auriez dû renvoyer une collection vide. Si vous envisagez d'utiliser null, pensez à l'annotation @Nullable. IntelliJ IDEA prend en charge l'annotation @Nullable.
Découvrez pourquoi ne pas utiliser les valeurs nulles dans La pire erreur de l'informatique.
Si vous utilisez Java 8, vous pouvez utiliser l'excellent nouveau type Facultatif. Si une valeur peut être présente ou non, enveloppez-la dans une classe facultative comme celle-ci :
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 ;
}
}
Alors maintenant, il est clair que les données ne seront jamais nulles, mais la barre peut être présente ou non. Facultatif a des méthodes comme isPresent , ce qui peut donner l'impression que peu de choses sont différentes de la simple vérification de null . Mais cela vous permet d'écrire des déclarations telles que :
final Optional < FooWidget > fooWidget = maybeGetFooWidget ();
final Baz baz = fooWidget . flatMap ( FooWidget :: getBar )
. flatMap ( BarWidget :: getBaz )
. orElse ( defaultBaz );
Ce qui est bien mieux que des vérifications enchaînées si nulles. Le seul inconvénient de l'utilisation de Optionnel est que la bibliothèque standard ne dispose pas d'un bon support Optionnel, donc le traitement des valeurs NULL y est toujours nécessaire.
Sauf si vous avez une bonne raison de les modifier autrement, les variables, les classes et les collections doivent être immuables.
Les variables peuvent être rendues immuables avec final :
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
Vous pouvez désormais être sûr que fooWidget ne sera pas réaffecté accidentellement. Le mot-clé final fonctionne avec les blocs if/else et avec les blocs try/catch. Bien sûr, si le fooWidget lui-même n'est pas immuable, vous pouvez facilement le muter.
Les collections doivent, dans la mesure du possible, utiliser les classes Guava ImmutableMap, ImmutableList ou ImmutableSet. Ceux-ci ont des constructeurs afin que vous puissiez les construire dynamiquement, puis les marquer comme immuables en appelant la méthode build.
Les classes doivent être rendues immuables en déclarant les champs immuables (via final ) et en utilisant des collections immuables. En option, vous pouvez rendre la classe elle-même finale afin qu'elle ne puisse pas être étendue et rendue mutable.
Soyez prudent si vous ajoutez de nombreuses méthodes à une classe Util.
public class MiscUtil {
public static String frobnicateString ( String base , int times ) {
// ... etc
}
public static void throwIfCondition ( boolean condition , String msg ) {
// ... etc
}
}
Ces cours, à première vue, semblent attrayants parce que les méthodes qui y sont utilisées n'appartiennent pas vraiment à un seul endroit. Vous les jetez donc tous ici au nom de la réutilisation du code.
Le remède est pire que le mal. Mettez ces classes à leur place et refactorisez-les de manière agressive. Ne nommez pas les classes, packages ou bibliothèques de manière trop générique, comme « MiscUtils » ou « ExtrasLibrary ». Cela encourage à y déposer du code sans rapport.
Le formatage est bien moins important que la plupart des programmeurs le prétendent. La cohérence montre-t-elle que vous vous souciez de votre métier et aide-t-elle les autres à lire ? Absolument. Mais ne perdons pas une journée à ajouter des espaces aux blocs if pour qu'ils « correspondent ».
Si vous avez absolument besoin d'un guide de formatage du code, je recommande fortement le guide de style Java de Google. La meilleure partie de ce guide est la section Pratiques de programmation. Ça vaut vraiment le coup d'être lu.
Il est important de documenter votre code destiné aux utilisateurs. Et cela signifie utiliser des exemples et utiliser des descriptions sensées des variables, des méthodes et des classes.
Le corollaire de ceci est de ne pas documenter ce qui n’a pas besoin d’être documenté. Si vous n'avez rien à dire sur un argument, ou s'il est évident, ne le documentez pas. La documentation standard est pire que l'absence de documentation du tout, car elle fait croire à vos utilisateurs qu'il existe de la documentation.
Java 8 a une belle syntaxe stream et lambda. Vous pourriez écrire du code comme ceci :
final List < String > filtered = list . stream ()
. filter ( s -> s . startsWith ( "s" ))
. map ( s -> s . toUpperCase ())
. collect ( Collectors . toList ());
Au lieu de ça :
final List < String > filtered = new ArrayList <>();
for ( String str : list ) {
if ( str . startsWith ( "s" ) {
filtered . add ( str . toUpperCase ());
}
}
Cela vous permet d’écrire du code plus fluide, plus lisible.
Déployer correctement Java peut être un peu délicat. Il existe aujourd’hui deux manières principales de déployer Java : utiliser un framework ou utiliser une solution maison plus flexible.
Parce que le déploiement de Java n'est pas facile, des frameworks ont été créés pour vous aider. Deux des meilleurs sont Dropwizard et Spring Boot. Le framework Play peut également être considéré comme l’un de ces frameworks de déploiement.
Tous tentent de réduire les obstacles à la diffusion de votre code. Ils sont particulièrement utiles si vous êtes nouveau sur Java ou si vous avez besoin de faire avancer les choses rapidement. Les déploiements JAR uniques sont tout simplement plus faciles que les déploiements WAR ou EAR compliqués.
Cependant, ils peuvent être quelque peu rigides et plutôt opiniâtres, donc si votre projet ne correspond pas aux choix faits par les développeurs de votre framework, vous devrez migrer vers une configuration plus élaborée à la main.
Bonne alternative : Gradle.
Maven reste l'outil standard pour créer, empaqueter et exécuter vos tests. Il existe des alternatives, comme Gradle, mais elles n'ont pas la même adoption que Maven. Si vous êtes nouveau sur Maven, vous devriez commencer par Maven par exemple.
J'aime avoir un POM racine avec toutes les dépendances externes que vous souhaitez utiliser. Cela ressemblera à ceci. Ce POM racine n'a qu'une seule dépendance externe, mais si votre produit est suffisamment gros, vous en aurez des dizaines. Votre POM racine doit être un projet à part entière : sous contrôle de version et publié comme tout autre projet Java.
Si vous pensez que marquer votre POM racine pour chaque changement de dépendance externe est trop difficile, vous n'avez pas perdu une semaine à rechercher les erreurs de dépendance entre projets.
Tous vos projets Maven incluront votre POM racine et toutes ses informations de version. De cette façon, vous obtenez la version sélectionnée par votre entreprise de chaque dépendance externe et tous les plugins Maven appropriés. Si vous devez intégrer des dépendances externes, cela fonctionne comme ceci :
< dependencies >
< dependency >
< groupId >org.third.party</ groupId >
< artifactId >some-artifact</ artifactId >
</ dependency >
</ dependencies >
Si vous souhaitez des dépendances internes, cela doit être géré par le responsable de chaque projet individuel. section. Sinon, il serait difficile de conserver le numéro de version racine du POM.
L'un des meilleurs aspects de Java est la quantité massive de bibliothèques tierces qui font tout. Essentiellement, chaque API ou boîte à outils dispose d'un SDK Java et il est facile de l'intégrer avec Maven.
Et ces bibliothèques Java elles-mêmes dépendent de versions spécifiques d’autres bibliothèques. Si vous récupérez suffisamment de bibliothèques, vous obtiendrez des conflits de versions, c'est-à-dire quelque chose comme ceci :
Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9
Quelle version sera intégrée à votre projet ?
Avec le plugin de convergence des dépendances Maven, la construction entraînera une erreur si vos dépendances n'utilisent pas la même version. Ensuite, vous disposez de deux options pour résoudre le conflit :
Le choix dépend de votre situation : si vous souhaitez suivre la version d'un projet, l'exclure est logique. D'un autre côté, si vous souhaitez être explicite à ce sujet, vous pouvez choisir une version, même si vous devrez la mettre à jour lorsque vous mettrez à jour les autres dépendances.
Évidemment, vous avez besoin d'une sorte de serveur d'intégration continue qui va continuellement créer vos versions SNAPSHOT et vos builds de balises basées sur les balises git.
Jenkins et Travis-CI sont des choix naturels.
La couverture du code est utile et Cobertura dispose d'un bon plugin Maven et d'un bon support CI. Il existe d'autres outils de couverture de code pour Java, mais j'ai utilisé Cobertura.
Vous avez besoin d'un endroit pour placer vos JAR, WAR et EAR que vous créez, vous aurez donc besoin d'un référentiel.
Les choix courants sont Artifactory et Nexus. Les deux fonctionnent et ont leurs propres avantages et inconvénients.
Vous devez disposer de votre propre installation Artifactory/Nexus et y refléter vos dépendances. Cela empêchera votre build de se briser car certains référentiels Maven en amont sont tombés en panne.
Alors maintenant, vous avez compilé votre code, votre référentiel configuré et vous devez sortir votre code dans votre environnement de développement et éventuellement le mettre en production. Ne lésinez pas ici, car l'automatisation de cela portera ses fruits pendant longtemps.
Chef, Puppet et Ansible sont des choix typiques. J'ai écrit une alternative appelée Squadron, que je pense bien sûr que vous devriez vérifier car elle est plus facile à réussir que les alternatives.
Quel que soit l'outil que vous choisissez, n'oubliez pas d'automatiser vos déploiements.
La meilleure fonctionnalité de Java est probablement la grande quantité de bibliothèques dont il dispose. Il s’agit d’une petite collection de bibliothèques susceptibles de s’appliquer au plus grand nombre de personnes.
La bibliothèque standard de Java, qui représentait autrefois un progrès incroyable, semble désormais manquer de plusieurs fonctionnalités clés.
Le projet Apache Commons possède de nombreuses bibliothèques utiles.
Commons Codec propose de nombreuses méthodes d'encodage/décodage utiles pour les chaînes Base64 et hexadécimale. Ne perdez pas votre temps à les réécrire.
Commons Lang est la bibliothèque incontournable pour la manipulation et la création de chaînes, les jeux de caractères et de nombreuses méthodes utilitaires diverses.
Commons IO propose toutes les méthodes liées aux fichiers dont vous pourriez rêver. Il contient FileUtils.copyDirectory, FileUtils.writeStringToFile, IOUtils.readLines et bien plus encore.
Guava est l'excellente bibliothèque de Google pour découvrir ce qui manque à Java. Il est presque difficile de distiller tout ce que j'aime dans cette bibliothèque, mais je vais essayer.
Le cache est un moyen simple d'obtenir un cache en mémoire qui peut être utilisé pour mettre en cache l'accès au réseau, l'accès au disque, mémoriser des fonctions ou quoi que ce soit de vraiment. Implémentez simplement un CacheBuilder qui indique à Guava comment créer votre cache et vous êtes prêt !
Des collections immuables . Il y en a plusieurs : ImmutableMap, ImmutableList ou même ImmutableSortedMultiSet si tel est votre style.
J'aime aussi écrire des collections mutables à la manière de Guava :
// Instead of
final Map < String , Widget > map = new HashMap <>();
// You can use
final Map < String , Widget > map = Maps . newHashMap ();
Il existe des classes statiques pour les listes, les cartes, les ensembles et bien plus encore. Ils sont plus propres et plus faciles à lire.
Si vous êtes bloqué avec Java 6 ou 7, vous pouvez utiliser la classe Collections2, qui possède des méthodes telles que filter et transform. Ils vous permettent d'écrire du code fluide sans la prise en charge du flux Java 8.
Guava a aussi des choses simples, comme un menuisier qui joint des chaînes sur des séparateurs et une classe pour gérer les interruptions en les ignorant.
La bibliothèque Gson de Google est une bibliothèque d'analyse JSON simple et rapide. Cela fonctionne comme ceci :
final Gson gson = new Gson ();
final String json = gson . toJson ( fooWidget );
final FooWidget newFooWidget = gson . fromJson ( json , FooWidget . class );
C'est vraiment facile et c'est un plaisir de travailler avec. Le guide de l'utilisateur de Gson contient de nombreux autres exemples.
L’un de mes ennuis récurrents avec Java est qu’il n’a pas de tuples intégrés dans la bibliothèque standard. Heureusement, le projet Java tuples corrige ce problème.
C'est simple à utiliser et fonctionne très bien :
Pair < String , Integer > func ( String input ) {
// something...
return Pair . with ( stringResult , intResult );
}
Javaslang est une bibliothèque fonctionnelle conçue pour ajouter des fonctionnalités manquantes qui auraient dû faire partie de Java 8. Certaines de ces fonctionnalités sont
Il existe plusieurs bibliothèques Java qui dépendent des collections Java originales. Celles-ci sont limitées pour rester compatibles avec les classes créées avec une orientation objet et conçues pour être mutables. Les collections Javaslang pour Java sont une toute nouvelle approche, inspirée de Haskell, Clojure et Scala. Ils sont créés avec une orientation fonctionnelle et suivent un design immuable.
Un code comme celui-ci est automatiquement thread-safe et sans try-catch :
// 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 est de loin la meilleure bibliothèque temporelle que j'ai jamais utilisée. Simple, direct, facile à tester. Que pouvez-vous demander d’autre ?
Vous n'en avez besoin que si vous n'êtes pas encore sur Java 8, car celui-ci possède sa propre nouvelle bibliothèque de temps qui n'est pas nulle.
Lombok est une bibliothèque intéressante. Grâce aux annotations, il permet de réduire le passe-partout dont Java souffre tant.
Vous voulez des setters et des getters pour vos variables de classe ? Simple:
public class Foo {
@ Getter @ Setter private int var ;
}
Maintenant, vous pouvez faire ceci :
final Foo foo = new Foo ();
foo . setVar ( 5 );
Et il y a bien plus encore. Je n'ai pas encore utilisé Lombok en production, mais j'ai hâte de le faire.
Bonnes alternatives : Jersey ou Spark
Il existe deux camps principaux pour créer des services Web RESTful en Java : JAX-RS et tout le reste.
JAX-RS est la méthode traditionnelle. Vous combinez des annotations avec des interfaces et des implémentations pour former le service Web en utilisant quelque chose comme Jersey. Ce qui est bien, c'est que vous pouvez facilement créer des clients à partir uniquement de la classe d'interface.
Le framework Play est une approche radicalement différente des services Web sur la JVM : vous disposez d'un fichier de routes, puis vous écrivez les classes référencées dans ces routes. Il s'agit en fait d'un framework MVC complet, mais vous pouvez facilement l'utiliser uniquement pour les services Web REST.
Il est disponible pour Java et Scala. Il souffre légèrement d'être Scala-first, mais il est toujours bon à utiliser en Java.
Si vous êtes habitué aux micro-frameworks comme Flask en Python, Spark vous sera très familier. Cela fonctionne particulièrement bien avec Java 8.
Il existe de nombreuses solutions de journalisation Java. Mon préféré est SLF4J car il est extrêmement enfichable et peut combiner simultanément des journaux de nombreux frameworks de journalisation différents. Vous avez un projet étrange qui utilise java.util.logging, JCL et log4j ? SLF4J est fait pour vous.
Le manuel de deux pages est à peu près tout ce dont vous aurez besoin pour commencer.
Je n'aime pas les frameworks ORM lourds parce que j'aime SQL. J'ai donc écrit beaucoup de modèles JDBC et c'était assez difficile à maintenir. jOOQ est une bien meilleure solution.
Il vous permet d'écrire du SQL en Java de manière sécurisée :
// 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 ();
En utilisant ceci et le modèle DAO, vous pouvez faciliter l'accès à la base de données.
Les tests sont essentiels pour votre logiciel. Ces packages facilitent les choses.
Bonne alternative : TestNG.
jUnit n'a pas besoin d'être présenté. C'est l'outil standard pour les tests unitaires en Java.
Mais vous n’utilisez probablement pas jUnit à son plein potentiel. jUnit prend en charge les tests paramétrés, les règles pour vous empêcher d'écrire autant de passe-partout, les théories pour tester certains codes de manière aléatoire et les hypothèses.
Si vous avez effectué votre injection de dépendances, c'est là que cela porte ses fruits : se moquer du code qui a des effets secondaires (comme parler à un serveur REST) tout en affirmant le comportement du code qui l'appelle.
jMock est l'outil de simulation standard pour Java. Cela ressemble à ceci :
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 ();
}
}
Cela configure une FooWidgetDependency via jMock, puis ajoute des attentes. Nous nous attendons à ce que la méthode call de dep soit appelée une fois avec une chaîne et que la méthode optionnelleCall de dep soit appelée zéro ou plusieurs fois.
Si vous devez configurer la même dépendance encore et encore, vous devriez probablement la mettre dans un appareil de test et mettre assertIsSatisfied dans un appareil @After .
Avez-vous déjà fait cela avec 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" ));
C’est juste un passe-partout ennuyeux. AssertJ résout ce problème. Vous pouvez transformer le même code en ceci :
assertThat ( some . testMethod ()). hasSize ( 4 )
. contains ( "some result" , "some other result" )
. doesNotContain ( "shouldn't be here" );
Cette interface fluide rend vos tests plus lisibles. Que demander de plus ?
Bonnes alternatives : Eclipse et Netbeans
Le meilleur IDE Java est IntelliJ IDEA. Il possède une tonne de fonctionnalités impressionnantes et constitue vraiment la principale chose qui rend la verbosité de Java supportable. La saisie semi-automatique est géniale, les inspections sont de premier ordre et les outils de refactoring sont vraiment utiles.
L'édition communautaire gratuite me suffit, mais l'édition Ultimate contient de nombreuses fonctionnalités intéressantes telles que les outils de base de données, la prise en charge de Spring Framework et Chronon.
L'une de mes fonctionnalités préférées de GDB 7 était la possibilité de voyager dans le temps lors du débogage. Ceci est possible avec le plugin Chronon IntelliJ lorsque vous obtenez l'édition Ultimate.
Vous obtenez l’historique des variables, un retour en arrière, l’historique des méthodes et bien plus encore. C'est un peu étrange à utiliser la première fois, mais cela peut aider à déboguer certains bugs vraiment complexes, les Heisenbugs, etc.
Bonne alternative : DCEVM
L'intégration continue est souvent un objectif des produits Software-as-a-Service. Et si vous n'aviez même pas besoin d'attendre la fin de la construction pour voir les modifications du code en direct ?
C'est ce que fait JRebel. Une fois que vous avez connecté votre serveur à votre client JRebel, vous pouvez voir instantanément les modifications sur votre serveur. C'est un énorme gain de temps lorsque l'on souhaite expérimenter rapidement.
Le système de types de Java est assez faible. Il ne fait pas de différence entre les chaînes et les chaînes qui sont en réalité des expressions régulières, et ne vérifie pas non plus les contaminations. Cependant, Checker Framework fait cela et bien plus encore.
Il utilise des annotations comme @Nullable pour vérifier les types. Vous pouvez même définir vos propres annotations pour rendre l'analyse statique encore plus puissante.
Même en suivant les meilleures pratiques, même le meilleur développeur commettra des erreurs. Il existe un certain nombre d'outils que vous pouvez utiliser pour valider votre code Java afin de détecter les problèmes dans votre code. Vous trouverez ci-dessous une petite sélection de certains des outils les plus populaires. Beaucoup d'entre eux s'intègrent aux IDE populaires tels qu'Eclipse ou IntelliJ, vous permettant de détecter plus tôt les erreurs dans votre code.
En plus d'utiliser ces outils pendant le développement, il est souvent judicieux de les exécuter également pendant vos étapes de construction. Ils peuvent être liés à des outils de construction tels que Maven ou Gradle, ainsi qu'à des outils d'intégration continue.
Des fuites de mémoire se produisent, même en Java. Heureusement, il existe des outils pour cela. Le meilleur outil que j'ai utilisé pour résoudre ces problèmes est l'analyseur de mémoire Eclipse. Cela nécessite un vidage du tas et vous permet de trouver le problème.
Il existe plusieurs façons d'obtenir un vidage de tas pour un processus JVM, mais j'utilise 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
Ensuite, vous pouvez ouvrir le fichier heapdump.hprof avec Memory Analyzer et voir rapidement ce qui se passe.
Ressources pour vous aider à devenir un maître Java.