Java

Merci Oracle

Ce matin, j’arrive au travail, je démarre mes PC et l’un d’eux me propose une mise à jour de Java. J’utilise Eclipse, plein d’Eclipses, et donc Java, tous les jours. Je dis oui. Tout se passe bien, rien de spécial à dire. Un peu plus tard, je double-clique sur mon raccourci pour lancer MicroEJ, l’IDE basé sur Eclipse de mon entreprise, et bim !

microej-java-disparu

Quoi ? Comment ? Tout marchait très bien hier soir ! Un petit tour dans l’explorateur de fichiers. Ah ok : le dossier C:\Program Files (x86)\jre7 n’existe plus, la mise à jour de Java l’a supprimé ! Les utilisateurs avertis d’Eclipse savent qu’à côté de eclipse.exe, il y a un fichier eclipse.ini qui donne le chemin vers le JRE à utiliser. Pour régler le problème ci-dessus, il suffit d’éditer ce fichier pour pointer vers un JRE qui existe. J’ai choisi mon JDK 7 qui, contrairement au JRE 7, n’avait pas été supprimé (logique, non ?). Maintenant, cet Eclipse marche, il n’y plus qu’à réparer les autres…

Merci Oracle.


Énumérations : Java vs C

Malgré ce titre aguicheur, l’objectif n’est pas de faire un combat entre le C et le Java ^^ Je viens simplement de me pencher un peu plus en détails sur les énumérations en Java et il s’avère qu’elles sont bien plus puissantes. En même temps, elles sont basiques en C… Java tire sa force dans le fait que ses énumérations sont très proches des classes* : une énumération a un constructeur, peut avoir des champs et des méthodes.

Si je me suis intéressé aux énumérations, c’est parce que j’étais cette semaine chez un client et qu’il souhaitait accéder à des données dans un tableau grâce aux valeurs de l’énumération, comme il avait l’habitude de le faire en C. Il est vrai que lorsqu’on définit une énumération en C, on peut écrire du code comme ceci :

#include <stdio.h>

typedef enum
{
    MORNING,
    AFTERNOON,
    NIGHT
} moment_t;

const char* moment_strings[] = {"I Hate Morning...", "I can deal with Afternoon.", "Night is great !"};

const char * to_string(moment_t m)
{
    return moment_strings[m];
}

int main()
{
    printf("%s\n", to_string(MORNING));
    printf("%s\n", to_string(AFTERNOON));
    printf("%s\n", to_string(NIGHT));

    moment_t m = 42;
    printf("%s\n", to_string(m));
}

On obtient la sortie suivante dans la console :

I Hate Morning...
I can deal with Afternoon.
Night is great !
(null)

Les valeurs énumérées sont des entiers en C et le compilateur ne râle pas quand on affecte 42 dans une variable de type moment_t. Il faut donc rajouter des tests dans la fonction to_string() pour s’assurer qu’on est dans la plage de moment_t. La rigueur des valeurs utilisées est à la charge du développeur, comme presque toujours en C, mais on peut arriver à des constructions assez puissantes avec des énumérations.

A première vue en Java, difficile de faire la même chose avec une énumération :

package com.gradot.enums;

public enum BasicMoment {
	MORNING, AFTERNOON, NIGHT
}

Il existe une technique presque cachée : BasicMoment.MORNING.ordinal() renverra 0. On peut donc récupérer un entier pour accéder au contenu d’un tableau. Il y a bien mieux à faire en Java, en tirant partie de cette ressemblance très forte avec une classe*. On peut par exemple faire ceci :

package com.gradot.enums;

public enum Moment {
		MORNING("I Hate Morning..."),
		AFTERNOON("I can deal with Afternoon."),
		NIGHT("Night is great !");
		
		private final String message;

		private Moment(String message) {
			this.message = message;
		}
		
		public String getMessage() {
			return message;
		}
	
	public static void main(String[] args) {
		System.out.println(Moment.MORNING.getMessage());
		System.out.println(Moment.AFTERNOON.getMessage());
		System.out.println(Moment.NIGHT.getMessage());
	}
}

Lorsqu’on définit les valeurs de l’énumération, on fait appel au constructeur (qui est forcément privé, car on ne peut pas rajouter de valeur à l’énumération). On peut ainsi conserver le message directement dans un champ. On peut enfin définir un getter pour récupérer ce texte. Et bien sûr ici, il n’est pas possible d’utiliser 42 comme valeur pour une variable de type Moment.

* : en fait, les énumérations sont des classes 😉 Pour être exact, Oracle dit dans ce lien :

The enum declaration defines a class (called an enum type).

Il existe une classe abstraite appelée Enum. Et voici la hiérarchie de classes pour Enum dans mon workspace :
H
Magique, non ?

PS : woh ! C’est mon 80e article !


Tableau en paramètre d’une méthode en Java

J’avance lentement mais sûrement dans mon apprentissage de Java (ouais, je préfère coder que de lire un bouquin, c’est comme ça ^^). Hier, je me suis demandé comment on pouvait modifier un tableau passé en paramètre à l’intérieur d’une méthode. Petit article avec code démonstratif pour me souvenir de tout ça.

