code – [Blog] du Java et du Freelance https://java-freelance.fr Vis ma vie de freelance java : techno et entreprise Mon, 12 Oct 2015 14:45:01 +0000 fr-FR hourly 1 https://wordpress.org/?v=4.4.4 Let’s make this test suite run faster! SoftShake 2010 https://java-freelance.fr/java/lets-make-this-test-suite-run-faster-softshake-2010 https://java-freelance.fr/java/lets-make-this-test-suite-run-faster-softshake-2010#comments Tue, 26 Oct 2010 07:00:51 +0000 https://java-freelance.fr/?p=920 Qui n’a jamais attendu de nombreuses minutes pour builder un projet ? Et qui n’en a jamais profité pour aller boire un café/regarder twitter/… ? :) Parce que l’on teste fréquemment, il est important d’essayer d’optimiser et de réduire la durée d’exécution des tests.  Tester souvent ne veux pas dire attendre souvent ! Il est donc primordial d’essayer de réduire cette durée en jouant sur différents paramètres. Comment obtenir le résultat des tests le plus rapidement possible ?

Ce qui suit est tiré de la conférence de David Gageot [ @dgageot / http://javabien.net ] à SoftShake 2010.

Sur une vingtaine de personnes présentes dans la salle, les durées de build vont de quelques minutes à plusieurs heures. David présente brièvement quelques frameworks comme Infinitest et JUnitMax. Ce sont des plugins pour IDE Java qui permettent de lancer les tests unitaires en continu et de manière intelligente, c’est à dire uniquement ceux impactés par le code modifié.
La première idée lorsque l’on cherche à optimiser cette durée d’exécution, c’est de vouloir déléguer le problème. C’est faire  tourner les tests sur des serveurs distribués qui permettront d’exécuter les tests en tâches de fond. C’est une mauvaise idée, les serveurs coûtent chers et on peut se retrouver submerger. Il existe des méthodes plus simples pour réduire cette durée.

Le KISS ( Keep It Simple, Stupid ) est également applicable lorsque l’on crée des tests. Chercher à optimises ses tests peut améliorer votre produit : ce qui est simple à tester sera simple à coder et à utiliser. Ce qui est compliqué n’en vaut surement pas la peine.

Le tricheur

La manière la plus simple pour accélérer les tests c’est d’acheter une machine plus rapide. Exécuter les tests sur une machine plus rapide peut être un vrai gain de temps, David nous donne l’exemple d’une exécution 15% plus rapide sur la machine la plus rapide par rapport à la plus lente. Il est également possible d’utiliser la nouvelle fonctionnalité de maven de build en parallèle (mvn -T2 clean install / mvn -t4 clean install). Nous avons essayé sur un de nos projets, l’exécution du build est passé de 1m30 à 30 secondes !
Il est également possible de faire en sorte que les tâches maven surefire pour JUnit et TestNG soient exécutés en parallèle. Comme les tests se doivent d’être indépendant et isolés, ce sont de bons candidats à une exécution en parallèle. Faire quand même attention que vous pouvez vous retrouver avec des problèmes de concurrence dans certains cas.

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <version>2.5</version>
   <configuration>
     <parallel>methods</parallel>
     <threadCount>4</threadCount>
   </configuration>
</plugin>

Il existe deux façons de paralléliser : méthodes ou classes. Utiliser la méthode de parallélisation par méthode peut se révéler risqué car il est fort probable que tous les tests n’auront pas été designés dans l’optique d’être exécutés en parallèle, la méthode ‘classes’ est un choix plus prudent. Plus d’infos sur le blog de Wakaleo Consulting.

Le paresseux

Il y a souvent des tests redondants dans un projets : débusquez les, cela permettra de gagner en exécution et en lisibilité. C’est tellement simple qu’on ne le fait pas ! Ne pas hésiter à supprimer des fonctionnalités et les tests associés si elles ne servent plus rien, le projet y gagnera en simplicité.
Les accès réseaux et disques sont trop lents. Il faut essayer au maximum de s’en passer et privilégier les bases de données en mémoire comme h2 (qui ressemblera plus à mysql que hsqldb). De même pour les accès mails, il est possible d’utiliser dans les tests des serveurs SMTP en mémoire comme ethereal. Si beaucoup de tests accèdent à des fichiers, Spring Resource ou Apache VFS (Virtual File System) sont de bonnes alternatives.

Le brave

Il est préférable de tester les règles métiers dans les tests unitaires plutôt que dans les test d’intégrations. Il ne faut pas confondre tests d’intégrations et tests unitaires : les premiers sont , bien qu’essentiel, plus longs à tester, ils doivent être utiliser avec parcimonie. Par exemple, pour plusieurs tests qui accèderaient à une base de données peuvent être remplacés par un test qui permet de garantir que l’on peut bien accéder à la base de données et par plusieurs autres tests où l’accès à la base de données aura été bouchonné.
Une méthode lorsque l’on cherche à diminuer la durée d’exécution de tests est de prendre le test d’intégration le plus long et de l’analyser jusqu’à réussir à le découper en un test d’intégration plus petit et plusieurs tests unitaires. Si c’est l’accès à certaines couches qui sont lentes lors de tests d’intégrations, il est recommandé de les bouchonner, les frameworks de mocks ne servent pas que dans le cas de tests unitaires :)
De même, méfiez vous des tests d’interface, ils prennent beaucoup de temps et souvent, ce qu’ils testent peut être tester unitairement. Selenium est à utiliser avec modération. Méfiez vous vraiment quand vous commencez à tester vos fonctionnalités via Selenium. Et ne dites pas ‘mon utilisateur veut de l’AJAX‘ ‘J’ai besoin de tester la compatibilité des différents navigateurs’.

