Les FAQs Java :
FAQ JAVA FAQ Java EE FAQ Java ME FAQ Java XML FAQ JavaFX FAQ Java GUI FAQ Struts FAQ JSF FAQ JDBC JDO FAQ Hibernate FAQ Spring FAQ Eclipse FAQ NetBeans FAQ JCreator FAQ Maven 2

FAQ JavaConsultez toutes les FAQ

Nombre d'auteurs : 53, nombre de questions : 231, dernière mise à jour : 26 janvier 2014 

 
OuvrirSommaireAstuces et divers

1. On récupère un InputStream sur le fichier TTF

 
Sélectionnez

InputStream ttf;

- depuis une servlet, le fichier TTF est dans le répertoire /fonts/ du war :

 
Sélectionnez

ttf = getServletContext().getResourceAsStream("fonts/ARIALN.TTF");

- depuis le système de fichiers :

 
Sélectionnez

ttf = new FileInputStream("/aaa/bbb/ccc/ARIALN.TTF");

2. On crée une Font :

 
Sélectionnez

Font arialNarrow;
try {
   arialNarrow = Font.createFont(Font.TRUETYPE_FONT, ttf);
}
catch (Exception e) { //Une solution de rechange, au cas où...
   arialNarrow = new Font("Arial", Font.PLAIN, 1);
}
finally {
   try {
      ttf.close();
   }
   catch (Exception ignore) {}
}

3. La Font obtenue est de taille 1. Ce qui n'est pas terrible. On utilise alors deriveFont pour en créer des dérivées. Par exemple, on obtient du arial narrow grassouillet avec :

 
Sélectionnez

Font arialNarrowBold = arialNarrow.deriveFont(Font.BOLD);

Si besoin, créer une version avec ITALIC... Maintenant avec nos polices de bases, il suffit de modifier la taille.

 
Sélectionnez