Comme avec un descendant d’Object, on passe non pas l’objet tableau (qui se trouve quelque part dans le tas) mais une référence vers ce tableau. Grâce à cette référence, on peut modifier les éléments du tableau ; en revanche, on ne peut pas échanger cet objet par un autre. Si on tente d’affecter un nouveau tableau au paramètre à l’intérieur de la méthode, cela n’a pas d’effet en dehors de cette méthode. L’appelant possède toujours une référence sur le « bon » objet, la méthode travaille elle sur la nouvelle référence et donc le nouvel objet.

package tests;

public class Main {

	private static void content(byte[] array) {
		array[0] = 42;
		System.out.println("Content :" + array);
	}

	private static void object(byte[] array) {
		array = new byte[] { 0, 0, 0 };
		System.out.println("Object : " + array);
	}

	private static void print(byte[] array) {
		System.out.println("Print: " + array);
		for (byte b : array) {
			System.out.print(b);
			System.out.print('\t');
		}
		System.out.println("\n");
	}

	public static void main(String[] args) {
		byte[] array = new byte[] { 1, 2, 3 };
		print(array);

		content(array);
		print(array);

		object(array);
		print(array);
	}

}

Sortie console :

Print: [B@1888759
1 2 3

Content :[B@1888759
Print: [B@1888759
42 2 3

Object : [B@6e1408
Print: [B@1888759
42 2 3

Mes débuts avec Maven

J’avais déjà entendu parler de Maven mais pas eu l’occasion de m’en servir. Pour ceux qui ne connaissent pas Maven, vous pouvez lire l’article Wikipédia à son sujet. En bref, Maven (en version longue Apache Maven, puisque c’est un outil de l’Apache Software Foundation) est un outil pour la gestion et la construction de projets Java. On m’avait surtout vanté ses mérites pour la gestion des dépendances. J’ai voulu cette semaine tester une bibliothèque Java et le tutoriel donnait les dépendances Maven pour récupérer les JAR nécessaires. Je me suis dit que c’était le moment de débuter et cet article retrace mes étapes de prise en main.

Logo Maven

Pour être honnête, ce n’est pas très compliqué. Il suffit de vous rendre ici : http://maven.apache.org/guides/. Il y a deux getting started with Maven. J’ai commencé par celui qui dure 5 minutes. Il explique de manière claire et détaillée comment l’installer puis comment créer son projet et le construire. J’ai ensuite lu celui qui dure 30 minutes. Je me suis en particulier intéressé à la section How do I use external dependencies?. J’ai édité mon fichier pom.xml pour y ajouter mes dépendances.

Quand est venu le moment de coder, je n’avais pas vraiment envie de faire ça avec Notepad++ et la ligne de commande, alors j’ai tapé dans mon terminal :

mvn eclipse:eclipse

J’ai ouvert Eclipse, j’ai fait Import / Existing project into workspace. Mon projet était là ! Il restait un petit détail à régler : Maven avait ajouter des classpath variables au Java build path de mon projet mais en utilisant une variable M2_REPO qui n’était pas positionnée dans mon Eclipse. Cette variable pointe vers le dépôt local de Maven, là où il télécharge les JAR des dépendances. Un petit tour sur Google pour savoir où est le dépôt Maven sur mon disque dur et savoir comment rajouter la variable dans Eclipse. Le build path était réparé et le projet compilait.

Le plus simple était fait, j’ai alors testé la bibliothèque 😉


ArrayList vers String[] et transtypage de tableau en Java

J’ai appris une petite subtilité de Java aujourd’hui, sur le transtypage de tableaux. Un tableau de type Object[] ne peut pas être caster en String[] même si chacun de ces Objects sont en fait des Strings. J’ai rencontré le problème avec une ArrayList que je voulais « transformer » en String[]. Il ne suffit pas de bêtement utilisé toArray() et de caster le tableau retourné. Le code suivant illustre le problème de trantypage (donnant lieu à une ClassCastException) et donne aussi la méthode correcte pour transformer l’ArrayList en tableau.

package tests;

import java.util.ArrayList;

public class Main {

	public static void main(String[] args) {

		ArrayList<String> list = new ArrayList<>();

		list.add("hello, ");
		list.add("world");

		try {
			String[] array = (String[]) list.toArray();
			printStringArray(array);
		} catch (ClassCastException e) {
			e.printStackTrace();
		}

		String[] array = list.toArray(new String[list.size()]);
		printStringArray(array);
	}

	static void printStringArray(String[] array) {
		for(String s : array) {
			System.out.println(s);
		}
	}

}

Le résultat de l’exécution est :

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at tests.Main.main(Main.java:15)
hello, 
world

Si vous avez un tableau d’Objects et que vous souhaitez le transformer en tableau de Strings (on passe ici dans un contexte plus général que mon histoire d’ArrayList), il faut utiliser System.arrayCopy() ou encore Arrays.copyOf(). Voir cette discussion sur stacksoverflow: How to convert object array to string array in Java.


Concevoir un site comme celui-ci avec WordPress.com
Commencer