Chaque complexité a un coût. Et cela se paye à chaque fois que les tests sont exécutés.  Si c’est compliqué à tester : danger, la fonctionnalité peut sûrement être faite plus simplement. Il est possible de faire des tests unitaires en Javascript plutôt que tester dans les browsers (ex : QUnit).
David préfère limité AJAX aux réels besoins et d’effectuer au maximum le code server-side.

Et pour finir : simplifier et optimiser votre code. Ce sont des choses qui se font. Le build va être plus rapide et l’application aussi 😀 A vous l’effet Kiss Cool :)

]]>
https://java-freelance.fr/java/lets-make-this-test-suite-run-faster-softshake-2010/feed 4
Bouchon (stub) ou Simulacre (mock) ? https://java-freelance.fr/java/bouchon-stub-ou-simulacre-mock https://java-freelance.fr/java/bouchon-stub-ou-simulacre-mock#comments Fri, 02 Jul 2010 05:04:37 +0000 https://java-freelance.fr/?p=795 Le test unitaire est un test qui provoque l’exécution d’une partie du code et qui l’analyse.  Il permet de garantir que le code exécuté fonctionne correctement. Il se doit donc d’être automatisé et répétable. Pour cela, cela nécessite fréquemment le besoin d’isoler le test unitaire des systèmes extérieurs (base de données, appels web-service distants).

Pour ce faire, il existe plusieurs méthodes, l’utilisation de bouchon (‘stub’) ou de simulacre (‘mock’). L’article de référence est un article de Martin Fowler « Les simulacres ne sont pas des bouchons« . Pour résumer, une méthode bouchonnée est appelée sur un objet bouchon réel, centré sur le système testé. Il ne peut jamais faire échouer le test. On regarde l’état de l’objet final à la fin du test et non les étapes qui ont permis d’obtenir cet état. C’est un test basé sur des états.

En ce qui concerne les simulacres, les assertions ne portent pas sur l’objet final mais sur la manière dont ce dernier a été obtenu. C’est un test basé sur le comportement de la méthode. On peut contrôler le nombre de fois qu’une méthode a été invoquée, vérifier que ses paramètres correspondent bien entre ce qui est défini et ce qui est exécuté et faire échouer le test si l’enchaînement de méthodes ne correspond pas à l’enchaînement attendu par exemple.