BufferedImage bi = ImageIO.read("fichier.jpg");
Graphics2D g2d = bi.createGraphics();
//Antialiasing
g2d.setRenderingHint(
   RenderingHints.KEY_TEXT_ANTIALIASING,
   RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setFont(arialNarrow.deriveFont(48f));
//et maintenant on peut écrire en Arial Narrow de taille 48
g2d.setFont(arialNarrowBold.deriveFont(24f));
//et  du Arial Narrow gras taille 24

Le petit f, c'est pour float, deriveFont accepte un int pour BOLD, ITALIC, PLAIN (qui sont des int), ou un float pour modifier la taille.

Créé le 7 juillet 2005  par iubito

Depuis Java SE 6, il est possible de placer des icônes dans le "system tray" du bureau. Toutefois cette fonctionnalité étant fortement dépendante du système d'exploitation et de son bureau, elle n'est pas forcément supporté dans tous les cas.

Voici un exemple de code permettant d'ajouter une icône dans le "systray" :

 
Sélectionnez

	// On vérifie que le "systray" est supporté
	// par la JVM pour ce système d'exploitation
	if (SystemTray.isSupported()) {
 
 
		// On Crée un TrayIcon qui représentera notre icône :
		TrayIcon trayIcon = new TrayIcon(
				image,		// L'image qui sera utilisé comme icône
				tooltip, 	// Le texte affiché lors du survol de la souris
				popup		// Le PopupMenu qui s'affichera lors du clic droit
				);
 
		// On active le redimensionnement automatique de
		// l'icône, afin qu'elle s'adapte au système
		// (sinon l'icône peut être tronqué ou disproportionné)
		trayIcon.setImageAutoSize(true);
 
		// On récupère l'instance du SystemTray
		SystemTray systemTray = SystemTray.getSystemTray();
 
		// Et on ajoute notre TrayIcon dans le system tray
		systemTray.add(trayIcon);
	}

A noter qu'une fois que l'icône est présente dans le systray, on peut l'utiliser pour afficher une infobulle :

 
Sélectionnez

trayIcon.displayMessage(
			"Titre",			// Titre de la bulle
			"Message",			// Contenu du message 
			MessageType.INFO	// Style de l'icone
		);

Pour les versions antérieurs à Java SE 6, plusieurs API (plus ou moins portables), utilisant JNI, existent pour pallier à ce manque :

Mis à jour le 25 août 2007  par Ioan Calapodescu, adiGuba

Lien : Les classes Desktop et SystemTray, des alternatives à JDIC, par Baptiste Wicht

La classe abstraite Preferences du package java.util.prefs permet d'enregistrer facilement certaines données. Les implémentations dépendent du système (registres, SGBD, fichiers, etc.), mais ceci est invisible pour l'utilisateur. Plusieurs niveaux de préférences peuvent être définis. Ceux-ci sont accessibles grâce aux méthodes statiques de la classe Preferences.

Niveaux de Preferences

  • Preferences.systemRoot() : préférences globales du système.
  • Preferences.systemNodeForPackage(Class c) : préférences du système pour une classe donnée.
  • Preferences.userRoot() : préférences globales de l'utilisateur.
  • Preferences.userNodeForPackage(Class c) : préférences globales de l'utilisateur pour une classe donnée.

Les Preferences associent à une clef (String) une valeur. On peut stocker dans les Preferences tout type primitif. Voici les méthodes correspondantes à :

La lecture de Preferences

 
Sélectionnez

Preferences prefs = Preferences.systemRoot();
String unString = prefs.get("uneClef","une valeur par défaut si il n'y a pas de valeur");
// on peut aussi récuperer d'autres types primitifs
int unInt = prefs.getInt("clefInt",123);
// on doit toujours spécifier une valeur par défaut

L'écriture de Preferences

 
Sélectionnez

Preferences prefs = Preferences.systemRoot();
prefs.put("clef","valeur");
prefs.putInt("clefInt",456);

Pour un exemple plus complet, regardez le fichier ci-dessous. Il consiste en une fenêtre capable de "mémoriser" sa position, sa taille et son état (maximisée, iconifiée, etc.).

Créé le 12 août 2004  par Ioan Calapodescu

Téléchargement : Exemple

Vous trouverez toutes les informations nécessaires sur le lien suivant :

Créé le 9 mai 2002  par L'équipe Java

Lien : https://java.net/projects/javamail/pages/Home

De nombreux formats de fichiers textes peuvent être utilisés avec Java. Malheureusement, tous ne sont pas utilisables grâce à l'API standard. Voici quelques formats et les API qui peuvent les utiliser :

Format API Remarques
HTML API Standard Cf. HTMLEditorKit, JEditorPane et JTextPane
RTF API Standard Cf. RTFEditorKit, JEditorPane et JTextPane
XML API Standard (SAX, DOM) Il existe de nombreuses librairies facilitant le travail avec ce type de documents
PDF iText, FOP Ces deux librairies sont utilisées seulement pour la génération
Excel POI, JExcelAPI  
Word POI  
Créé le 19 juillet 2004  par duj, Ioan Calapodescu


Cas de figure :
Un composant donné a besoin d'informer un ou plusieurs composants externes que certains événements se sont produits.


Un petit exemple :
Le composant MonBouton a besoin d'informer une liste d'objets que le bouton gauche de la souris est appuyé et que le bouton de la souris a été relaché.


Définir une nouvelle interface :

 
Sélectionnez

			public interface MonBoutonMouseListener extends EventListener {
			        public void boutonGauchePresse (EventObject e);
			        public void boutonGaucheRelache (EventObject e);
			} 
			


class monBoutton :

 
Sélectionnez

			/** import nécessaire : */
			import javax.swing.event.EventListenerList;
 
			/** attribut : */
			protected EventListenerList listenerList;
 
			/** instanciation nécessaire : (à faire dans son constructeur
			 * ou dans une méthode appelée par le constructeur)
			 */
			this.listenerList = new EventListenerList ();
 
			/** méthode à faire :
			 * permet d'ajouter un composant dans la liste de ceux qui veulent
			 * être informés de l'évènement
			 */
			public void addMonBoutonMouseListener (MonBoutonMouseListener l) {
			        this.listenerList.add (MonBoutonMouseListener.class, l);
			} 
 
			/** enlève un objet qui est actuellement écouteur de l'évènement */
			public void removeMonBoutonMouseListener (MonBoutonMouseListener l) {
			        this.listenerList.remove (MonBoutonMouseListener.class, l);
			} 
 
			/** lance un évènement à tous les objets écouteurs
			 * (== appelle la méthode boutonGauchePresse sur tous les objets
			 * écouteurs de la liste)
			 */
			protected void fireboutonGauchePresse () {
			        MonBoutonMouseListener [] listeners = (MonBoutonMouseListener [])
			                 listenerList.getListeners( MonBoutonMouseListener.class);
			        EventObject e = new EventObject (this);
			        for (int i = listeners.length-1; i>=0; i--) {
			                listeners [i].boutonGauchePresse (e);
			        } 
			} 
 
			


Il suffit ensuite d'appeler cette méthode à chaque fois que l'évènement approprié est généré.

Mis à jour le 25 mars 2007  par Johann Heymes

Téléchargement : Exemple d'implémentation.

En Java les types de base sont passés aux méthodes par valeur, ils ne peuvent pas être modifiés. Il va falloir utiliser une instance de classe "encapsulant" un entier pour effectuer la modification. Attention la classe fournie Integer ne permet pas la modification et est donc inutile dans ce cas.

Exemple :

 
Sélectionnez

class MonEntier {
        /** champ privé : */
        private int value;
 
        /** mise à jour de la valeur */
        public void setValue(int newValue) {
                value = newValue;
        } 
 
        /** Acces à la valeur */
        public int getValue() {
                return( value);
        } 
} 

Dans la méthode maMethode faire :

 
Sélectionnez

public void maMethode (MonEntier i) {
        i.setValue(maNouvelleValeur);
} 
Créé le 28 mars 2002  par Clément Cunin

Contrôle-C, kill -2, kill -15 et autres sont des méthodes permettant d'arrêter l'exécution du programme sans lui demander son avis. Pourtant, il est parfois nécessaire de faire au moins quelques instructions capitales telles que la fermeture de flux de fichier, d'une connexion réseaux ou une sauvegarde rapide. Pour se faire il est possible de définir un 'ShutdownHook' ce qui se traduit par un thread exécuté à la réception du signal de fin d'exécution.

Attention : Ce traitement final sera également éxécuté lors de l'arrêt normal de l'application.

Cette astuce ne marche malheureusement pas pour le code kill -9.

Mis à jour le 25 mars 2007  par Johann Heymes

Téléchargement : Exemple d'implémentation.

Le garbage Collector (rammasse miette) est la partie de la JVM qui s'occupe de la récupération des zones mémoires. Les phases de libération de la mémoire sont gérées de façon autonome, il est inutile de lui dire quand passer.

Il existe néanmoins la fonction gc de la classe java.lang.System qui permet de faire un appel explicite au garbage collector. Cet appel ne garantit pas que tous les objets inutiles seront supprimés de la mémoire.

 
Sélectionnez

System.gc ();
//Appel explicite au Garbage collector

Néanmoins, cette méthode ne garantit par le passage du GC. Elle permet seulement d'augmenter la propabilité que le GC se déclenche. Il est préférable de mieux gérer ses objets plutôt que d'utiliser cette méthode.

Mis à jour le 1er mai 2008  par Clément Cunin

Voici trois solutions :

1ère solution :

 
Sélectionnez

public class MonEnum {
        public final static int Val1=0;
        public final static int Val2=1;
        public final static int Val3=2;
} 

On peut ensuite utiliser MonEnum.Val1, MonEnum.Val2 etc, ou mieux on peut faire une interface plutôt qu'une classe afin que les classes l'implémentant puissent directement appeler Val1, Val2...

Le problème reste le typage des éléments, rien n'empêche de passer un objet d'une énumération à la place d'une autre.

2ème solution :
Cette deuxième catégorie de solutions, plus complexes, permet d'éviter ce problème. On peut par exemple penser à utiliser des instances de classes :

 
Sélectionnez

public final class MonEnum1 {
        private MonEnum1() {
                /** Rien à faire */
        } 
 
        /** liste des valeurs */
        public final static MonEnum1 Val1 = new MonEnum1();
        public final static MonEnum1 Val2 = new MonEnum1();
        public final static MonEnum1 Val3 = new MonEnum1();
} 

Ainsi un éventuel objet de type MonEnum2 ne pourra jamais être utilisé à la place d'un objet de type Enum1 (Enum1.Val1 Enum1.Val2 ...).

2ème bis solution :
La 2ème solution pose un autre problème, il reste possible d'utiliser la valeur 'null' alors que celle-ci n'appartient pas au domaine de notre énumération. Pour ce faire, rien de plus simple, si on considère val1 comme la valeur par défaut, on la déclare de la manière suivante :

 
Sélectionnez
public final static Enum1 val1 = null;

De cette manière il devient totalement impossible de passé un Enum1 non reconnu !

3ème solution :
Depuis Java 5.0, vous pouvez utiliser le mot-clé enum pour créer des énumérations. Voilà comment vous pouvez procéder pour créer un énumération :

 
Sélectionnez

enum Align{ 
	LEFT,
	RIGHT, 
	CENTER,
	JUSTIFIED 
};

Vous pouvez accéder aux valeurs ainsi :

 
Sélectionnez

Align.LEFT;
Align.RIGHT;

Conclusion :
Si vous avez Java 5.0 ou une version plus récente, il vous faut utiliser la solution 3.

Mis à jour le 2 juin 2007  par Clément Cunin

Lien : http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/enums/Enum.html
Lien : Plus d'infos sur les enums

Si les paramètres passés au constructeur sont incohérents ou que la construction provoque une erreur, la création de l'objet est impossible et doit être annulée. Comme les méthodes, les constructeurs peuvent lever des exceptions, c'est la façon la plus simple d'annuler l'exécution du constructeur. Techniquement, l'objet est créer en mémoire (l'allocation de la mémoire a lieu au moment de l'appel du constructeur) mais l'appelant étant obligé de traiter l'exception, le pointeur vers cette objet est perdu et sera donc recupéré par le ramasse-miettes.

Une solution plus élégante consiste à utiliser par une méthode statique qui verifie les paramètres et ne fait l'appel au constructeur que si ceux-ci sont corrects.

 
Sélectionnez

public class Test {
        /** Le constructeur est déclaré protected 
           * pour interdire son utilisation par les clients de la classe. 
           */
        protected Test(int val) {
 
        } 
        public static Test createTest( int val ) {
                if( val<100 ) {
                        return( new Test(val) );
                } else {
                        return( null);
                        /** Ou alors on lève une exception... */
                } 
        } 
} 
Créé le 1er janvier 2004  par Clément Cunin

En utilisant la méthode:

 
Sélectionnez
Class c = Class.forName("com.developpez.MaClasse"); 

On utilise le ClassLoader du système. Ce ClassLoader cache l'information et ne rechargera pas la classe lors d'un nouvel appel a forName, et ce même si le fichier ".class" a changé depuis le dernier chargement.

Il y a deux solutions :

1 - La classe n'est pas présente dans le CLASSPATH C'est le cas le plus simple, il suffit d'utiliser un nouveau URLClassLoader a chaque fois pour recharger une nouvelle version de la classe.

 
Sélectionnez

  // le chemin ou trouver la classe a recharger 
  URL chemins[] = { new URL("file:/C:/MesClasses/") }; 
  URLClassLoader loader = new URLClassLoader(chemins); 
  Class c = loader.loadClass("com.developpez.MaClasse"); 
 

Attention, il faut créer a chaque fois un nouvel URLClassLoader, sinon la classe est cachée par le loader.

Si la classe est présente dans le CLASSPATH c'est le ClassLoader du système qui la charge (et la met dans son cache).

2 - La classe est présente dans le CLASSPATH

Dans ce cas, on ne peut pas utiliser l'URLClassLoader. Il faut créer son propre ClassLoader qui hérite de la classe ClassLoader

 
Sélectionnez

import java.io.InputStream; 
 
public class MonLoader extends ClassLoader 
{ 
 
  public Class loadNewClass(String aName) throws Exception 
  { 
    InputStream is = getClass().getResourceAsStream("/" + aName); 
    if (null == is) 
    { 
      return null; 
    } 
 
    byte buffer[] = new byte[is.available()]; 
    is.read(buffer); 
    Class c = defineClass(aName, buffer, 0, buffer.length); 
    resolveClass(c); 
    return c; 
  } 
} 

Dans ce code, nous avons créé une nouvelle méthode "loadNewClass" qui recharge le fichier ".class" a chaque fois.

Le fait de ne pas avoir redéfini la méthode loadClass permet a ce nouveau ClassLoader d'utiliser le ClassLoader du système pour charger d'eventuelles classes mères ou interfaces.

Si la méthode loadClass est redéfinie il faut qu'elle puisse aussi trouver les super classes et interfaces des classes qui seront chargées, et ce sans recharger celles déjà présentes dans le système.

Créé le 19 juillet 2004  par bulbo

Un singleton est un objet qui ne peut être instancié qu'une seule et unique fois dans le programme.
Pour transformer une classe en singleton, il faut passer les constructeurs en accès private et ajouter au code une instance et un accesseur statiques :

 
Sélectionnez
public class Singleton {
 
    private static Singleton instance = new Singleton();
 
    public static Singleton getInstance() {
        return instance;
    }
 
    private Singleton() {
        //constructeur
    }
 
    //reste de la classe
 
}

Il existe une variante :

 
Sélectionnez
public class Singleton {
 
    private static Singleton instance = null;
 
    public static Singleton getInstance() {
        if(instance == null)
            instance = new Singleton();
        return instance;
    }
 
    private Singleton() {
        //constructeur
    }
 
    //reste de la classe
 
}

Enfin, pour accéder au singleton, il suffit d'appeler :

 
Sélectionnez
Singleton s = Singleton.getInstance();


Il existe encore une dernière variante consistant à utiliser une classe interne statique comme conteneur du singleton :

 
Sélectionnez
public class Something{
     private Something() {
     }
 
     private static class LazyHolder {
         private static final Something something = new Something();
     }
 
     public static Something getInstance(){
         return LazyHolder.something;
     }
}

Attention, toutes ces méthodes sont uniquement adaptées à un environnement mono-thread. Dans le cas où vous avez plusieurs processus, dirigez-vous vers cet article.

Mis à jour le 1er mai 2008  par xavlours, osopardo

Lien : Le Singleton en environnement Multithread

Le double-check locking est un idiome de programmation censé assurer la sécurité du Singleton en environnement multithread.
Attention, ce pattern ne marche pas !

Il peut etre écrit comme suit :

 
Sélectionnez
public static Singleton getInstance(){
  if (instance==null)               
    {
      synchronized (Singleton.class){
        if(instance==null)
          instance=new Singleton();
      }
    }
  return instance;               
}

Bien qu'encore recommandé sur le web, son utilisation est fortement déconseillée.
Pour plus de détails : Le Singleton en environnement Multithread

Créé le 3 avril 2005  par christopheJ

Il existe trois solutions pour sécuriser un Singleton dans un programme multithread :

- Synchroniser toute la méthode getInstance() et payer le coût de la synchronisation à chaque appel
- Utiliser ThreadLocal dont l'implémentation n'est pas plus performante que la synchronisation
- Abandonner la synchronisation et utiliser un initialiseur static quand la construction du Singleton ne nécessite pas de paramètres particuliers.

Pour plus d'informations : Le Singleton en environnement Multithread

Créé le 3 avril 2005  par christopheJ

La méthode toString() de la classe Object affiche le nom de l'objet suivi de la réference de l'objet dans la machine virtuelle (une sorte de pointeur).

Ceci peut s'avérer utile parfois lors d'une phase de deboguage, mais comment faire lorsqu'une classe (comme la classe String par exemple) redéfinie la méthode toString() ?

Il faut passer par la méthode System.identityHashCode(Object).

Le code suivant retourne la même chose que le toString() d'Object pour n'importe quel type d'objet:

 
Sélectionnez
public String getReference(Object anObject){ 
	return anObject.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(anObject));
}
Créé le 12 octobre 2006  par bulbo


