Outils java

Programmer en java

On a besoin d'avoir un JDK installé sur la machine de développement ; voir https://www.java.com/en/download/help/index_installing.xml.
Les utilisateurs de programmes écrits en java n'ont pas besoin du JDK sur leur machine, mais uniquement d'un JRE.

Il existe de nombreux éditeurs intégrés pour java, comme Netbeans, Eclipse, IntelliJ IDEA... Ces outils utilisent en interne les outils fournis par le JDK.
Dans ce cours, on utilisera Eclipse mais dans un premier temps, on va utiliser javac et java en ligne de commande.

Les outils du JDK

Le JDK fournit des outils pour développer et déployer des applications java
Dans ce cours, on va surtout utiliser les deux principaux outils :
- javac, le compilateur.
- java, l'interpréteur.
On verra aussi rapidement d'autres outils :
- javadoc, pour générer de la documentation.
- jshell, pour tester des aspects du langages ou écrire du code jetable (depuis java 9).

La documentation est accessible en ligne : https://docs.oracle.com/javase/10/tools/tools-and-command-reference.htm.
La doc est aussi accesible par la comande man, par ex :
man javac
Ces outils ont un grand nombre d'options, on ne verra que celles qui sont nécessaires au début, on complètera suivant les besoins, par ex pour les types génériques.
Note valable aussi pour tous les outils : lorsqu'on spécifie le nom d'un répertoire, on peut indiquer un chemin absolu ou un chemin relatif au répertoire courant (l'endroit d'où est lancé la commande).
En l'absence de l'option, l'outil considère qu'il s'agit du répertoire courant.

Classpath

Pour fonctionner, la plupart des outils du JDK ont besoin de savoir où aller chercher les classes dont ils ont besoin.
Ces classes se trouvent soit dans des fichiers .class ou dans des .jar (java archives).
L'ensemble des chemins (répertoires) à utiliser s'appelle le classpath.
Il faut donc indiquer le classpath pour :
- Les classes du JDK ou du JRE.
- Les classes des libs utilisées par le programme.
- Les classes constituant le programme sur lequel on travaille.

Variables d'environnement