Easymock utilise dans son fonctionnement le plus basique des simulacres, qui permettent de construire un test de manière très simple : l’ordre des méthodes invoquées, le nombre d’appel à une méthode peut engendrer un échec du test. Potentiellement, les tests sont plus fragiles et plus difficile à maintenir.
Mais EasyMock permet également la création de bouchons qui peuvent être réutilisé. Il est ainsi possible de maintenir des bouchons partagés entre différents tests unitaires, ce qui permet une meilleure maintenabilité. Dans ce cas, nous ne nous intéressons pas au comportement, uniquement au résultat.

La création de bouchon à l’aide de andStubReturn()

public Service getServiceMock() {
   Service serviceMock =  createMock(Service.class);

   expect(serviceMock.appel1()).andStubReturn(Integer.valueOf(5));
   expect(serviceMock.appel2(anyObject())).andStubReturn(BigDecimal.TEN);

   replay(serviceMock);

}

La méthode andStubReturn signifie que cette méthode peut être appelée sans condition de nombre (0,1 …n) ni d’ordre. Il est simplement défini que si cette méthode est appelée, elle renverra un paramètre tel que défini via le andStubReturn. Il n’y a pas de verify(serviceMock) car les contrôles sur le comportement du mock ne nous intéressent pas.

La création de bouchon à l’aide des ‘niceMock’

Une autre possibilité lorsque l’on souhaite utiliser les bouchons (stub) est de créer un ‘nice mock’, qui est par défaut, renvoie 0, null ou false selon le paramètre de retour des méthodes :

myNiceMock  = createNiceMock(Service.class);

Toujours sans utiliser de verify.

Les avantages du stub sont nombreux : les tests sont plus faciles à maintenir, il est possible de réutiliser les stubs au sein de plusieurs classes de tests… Néanmoins,  il y a des situations où le test d’un comportement est plus adéquat que l’utilisation de bouchon comme par exemple, vérifier que certains paramètres sont bien calculés avant d’être envoyé à des services externes, ce qui est fréquemment mon cas.

]]>
https://java-freelance.fr/java/bouchon-stub-ou-simulacre-mock/feed 6
Kawa BarCamp 2 https://java-freelance.fr/java/kawa-bar-camp-2 https://java-freelance.fr/java/kawa-bar-camp-2#comments Sun, 30 May 2010 17:47:01 +0000 https://java-freelance.fr/?p=691 J’ai participé hier à la deuxième édition du kawa barcamp. Un bar camp c’est une rencontre ouverte autour de thèmes choisis par les participants. Nous étions hier une trentaine de personnes réunis pendant environ 3 heures. Après un bref tour de table où nous nous sommes présentés (nom + prénom + 3 mots clés), 8 personnes ont inscrits des thèmes d’ateliers sur un tableau. Nous devions choisir parmis 2 sujets au choix :
en première partie No SQL pour les entreprises / TDD et ATDD / HTML 5 et en deuxième User Experience / Les nouveaux frameworks web (Play! Vaadin) / Les commentaires dans le code . Et d’autres que j’ai oublié !

J’ai participé à TDD/ATTD et à la session sur les commentaires dans le code.

TDD – ATTD

Le Test Driven Development est une méthode de programmation basée sur les règles suivantes :

  • on écrit un test
  • on vérifie qu’il échoue
  • on écrit juste ce qu’il faut pour que le test passe (et rien d’autre!)
  • on vérifie qu’il passe
  • on refactorise encore et encore

L’Acceptance Test Driven Development (ATDD) est basée sur l’idée de faire des tests d’acceptance (automatisés) avant même de commencer les développements. La bonne mise en pratique se fait en deux temps : le client, les utilisateurs, la MOA écrit les test pendant que les développeurs se chargent de les automatiser. Plusieurs outils existent pour cela comme par exemple Greenpepper, Fit/Fitnesse, Robot Framework … La plupart se base sur des wiki pour permettre aux personnes fonctionnelles d’écrire facilement leurs tests.