System.currentTimeMillis()


En utilisant la méthode statique currentTimeMillis() de la classe System. Cette méthode renvoie un long représentant la différence de temps entre le 1er Janvier 1970 à minuit et le temps système à l'exécution de l'instruction. Cette différence s'exprime en fonction de l'unité de temps de l'OS (la milliseconde, voire quelques dizaines de milliseconde).

 
Sélectionnez

long start = System.currentTimeMillis();
// ... instructions à chronométrer
long duree = System.currentTimeMillis() - start;
System.out.println(duree);


System.nanoTime()


En utilisant la méthode statique nanoTime() de la classe System. Cette méthode n'est disponible que depuis le JDK 5.0. Elle renvoie un long représentant la valeur du timer en nanosecondes.

 
Sélectionnez

long start = System.nanoTime();
// ... instructions à chronométrer
long duree = System.nanoTime() - start;
System.out.println(duree);


Ce temps n'est pas lié à un référentiel de temps universel, aussi on ne doit-on l'employer que pour mesurer une différence de temps. La précision est de l'ordre de la nanoseconde.


Il faut aussi noter que ce n'est pas exactement le temps utilisée par votre application, mais le temps qui s'est écoulée depuis le début à la fin de votre code. Pendant ce temps, d'autres applications tournent sur votre ordinateur et utilisent ce qu'on appelle du temps CPU. Pour connaître exactement le temps CPU nécessaire, il faut utiliser la méthode getCurrentThreadCpuTime() de l'interface java.lang.management.ThreadMXBean à la place de System.nanoTime() ou currentTimeMillis() et vous aurez le temps CPU.

