Packages, application java

Packages, java namespace

Package = ensemble de classes (ou d'interfaces) ; sert à regrouper du code et à fournir un espace de nommage (namespace) aux classes qu'ils contiennent.

Par convention, les noms de packages sont en lettres minuscules.

Utilités :
- Eviter les collisions de nom.
- Organiser son code en sous-ensembles cohérents.
- Permet aux classes et méthodes d'avoir une visibilité package, importante dans des gros programmes.

NOTE : concevoir ses packages en n'utilisant qu'un nombre mimimum de classes publiques est conseillé, afin de renforcer l'encapsulation au niveau package.
Si une classe n'a pas vocation a être utilisée par d'autres package, donnez-lui une visibilité package : simplifie l'API publique et vous permet de faire évoluer le package sans perturber le code client.
Exemple : Comparer la doc du package javax.swing.colorchooser et le code source.

Les classes centrales de l'API sont dans un package qui commence par java. En particulier java.lang et java.util, aussi java.io, java.net.
javax* = eXtensions qui ont été intégrées à la plateforme.
Oracle contrôle les packages commençant par java, javax, sun.

Une classe a donc à la fois un nom simple et un fully qualified name.
Nom simple : System Fully qualified name : java.lang.System

2 classes de même nom simple ne peuvent être différenciées que par leur fully qualified name, par exemple java.util.List et java.awt.List.
Par défaut, pour référencer une classe dans le code, il faut utilser son fully qualified name, à 3 exceptions :
- les classes de java.lang
- les classes du package courant
- les classes qui ont été importées dans la package courant avec la déclaration import.

Une toute petite application peut être écrite dans un répertoire sans spécifier le package, elle se trouve dans le package par défaut.
Mais dès qu'une application grossit, elle est packagée ; le nom du package courant est spécifié en utilisant l'instruction package.

Les clauses import doivent apparaître en début de fichier, juste après la clause package.
package myapp.mypackage;

import java.io.File;    // single type import
import java.io.*;       // on-demand type import - ne s'applique pas aux sub-packages
On-demand import équivalent à simple type import uniquement pour les classes que l'on utilse.

Conflits

import java.util.List;
import java.awt.List;
Génère une erreur de compilation.
import java.util.*;
import java.awt.*;
est légal, mais l'utilisation de List dans le code génère une erreur de compilation.
Dans ce cas, on peut faire :
import java.util.*;
import java.awt.*;
import java.util.List; // pour lever l'ambiguïté
Dans le code, l'identifiant "List" désignera une java.util.List et pour utiliser java.awt.List, on doit faire :
java.awt.List = new java.awt.List(...)

import static

Introduit en java 5.
Les imports "normaux" permettent d'importer des noms de types référence (classes, interfaces...).
Les imports static permettent d'importer les membres statiques (variables et méthodes) d'une classe, en faisant :
import static java.lang.System.out;
Permet par exemple d'utiliser dans le code out.println() au lieu de System.out.println().
Utilisation courante :
import static java.lang.Math.*;
// permet de remplacer :
Math.sqrt(Math.abs(Math.sin(x)))
// par 
sqrt(abs(sin(x)))
Aussi utile pour les constantes (utiliser PI au lieu de Math.PI).

Mais ATTENTION, à utiliser avec parcimonie car diminue la lisibilité du code : il faut faire des efforts pour savoir si une variable est locale ou vient d'un import static (pire en cas de multiples import static *). Favoriser l'import des variables une par une plutôt que la syntaxe avec *.

Structure d'une application java

En java, le code est écrit dans des fichiers .java.
Les fichiers .java doivent être compilés (transformés en bytecode lisible par la JVM) en utilisant javac. Le bytecode est stocké dans des fichiers .class.
La (quasi ?) totalité des projets java stocke les .java et les .class dans deux dossiers séparés.
La structure typique d'un projet java est :
projet/
    ├── bin             // contient les .class
    └── src             // contient les .java
Il y a obligatoirement une correspondance entre la hiérarchie des packages et la hiérarchie des fichiers.

Exemple :
src/
    └── projet
        ├── package1
        │   └── Class1.java    <- package projet.package1;
        ├── package2
        │   └── Class2.java    <- package projet.package2
        └── Projet.java        <- package projet;

La même hiérarchie se trouve dans bin/ :
bin/
    └── projet
        ├── package1
        │   └── Class1.class
        ├── package2
        │   └── Class2.class
        └── Projet.class
Une manière assez répandue de nommer les packages utilise l'url de(s) auteur(s) pour former le nom du package principal.
Par exemple http://commons.apache.org met ses projets dans les packages
org.apache.commons.projet1
org.apache.commons.projet2
Ce qui correspond à une hiérarchie de fichiers org/apache/commons/projet1 et org/apache/commons/projet2

Modules

La notion de module a été introduite en java 9. Un module regroupe un ou plusieurs packages.
Java SE a été découpé en modules, ce qui permet de déployer une application en n'incluant que les modules utiles.
Voir https://www.oracle.com/corporate/features/understanding-java-9-modules.html