Dans une approche basée sur l’ATDD, les spécifications et les implémentations sont dirigées par des exemples concrets. Décrire précisément des cas de tests oblige celui qui spécifie à aller plus loin que les spécifications habituelles. Cette méthode a également l’avantage d’être plus claire pour le développeur.

Le TDD

Peu de personnes font du TDD pur et dur, la plupart de la dizaine de personnes présentes écrivent un bout de code avant de tester.  Néanmoins,  la personne ayant le plus d’expérience est un adepte du TDD pur et dur depuis de nombreuses années. Les frameworks de mocks permettent de simplifier sensiblement la tâche du développeur. Néanmoins, le TDD est loin d’être une évidence pour tout le monde. Le risque de perdre de vue l’architecture générale du projet, la difficulté de la sensibilisation d’une équipe aux tests, les problèmes de maintenabilité et de refactoring sont quelques uns des exemples soulevés pour montrer les difficultés engendrés par l’application de cette méthode.

L’ATDD

Au niveau des tests d’acceptance, seul une seule personne les utilise dans un contexte d’entreprise.
Le gros problème soulevé par les tests d’acceptance c’est la difficulté, lors d’utilisation d’outils type fit/fitness greenpepper est la refactorisation des tests : les tests écrits sont difficilement maintenable dans le temps. L’ATDD permet au développeur d’avoir des spécifications claires et précises, permettant entre autre de réduire les difficultés de communication entre la maitrîse d’oeuvre et d’ouvrage. Un autre point bloquant est que l’ATDD demande à l’équipe fonctionnelle de s’impliquer et de se former à un nouvel outil, ce qui n’est pas simple dans certains contextes.

Digressions diverses

Un autre aspect négatif est le temps pris par les tests, qu’ils soient d’intégration, d’acceptance …  Ils ont tendance à grossir encore et encore, à devenir de moins en moins maintenables jusqu’à devenir contre productif. Plutôt qu’un enchaînement d’action, difficile maintenable dans le temps, il faut se focaliser sur les work flows et sur les règles business. Il faut également essayer de limiter quand cela est possible l’utilisation de l’IHM dans les tests d’acceptance.

Les commentaires dans le code

Olivier Croisier a pour projet de synthétiser les bonnes pratiques de commentaires. Plusieurs points ont été abordés dans cet atelier.
Au niveau des APIs publics, la javadoc est coûteuse à maintenir mais obligatoire, et en anglais. Lorsqu’il y a du code, il est souvent obsolète donc à utiliser avec précaution.
Au niveau du code non public, les personnes présentes utilisent beaucoup moins la javadoc. On remarque souvent qu’il n’y en a pas, qu’elle est obsolète ou inintéressante. Un point pour commenter facilement le code est l’encapsulation du code dans des méthodes private qui, via leurs noms, sont auto-documentées. On peut donc alors comprendre facilement une méthode principale en lisant la succession de méthodes appelées. A noter qu’il ne suffit pas de découper son code n’importe comment, il est important de ne pas avoir une profondeur d’appels de méthodes de ce type trop importantes (A qui appelle B qui appelle C qui appelle D qui appelle E). Un moyen de découper convenablement le code est d’éviter d’appeler dans la méthode principale des méthodes fonctionnelles et des méthodes techniques. Le code est plus lisible si on découpe du fonctionnel vers le technique.
J’ai utilisé cette méthode pour découper des classes de plusieurs centaines de lignes avec un fonctionnel un peu compliqué et je trouve que le code est beaucoup plus clair, en cas d’évolution ou de recherche d’un bug, on sait directement où aller. Le problème de cette méthode est que parfois, on ne voit pas certains refactoring qui pourrait faire gagner en lisibilité (là encore, il est possible de perdre de vue la ‘big picture’). C’est pour cette raison que certains estiment qu’une méthode n’a d’utilité que lorsqu’elle est réutilisée et que les méthodes de plusieurs dizaines de lignes sont en fait plus claires. Sur ce sujet, lire Clean Code et Effective Java est essentiel.