Mis à jour le 12 janvier 2008  par Nourdine Falola, Baptiste Wicht

Avec Java 5.0, on peut utiliser la classe MemoryMXBean de la nouvelle API de management pour obtenir des informations sur l'état de la mémoire. On récupère une instance de MemoryMXBean via le code suivant :

 
Sélectionnez

	MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();

Ensuite, il suffit d'utiliser la méthode getHeapMemoryUsage() qui retournera un objet MemoryUsage contenant le détail de la mémoire utilisé par votre application. Il contient ainsi les informations suivantes :

  • init : La taille initiale de la mémoire utilisé par l'application (généralement 0, sauf si l'on a utilisé l'option -Xms de la JVM).
  • used : La quantité de mémoire qui est réellement utilisée par votre application.
  • committed : La quantité de mémoire qui a été réservée auprès du système d'exploitation.
  • max : La quantité maximale que la JVM est authorisée à réserver auprès du système d'exploitation (modifiable avec l'option -Xmx de la JVM). Si l'application utilise plus de mémoire cela générera une OutOfMemoryError.

L'objet MemoryUsage possède bien entendu toutes les méthodes accésseurs pour accéder à ces éléments, mais également une redéfinition de la méthode toString() afin de les afficher plus simplement. Ainsi le code suivant :

 
Sélectionnez

	System.out.println( memoryBean.getHeapMemoryUsage() );