Permettent d'intégrer java au système d'exploitation.
La variable CLASSPATH contient le chemin vers les classes du JRE, donc on n'a pas besoin de les répéter lorsqu'on spécifie le classpath.
(mais cela permet d'utiliser différentes versions de java sur une même machine).

Windows
JAVA_HOME : C:\Program Files\Java\jdk1.8.0_112
JDK_HOME  : %JAVA_HOME%
JRE_HOME  : %JAVA_HOME%\jre
CLASSPATH : .;%JAVA_HOME%\lib;%JAVA_HOME%\jre\lib
PATH      : your-unique-entries;%JAVA_HOME%\bin
Linux
JAVA_HOME : /usr/lib/jvm/java-11-openjdk-amd64
JDK_HOME  : $JAVA_HOME
JRE_HOME  : $JAVA_HOME/jre
CLASSPATH : .:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
PATH      : your-unique-entries:$JAVA_HOME/bin

Compilation - javac

Les deux principales options sont :
- où aller chercher les fichiers source .java (-sourcepath).
- le classpath (-classpath ou -cp).
- le répertoire de destination, où les fichiers .class générés doivent être stockés (-d).

Avec cette structure :
projet
    ├── bin
    └── src
        └── projet
            ├── package1
            │   └── Class1.java
            ├── package2
            │   └── Class2.java
            └── Projet.java

Si on se trouve dans le répertoire projet/
javac -sourcepath src/ -d bin/ src/projet/Projet.java
Note : javac va chercher à compiler les .java qu'on lui spécifie et compile automatiquement les autres fichiers nécessaires (à partir des instructions import, du sourcepath et du classpath).

Si le code utilisait des libs situés dans un répertoire contenant des fichiers .class /path/to/lib1/bin et dans un jar /path/to/lib2.jar :
javac -sourcepath src/ -classpath /path/to/lib1/bin:/path/to/lib2.jar -d bin/ src/projet/Projet.java
(pour spécifier plusieurs répertoires, on utilise les séparateurs : sous linux et ; sous windows).

Autres options utilisées :
-Xlint:deprecation
-Xlint:unchecked (voir types génériques)

Exécution - java

On utilise surtout l'option -classpath (ou -cp).

2 formes possibles : Les argument suivant le nom de la classe ou le nom du fichier jar sont transmis au programme par le biais du paramètre args de la méthode main().

Depuis java 11, il est possible de compiler et d'exécuter un programme java en une seule instruction :
java HelloWorld.java
ATTENTION : cela n'est possible que pour des petits programmes, constitués d'un seul fichier.

Documentation - javadoc

Page d'accueil officielle ; voir notamment How to Write Doc Comments for Javadoc et Requirements for Writing API Specifications.

La documentation des classes, interfaces et membres des classes (variables et méthodes) se font dans les commentaires javadoc /** */.
L'outil javadoc reconnait un certain nombre de tags javadoc, identifiés par @ (arobase).
javadoc convertit la documentation en html, il est donc possible d'utiliser des tags html dans la documentation (<i>, <code>, <pre>, <ul>, <li>, <p> ...).
Penser que la doc que vous écrivez va faire partie d'un html généré, donc éviter les tags html de structure (<h2>, <h3> ...) ; utiliser par exemple &lt; au lieu de < (voir plus loin le tag javadoc {@literal).

Il est aussi possible d'écrire une présentation de l'application dans un fichier overview.html situé dans le top-level package, ainsi qu'une doc pour chaque package, située dans le répertoire du package, dans un fichier package.html.

Un bon endroit pour trouver des exemples de documentation est le code source de open JDK.

Documenter une classe, une interface

La documentation d'une classe ou interface se trouve dans le commentaire javadoc précédant la déclaration de la classe.
/** 
    Une phrase d'introduction, qui apparaitra dans les pages de résumé.
    Une description plus précise de la classe, qui peut s'étaler sur plusieurs lignes.
    @author Auteur 1
    @author Auteur 2
    @version 2017-01-02
*/
public class MyClass{
    ...
}

Documenter une méthode

public class MyClass{
    
    /**
        Une phrase de résumé.
        Une description plus précise de la méthode, qui peut s'étaler sur plusieurs lignes.
        
        @param  param1  Description du premier paramètre
        @param  param2  Description du second paramètre
        
        @return Description du retour de la méthode
        
        @throws IllegalArgumentException    Description de l'exception
        @throws IOException                 Description de l'exception
        
        @see    java.util.List
    */
    public static int method1(int param1, String param2) throws IllegalArgumentException, IOException{
        
    }
}

Liens entre les pages, inline doc-comment tags

On appelle inline doc-comment tags des tags javadoc utilisés à l'intérieur des descriptions ; ils sont repérés par des accolades { ... }.

On n'utilise très peu la balise html <a> pour faire des liens internes à la doc, mais des tags javadoc spéciaux.
{@link reference } ou {@linkplain reference }
    @param regexp   The regular expression to search for. This string
                    argument must follow the syntax rules described for
                    {@link java.util.regex.Pattern}.
La syntaxe de reference s'applique à @see et aux inline tags {@link} {@linkplain} et {@value} et peut prendre plusieurs formes : Pour inclure des images ou des liens vers des fichiers, la convention est de les mettre dans un dossier nommé doc-files (un tel dossier dans chaque package).
Par exemple :
appli
    ├── overview.html
    ├── package1
    │   ├── doc-files
    │   │   └── image1.jpg
    │   └── package.html
    └── package2
        └── package.html
Dans ce cas, la doc de package1 contient des images, donc on crée un dossier doc-files, mais on ne le crée pas dans package2 si on n'en a pas besoin.
Dans package1/package.html ou dans la doc des classes contenues dans package1, on peut inclure des images avec un lien relatif :
<img src="doc-files/image1.jpg" alt="Description texte">

Le tag {@docRoot} peut être utile : <img src="{@docroot}/images/logo.gif"> (lien vers la racine de la doc générée).

{@literal text } ou {@code text } servent à inclure du html ou des tags javadoc dans une doc.

Tests - jshell

Depuis java 9, le JDK fournit un outil REPL (Read Eval Print Loop), qui permet de tester du code java sans avoir besoin d'écrire un programme de test.
En ligne de commande, il suffit de taper :
jshell -v
On se retrouve dans un environnement de programmation :
|  Welcome to JShell -- Version 10.0.2
|  For an introduction type: /help intro

jshell> 
L'option -v fait fonctionner jshell en mode verbeux ; pratique pour connaître le type des variables manipulées.
On peut en sortir en tapant
/set feedback normal
Comme dans toute application en ligne de commande :
la flèche du haut permet de retrouver les saisies précédentes
Ctrl R permet de recherche dans l'historique des commandes
Ctrl C permet d'annuler une saisie en cours
Ctrl D permet de sortir de jshell (identique à /exit)

Imports par défaut

Certains packages sont inclus par défaut, qu'on peut connaître en tapant /import :
jshell> /import
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.nio.file.*
|    import java.util.*
|    import java.util.concurrent.*
|    import java.util.function.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.util.stream.*
Pour importer d'autres packages, on tape la commande java usuelle
jshell> import java.lang.reflect.*

Expressions

jshell permet d'évaluer des expressions.
Pratique par exemple pour savoir comment java se comporte dans les conversions automatiques de type :
jshell> 1+1
$1 ==> 2
|  created scratch variable $1 : int

jshell> 1+1.0
$2 ==> 2.0
|  created scratch variable $2 : double
jshell> 1/2
$4 ==> 0
|  created scratch variable $4 : int

jshell> 1/2.0
$5 ==> 0.5
|  created scratch variable $5 : double

jshell> 1.0/2
$6 ==> 0.5
|  created scratch variable $6 : double

jshell> 1.0f/2
$7 ==> 0.5
|  created scratch variable $7 : float
Peut être aussi utile pour connaître la valeur de constantes.
jshell> Math.PI
$3 ==> 3.141592653589793
|  created scratch variable $3 : double

Variables

On peut créer des variables et les réutiliser
jshell> int x = 5
x ==> 5
|  created variable x : int

jshell> x
x ==> 5
|  value of x : int

Méthodes

On peut créer des méthodes et les appeler
jshell> void hello(){System.out.println("hello");}
|  created method hello()

jshell> hello()
hello
On peut aller à la ligne en définissant la méthode :
jshell> int add4(int nb){
   ...> return nb + 4;
   ...> }
|  created method add4(int)

jshell> add4(5)
$17 ==> 9
|  created scratch variable $17 : int

Commandes

Une ligne commençant par / est considérée comme une commande jshell (ex : /imports).
Pour la liste des commandes disponibles :
jshell> /help
Commandes utiles
/vars liste les variables définies.
/methods liste les méthodes définies.