Un autre point est l’utilisation des commentaires du style /**** GETTERS AND SETTERS *****/ /***** CONSTRUCTORS *****/ . La encore, cette méthode ne fait pas l’unanimité (et je suis loin d’en être la première fan).

Au niveau de l’utilisation français/anglais, c’est assez mitigé. La plupart écrivent leurs noms de variables et de commentaires en anglais, d’autres se permettent quelques écarts en français et pour quelques un le français est la norme.

Au niveau des tâches (//FIXME //XXX //TODO), la plupart des personnes présentes sont d’accord avec le fait que cela n’est utile que si la tâche nous concerne.

En ce qui concerne les warnings sur les classes, l’idée est d’en avoir aucun : l’utilisation des outils comme PMD, FindBugs, CheckStyle est à bien configurer avant utilisation, car la multiplication des warnings noie les vrais warnings dans de la pollution.

Je retiens également que Implementation Patterns de Kent Beck sera une de mes lectures estivales et que l’outil mvn eclipse:eclipse permet de faire bien plus de choses que prévues !

J’ai passé un agréable moment, j’y étais venue surtout par curiosité et je compte bien retourner à la prochaine ! Ça a duré jusqu’à un peu plus de 23 heures pour moi, ce qui fait quand même une bonne soirée. Énormément de digressions, ça part dans tous les sens mais c’est souvent là que c’est le plus intéressant !

Sur twitter : http://twitter.com/KawaCampParis

]]>
https://java-freelance.fr/java/kawa-bar-camp-2/feed 2
Revue de code II https://java-freelance.fr/java/revue-de-code-ii https://java-freelance.fr/java/revue-de-code-ii#comments Mon, 19 Apr 2010 20:50:41 +0000 https://java-freelance.fr/?p=356 Suite de la revue de code : BigDecimal, nommage et concaténation de String.

BigDecimal.equals vs BigDecimal.compareTo

Deux BigDecimaux qui ont la même valeur avec une précision différente ne sont pas considérés comme égaux à l’aide la méthode equals. En revanche, ils sont considérés comme égaux si on les compare avec la méthode compareTo.

Exemple :

BigDecimal bigDecimal1 = new BigDecimal(0);//0
BigDecimal bigDecimal2 = BigDecimal.ZERO;//0
BigDecimal bigDecimal3 = BigDecimal.valueOf(0.0);//0.0

System.out.println(bigDecimal1.equals(bigDecimal2));  //true
System.out.println(bigDecimal1.equals(bigDecimal3));  //false
System.out.println(bigDecimal2.equals(bigDecimal3)); //false

System.out.println(bigDecimal1.compareTo(bigDecimal2)==0); //true
System.out.println(bigDecimal1.compareTo(bigDecimal3)==0); //true
System.out.println(bigDecimal2.compareTo(bigDecimal3)==0); //true

public int compareTo(BigDecimal val)

Compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for performing these comparisons is: (x.compareTo(y) <op> 0), where <op> is one of the six comparison operators.

public abstract

Dans un autre registre, quelque chose qui revient souvent dans le code :

Les termes public ou abstract dans la déclaration des méthodes d’une interface.  L’ensemble des méthodes d’une interface sont obligatoirement public abstract, inutile donc de l’ajouter.

Mauvais nommage

Il y a toujours des variables mal nommées.  Plusieurs raisons à cela :

  • elles ne respectent pas les règles de nommage Java (variables en majuscule alors que non final static, présence de _ dans une variable local).
  • le nom de la variable ne dépend de ce qu’elle fait : autant i,j,k sont des noms de variables admettables pour des compteurs au sein de boucle, pas ailleurs.
  • le nom de la variable n’est pas compréhensible : updateFMTTTL si FMTTTL ne renvoie à rien fonctionnellement parlant,  il faut lui donner un autre nom. Il vaut mieux une variable à nom long mais compréhensible plutôt qu’essayer de faire court. Ceux qui vous passeront derrière vous en remercieront !

Le livre Coder Proprement de Robert C Martin consacre plusieurs pages intéressantes sur ce sujet.