Donnera un résultat de le forme suivante :

 
Sélectionnez

init = 0(0K) used = 436912(426K) committed = 2031616(1984K) max = 530907136(518464K)

A noter également qu'il est possible de surveiller la mémoire utilisé pour la JVM elle-même (et non pas par votre application) via la méthode getNonHeapMemoryUsage().

Pour les versions précédentes à Java 5.0, on peut utiliser la classe Runtime et ses méthodes maxMemory(), totalMemory() et freeMemory() :

  • maxMemory() représente la quantité maximale que la JVM est authorisée à réserver auprès du système d'exploitation (équivalent de l'attribut max).
  • totalMemory() représente la quantité de mémoire qui a été réservée auprès du système d'exploitation (équivalent de l'attribut committed).
  • freeMemory() représente la quantité de mémoire libre utilisable avant que la JVM n'alloue encore de la mémoire auprès du système (équivalent à la différence entre les attributs committed et used)

Ainsi pour obtenir un résultat similaire, on peut utiliser le code suivant :

 
Sélectionnez

Runtime runtime = Runtime.getRuntime();
System.out.print( "used : " + ( runtime.totalMemory()-runtime.freeMemory() ) );
System.out.print( "  committed : " + runtime.totalMemory() );
System.out.println( "  max : " + runtime.maxMemory() );