La concaténation de String

Exemple 1 : Avec utilisation de l’opérateur +

long start = System.currentTimeMillis();
String a = " Concaténation";
for (int i = 0; i < 10000; i++) {
a += i;
}
System.out.println(a);
System.out
.println(" in " + (System.currentTimeMillis() - start) + "ms");

Exemple 2 : Avec un StringBuilder

start = System.currentTimeMillis();
StringBuilder stringBuffer = new StringBuilder (" Concaténation");
for (int i = 0; i < 10000; i++) {
stringBuffer.append(i);
}
System.out.println(stringBuffer.toString());
System.out
.println(" in " + (System.currentTimeMillis() - start) + "ms");

Durée des 10000 concaténations :

Exemple 1 : 360ms

Exemple 2 : 15ms

Il a néanmoins des cas où il est préférable d’utiliser la concaténation de string (+ ou String.concat) :

pour aérer une ligne ex :

String myString = " line 1 "
                     +  "line 2";

pour strictement moins de 4 concaténation :

 logger.debug("x :"+x+"y :"+y);

Le compilateur transforme automatiquement cettte ligne en utilisant un StringBuilder System.out.println((new StringBuilder()).append(« x: »).append(x).append( » y: »).append(y).toString());

Les tests avec les objets StringBuilder et StringBuffer renvoient des résultats quasiment similaires. StringBuilder étant un tout petit plus rapide, il est à utiliser le plus souvent possible. Le StringBuffer est quand à lui thread-safe donc à utiliser dans les environnements concurrents.

Il n’est pas forcément judicieux de remplacer toutes les concaténations de string automatiquement par un StringBuilder / StringBuffer. Si elles sont dans une boucle, le gain peut être remarquable dans les autres cas, cela se discute.  Les StringBuilder / StringBuffer alourdissent considérablement la syntaxe et le gain est parfois très faible. Comme dans la plupart des cas, l’optimisation prématurée est à éviter !  Pour appronfondir le sujet, voir l’interview du Dr Heintz Kabutz : http://java.sun.com/developer/technicalArticles/Interviews/community/kabutz_qa.html

]]>
https://java-freelance.fr/java/revue-de-code-ii/feed 2
Revues de code I https://java-freelance.fr/java/revues-de-code-i https://java-freelance.fr/java/revues-de-code-i#comments Thu, 04 Feb 2010 17:49:32 +0000 https://java-freelance.fr/?p=341 Au cours de mes revues de code, je tombe sur des problèmes plus ou moins réguliers.  Outre les problèmes de designs, certains aspects techniques sont récurrents.

Comparaison avec == sur des java.lang.Integer

Le problème, c’est que sur des integers entre -128 et 127, cela peut marcher.  Dans la suite de l’exemple, integer1 et integer2 seront de type java.lang.Integer, int1 sera de type primitif int.

        Integer integer1 = 127;
        Integer integer2 = 127;
        System.out.println(integer1 == integer2); // true

        integer1 = 128;
        integer2 = 128;
        System.out.println(integer1 == integer2); // false

Par contre, on a bien pour toutes les valeurs, y compris celles entre -128 et 127 :

integer1 = new Integer(127);
integer2 = new Integer(127);
System.out.println(integer1 == integer2); // false - normal on a instancié 2 objects différents

integer1 = new Integer(129);
int1 = 129;
System.out.println(integer1 == integer2); // true

Si on regarde la doc de Sun, pour tous les objets entre -128 et 127, l’autoboxing garantit que l’objet renvoyé Integer sera identique pour un même entier primitif. Ce qui ne sera pas le cas au delà de l’intervalle. De plus, rien ne garantit qu’une implémentation étende l’intervalle de cache, raison pour laquelle il est risqué de se baser dessus.
Byte,  Short,  Long ont également le même type de cache. Character a également un cache mais de 0 à 127 (un nombre négatif n’aurait pas eu de sens).

d. Autoboxing is guaranteed to return the same object for integral
values in the range [-128, 127], but an implementation may, at its
discretion, cache values outside of that range. It would be bad style