Qui donnerait ceci :

 
Sélectionnez

used : 446256  committed : 2031616  max : 530907136
Créé le 16 décembre 2006  par adiGuba

Lien : Gestion du Garbage Collector
Lien : MemoryMXBean
Lien : Runtime

La méthode equals() permet d'indiquer qu'un objet est égal à un autre. L'implémentation par défaut hérité de Object se contente de renvoyer true lorsqu'il s'agit du même objet en mémoire et ne vérifie pas les valeurs des attributs de la classe (donc x.equals(y) équivaut à x==y).

Dès lors que l'on a besoin de tester l'égalité des instances d'une classe, il faut que cette dernière redéfinissent la méthode equals(). C'est également une condition pour le bon fonctionnement de certaines méthodes des Collections de Java.

La méthode equals() doit donc renvoyer true lorsque deux objets sont identiques, et false dans le cas inverse. Enfin il faut noter que cette méthode ne devraient pas renvoyer d'exception, même si son paramètre vaut null.

En général la méthode equals() se décompose en trois étapes :

  • Vérification de l'égalité des références : il est inutile de comparer les valeurs si les références sont identiques.
  • Vérification du type du paramètre : on ne peut pas comparer n'importe quel type.
  • Vérification des valeurs des attributs utiles des deux objets (c'est à dire des attributs représentatifs de la valeur de l'objet).

Ainsi, cela pourrait donner :

 
Sélectionnez

class TestClass {
    private int attribut1;
    private String attribut2;
    private boolean visible; // Attribut non-représentatif et donc ignoré
 
    @Override
    public boolean equals(Object obj) {
        // Vérification de l'égalité des références
        if (obj==this) {
            return true;
        }
 
        // Vérification du type du paramètre
        if (obj instanceof TestClass) {
            // Vérification des valeurs des attributs
            TestClass other = (TestClass) obj;
 
            // Pour les attributs de type primitif
            // on compare directement les valeurs :
            if (this.attribut1 != other.attribut1) {
                return false; // les attributs sont différents 
            }
 
            // Pour les attributs de type objets 
            // on compare dans un premier temps les références 
            if (this.attribut2 != other.attribut2) {
                // Si les références ne sont pas identiques
                // on doit en plus utiliser equals()
                if (this.attribut2 == null || !this.attribut2.equals(other.attribut2)) {
                    return false; // les attributs sont différents 
                }
            }
 
            // Si on arrive ici c'est que tous les attributs sont égaux :
            return true;
        }
 
        return false;
    }
}

Il faut prendre en compte les règles suivantes lors de la redéfinition de la méthode equals() :

  • Réflection : x.equals(x) devrait toujours retourner true.
  • Symétrie : Si x.equals(y) retourne true, alors y.equals(x) retournera true.
  • Transitivité : Si x.equals(y) retourne true et y.equals(z) retourne true, alors x.equals(z) retourne true.
  • Consistance : Pour deux référence x et y, tous les appels à la méthode x.equals(y) devront toujours donner le même résultat.

Toutefois ces règles peuvent être difficilement réalisable en cas d'héritage lorsque de nouveaux attributs sont pris en compte.

Enfin, la librairie Jakarta Common Lang propose une classe EqualsBuilder qui facilite et simplifie l'écriture des méthodes equals() en se chargeant de la comparaison des attributs, ce qui pourrait donner dans ce cas :

 
Sélectionnez

public boolean equals(Object obj) {
    // Vérification de l'égalité des références
    if (obj==this) {
        return true;
    }
 
    // Vérification du type du paramètre
    if (obj instanceof TestClass) {
 
        // Vérification des valeurs des attributs
        TestClass other = (TestClass) obj;
 
        return new EqualsBuilder()
            .append(this.attribut1, other.attribut1)
            .append(this.attribut2, other.attribut2)
            .isEquals();
    }
 
    return false;
}

Enfin, il faut noter qu'il est conseillé de redéfinir également la méthode hashCode() afin de respecter le contrat de cette dernière (qui est fortement lié à equals()).

Créé le 3 février 2007  par adiGuba

Lien : Pourquoi et comment redéfinir la méthode hashCode() ?

La méthode hashCode() a pour objectif de fournir un code de hashage, afin d'optimiser le traitements des collections de type Map, qui se basent sur ce hashCode pour classer les données. Il est ainsi nécessaire de redéfinir la méthode hashCode() dès que l'on souhaire utiliser un objet en tant que clef d'une Map.

Mais plus généralement, il est souhaitable de redéfinir la méthode hashCode() lorsque l'on redéfinit la méthode equals(), afin de conserver une certaine cohérence.

En effet, ces deux méthodes sont très liées, puisque les hashCode de deux objets égaux doivent être égaux, ainsi l'on doit vérifier la condition suivante :

Si x.equals(y), alors x.hashCode() == y.hashCode()

Par contre l'inverse n'est pas forcément vrai. Ainsi deux objets différents peuvent avoir le même hashCode(). Toutefois ceci est à éviter dans la mesure du possible, car cela peut détériorer les performances des Map.

Mais le calcul du hashCode() doit rester raisonnables et peu complexe, afin d'éviter des temps de calcul trop important.

La solution les plus courantes est de calculer un hashCode() selon la valeurs des attributs utilisés dans la méthode equals() afin de conserver la cohérence entre les deux méthodes.

Pour le calcul du hashCode(), on peut raisonnablement suivre la règle suivante :

  • On choisit deux nombres impairs différents de zéro. Un de ces nombres servira comme valeur de départ pour le calcul du hashCode. Le second servira de "multiplieur" à chaque "ajout" du hashCode d'un attribut. Il est préférable d'utiliser des nombres premiers par sécurité.

En effet, si à chaque clé x , correspond h(x) l'endroit où se trouve x dans la table de hachage. L'expression de la fonction de Hachage est :

 
Sélectionnez
h(x)=[x(1)*B^(l-1) + x(2)*B^(l-2)....+x(l)] mod N

Prenons B = 128, et prenons une taille N égale a B, on obtient après calcul :

 
Sélectionnez
h(x)=x(l) mod N

car B mod N serait égale a 0

Une seule valeur a donc été rangée dans la table, voilà pourquoi il est très important de limiter au maximum les risques de diviseur commun car certaines valeurs disparaîtraient alors des tables.

NB : le choix de B comme d'une puissance de deux au lieu d'un nombre premier peut s'avérer judicieux pour des raisons de vitesse d'exécution. En effet une multiplication par deux est un simple décalage d'un bit à gauche pour l'ordinateur. Malgré tout, cela augmente les risques de diviseur commun et donc de disparition de donnée.

  • Calcul du hashCode de chaque attribut utile (ceux utilisés dans la méthode equals()), ce qui revient à faire (soit 'a' l'attribut) :
  • Pour un boolean, renvoyer 0 ou 1 (a ? 0 : 1)
  • Pour type entier (byte, char, short ou int) il suffit de prendre la valeur entière (avec un cast éventuel) : (int)a;
  • Pour un type long, le convertir en int en déplacant les bits : (int) (a^(a>>>32))
  • Pour le type float, on le convertit en int avec la méthode Float.floatToIntBits(a).
  • Pour le type double, on le convertit en long avec la méthode Double.doubleToLongBits(a), puis on effectue le même traitement que pour les long.
  • Pour les objets, on se contentera d'utiliser la méthode hashCode(), ou d'utiliser zéro si la référence est null : (object==null ? 0, object.hashCode())
  • Pour un tableau, on traitera tous les éléments de ce dernier en respectant les règles ci dessus.

Et enfin on ajoute chacun des hashCodes calculés au résultat, après l'avoir multiplié par le nombre "multiplieur".

Ce qui pourrait donner (pour la classe en exemple dans la question précédente) :

 
Sélectionnez
public int hashCode() {
    // On choisit les deux nombres impairs
    int result = 7;
    final int multiplier = 17;
 
    // Pour chaque attribut, on calcule le hashcode
    // que l'on ajoute au résultat après l'avoir multiplié
    // par le nombre "multiplieur" :
    result = multiplier*result + attribut1;
    result = multiplier*result + (attribut2==null ? 0 : attribut2.hashCode());
 
    // On retourne le résultat :
    return result;
}

Les nombres 7 et 17 ont été choisit de manière totalement arbitraire. Il est juste préférable de ne pas utiliser les mêmes pour toutes les classes.

Enfin, la librairie Jakarta Common Lang propose également une classe HashCodeBuilder qui facilite et simplifie l'écriture des méthodes hashCode() en se chargeant du calcul des hashCode des attributs selon leurs types, ce qui pourrait donner dans ce cas :

 
Sélectionnez
public int hashCode() {
    return new HashCodeBuilder(17, 37)
        .append(this.attribut1)
        .append(this.attribut2)
        .toHashCode();
}
Mis à jour le 7 juin 2009  par adiGuba, mlny84, nolofinwe

Il faut consommer tous les flux dans des threads différents.

La JVM utilise deux (petit) buffer pour lire la sortie stdout et stderr du programme appellé, mais lorsque ces buffers sont plein, le programme appellé reste bloqué sur la méthode d'écriture tant que le buffer de la JVM n'est pas vidé.

Voici un exemple complet :

 
Sélectionnez
Runtime runtime = Runtime.getRuntime();
final Process process = runtime.exec("monappli");
 
// Consommation de la sortie standard de l'application externe dans un Thread separe
new Thread() {
	public void run() {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line = "";
			try {
				while((line = reader.readLine()) != null) {
					// Traitement du flux de sortie de l'application si besoin est
				}
			} finally {
				reader.close();
			}
		} catch(IOException ioe) {
			ioe.printStackTrace();
		}
	}
}.start();
 