http://java.sun.com/developer/JDCTechTips/2005/tt0405.html#1

Ainsi, utiliser == en se fiant à l’autoboxing et au cache est une mauvaise pratique, même pour comparer des constantes de faible valeur.

Utiliser plutôt valueOf()  plutôt que new

Il est préferable d’utiliser un valueOf plutôt qu’une nouvelle instanciation à l’aide du constructeur. Valable pour la certains objets immutables.

Exemple avec des types java.lang.Integer, si on regarde la javadoc pour la méthode Integer.valueOf(int i) :

public static Integer valueOf(int i)
Returns a Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

Idem pour les Byte, Long, Character, BigInteger … Par contre, préférer quand c’est possible de construire les valeurs accessibles directement via une méthode statique (BigInteger.ONE plutôt que BigInteger.valueOf(1), Boolean.FALSE plutôt que Boolean.valueOf(false) …)

Éviter d’utiliser new String

String test1 = "abc";
String test2 = "abc";
String test3 = new String("abc");
String test4 = new String("abc");

System.out.println(test1 == test2); // true
System.out.println(test1 == test3); //false
System.out.println(test3 == test4); //false

Utiliser new String implique de créer un nouvel object en mémoire. Les String étant immutables, avoir 2 objets différents ayant la même valeur ne fait que consommer de la mémoire. Attention à bien noter le cas 2, « abc » est différent de new String(« abc »).  Cet exemple permet également de montrer l’importance d’utiliser la méthode equals pour comparer les valeurs des objets java.lang.String .

Comme précisé par Jérôme et Nicolas Le Coz en commentaire, l’instanciation d’un nouvel objet String est conseillée lors de l’utilisation de substring sur des très grandes chaînes de caractères. En effet, la valeur stockée avec un substring n’est pas uniquement la substring, mais la chaîne entière avec un offset (premier caractère à utiliser) et un compteur (nombre de caractères à utiliser).

C’est clair si l’on regarde la classe java.lang.String

  public final class String
  	implements java.io.Serializable, Comparable, CharSequence
  {
  /** The value is used for character storage. */
  private final char value[];

  /** The offset is the first index of the storage that is used. */
  private final int offset;

  /** The count is the number of characters in the String. */
  private final int count;
[...]
public String substring(int beginIndex, int endIndex) {
 [...]
 return ((beginIndex == 0) && (endIndex == count)) ? this :
 new String(offset + beginIndex, endIndex - beginIndex, value);
 }

Plus d’infos ici http://blog.xebia.fr/2009/08/03/revue-de-presse-xebia-120/#AttentionvotremmoireavecString et dans les autres liens en commentaires.

Se méfier de la construction des BigDecimal.

On utilise ici 3 manières de faire pour créer un BigDecimal que l’on souhaite égal à 4.12.  Néanmoins, les résultats ne sont pas conformes à ce qu’on pourrait en attendre.

Double myDouble = 4.12D;

BigDecimal bd1 = new BigDecimal(myDouble);
BigDecimal bd2 = new BigDecimal(String.valueOf(myDouble));
BigDecimal bd3 = BigDecimal.valueOf(myDouble);

System.out.println(bd1.equals(bd2));  // false !
System.out.println(bd1.equals(bd3)); // false !
System.out.println(bd2.equals(bd3));  // true

Il n’y a donc pas égalité de valeur entre l’object construit à partir du double et les 2 autres objets. En effet, si on affiche les différentes valeurs des 3 BigDecimal, le problème est facilement visible :

RESULT 1: 4.12000000000000010658141036401502788066864013671875
RESULT 2: 4.12
RESULT 3: 4.12

Il vaut mieux donc éviter d’utiliser le constructeur BigDecimal(double double) et de lui préférer les deux autres méthodes.

public BigDecimal(double val)
Translates a double into a BigDecimal which is the exact decimal representation of the double‘s binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.Notes:

  1. The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
  2. The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.
  3. When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
]]>
https://java-freelance.fr/java/revues-de-code-i/feed 4