// Consommation de la sortie d'erreur de l'application externe dans un Thread separe
new Thread() {
	public void run() {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
			String line = "";
			try {
				while((line = reader.readLine()) != null) {
					// Traitement du flux d'erreur de l'application si besoin est
				}
			} finally {
				reader.close();
			}
		} catch(IOException ioe) {
			ioe.printStackTrace();
		}
	}
}.start();
Créé le 2 juin 2007  par le y@m's

Lien : Comment exécuter une application externe ?
Lien : Exécuter une application externe en Java

Il suffit de positionner la propriété systeme sun.awt.exception.handler soit avec l'option -D de java soit avec un System.setProperty().

Cette propriété doit contenir le nom complet d'une classe contenant une méthode :

 
Sélectionnez

public void handle (Throwable t);

A chaque exception non interceptée, une nouvelle instance de cette classe est créée (il faut un constructeur vide) et la méthode handle() est appelée.

Attention : Cela ne fonctionne pas avec Java 1.5.

Dans le cadre de Java 1.5 on peut utiliser les UncaughtExceptionHandler avec la méthode Thread.setDefaultUncaughtExceptionHandler() (voir avec setUncaughtExceptionHandler() afin de l'effectuer thread par thread...)

Cette solution est nettement plus propre mais malheureusement elle neccessite une JVM 1.5.

Créé le 2 juin 2007  par adiGuba

Il faut se connecter à l'URL et vérifier le code de réponse. On voit ainsi si l'URL est valide.

 
Sélectionnez

import java.io.*;
import java.net.*;
 
publique boolean testUrl(String url) {
	try {
		HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
		conn.connect();
 
		return conn.getResponseCode() == HttpURLConnection.HTTP_OK;
	} catch (MalformedURLException e) { 
		return false; 
	} catch (IOException e) { 
		return false; 
	}
}
Créé le 2 juin 2007  par romuluslepunk


Pour définir les commentaires javadoc au niveau du package, il faut créer un fichier HTML nommé "package.html" dans le répertoire du package. Ce fichier sera lu par l'outil javadoc pour générer la page de documentation du package, et son contenu (entre les balises <body> et </body>) sera alors utilisé comme commentaire pour le package, par exemple :

 
Sélectionnez

<HTML>
	<BODY>
		Documentation du package <b>com.masociete.monpack</b>.
		@since 1.0
	</BODY>
</HTML>


A partir de Java 5.0, le fichier "package.html" peut être remplacé par un fichier source java spécial nommé "package-info.java". Ce fichier ne doit contenir que la ligne de déclaration du package, avec ses commentaires "javadoc" et surtout ses éventuelles annotations. Par exemple :

 
Sélectionnez

/**
 * Documentation du package <b>com.masociete.monpack</b>.
 * @since 1.0
 */
@MonAnnotation
package com.masociete.monpack;
Créé le 25 août 2007  par adiGuba

Lien : The Java API Documentation Generator - Package Comment Files

La liste de toutes les options pour les versions 1.3.1 à 1.6.0 de la Java HotSpot VM (plateforme SPARC/Solaris) sont disponibles sur le site de Sun Microsystems : A Collection of JVM Options

D'autres éléments relatifs aux options de la JVM sont disponibles aux adresses suivantes:

Il est à noter que cette liste d'options est utilisable avec la plupart des outils livrés avec le JDK tels que:

  • %JAVA_HOME%\bin\javac.exe
  • %JAVA_HOME%\bin\javap.exe
  • %JAVA_HOME%\bin\jconsole.exe
  • %JAVA_HOME%\bin\keytool.exe
  • %JAVA_HOME%\bin\rmic.exe
  • etc.

Il suffit pour cela d'utiliser l'option -J qui passera directement les paramètres à la Runtime Java sous-jacente.

Exemple:

 
Sélectionnez


C:\Program Files\Java\jdk1.6.0_02\bin>javadoc.exe -J-version
java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b06)
Java HotSpot(TM) Client VM (build 1.6.0_02-b06, mixed mode, sharing)
Créé le 1er mai 2008  par adiGuba, Pierre Chauvin
Les codes sources présentés sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Pour le reste, ce document constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Ce document issu de http://www.developpez.com est soumis à deux licences, en fonction des contributeurs : - Les contributions de Clément Cunin et Johann Heymes sont soumises aux termes de la la licence GNU FDL traduite en français ici. Permission vous est donnée de distribuer, modifier des copies des contributions de Clément Cunin et Johann Heymes tant que cette note apparaît clairement : "Ce document issu de http://www.developpez.com est soumis à la licence GNU FDL traduite en français ici. Permission vous est donnée de distribuer, modifier des copies de cette page tant que cette note apparaît clairement". - Pour ce qui est des autres contributions : Copyright © 2014 Developpez LLC : Tous droits réservés Developpez LLC. Aucune reproduction, ne peut en être faite sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.