…ale některé věci můžem dělat lépe. Při sledování
jednoho výborného videa Java Puzzles jsem si uvědomil, jak málo toho
vím a jak bez větší námahy můžem napsat aspoň trošku
efektivnější kód. Proto jsem se začal prohrabával
kódem mým i kolegů a narazil jsem na 3 často se
opakující věci (chybky) u často používaného kódu.

Spojování řetězců

V kódu jsem objevil, že se používají 3 způsoby, jak
spojit řetězec, viz demonstrační metody:

public String str1(int value) {

builder.append(„String : “ + value + “ neco“);

builder.append(„String : “ + value + “ neco“);

builder.append(„String : “ + value + “ neco“);

builder.append(„String : “ + value + “ neco“);

return builder.toString();

}

 

public String str2(int value) {

StringBuilder builder = new StringBuilder();

builder.append(„String :
„).append(value).append(“ neco“);

builder.append(„String :
„).append(value).append(“ neco“);

builder.append(„String :
„).append(value).append(“ neco“);

builder.append(„String :
„).append(value).append(“ neco“);

return builder.toString();

}

 

public String str3(int value) {

String str =

„String : “ + value + “ neco“

+ „String : “ + value + “ neco“

+ „String : “ + value + “ neco“

+ „String : “ + value + “ něco“;

return str;

}

Pří dostatečném množství opakování 1 000 000
dostaneme tyto hodnoty:

  • str1 1406 ms
  • str2: 633 ms
  • str3: 697 ms

Z naměřených hodnot vidíme, že metoda str1 je cca
2.2x pomalejší než další 2 metody. A důvodem je, že
compilátor převádí retězení Stringu pomocí ‚+‘ na
volání StringBuilder.append(). Takže když se podíváme
na první metodu str1() tak vlastně vytváříme 4x
instanci třídy StringBuilder. Detail si můžete
prohlidnout v příloze přímo na výpisu bytecode, získaný utilitkou javap, která
je v JDK.

Java primitives X Wrapper types

Java není čistě OOP jazyk, právě protože má
primitivní datové typy jako je int, boolean.
Samozřejmně existují jejich objektové reprezentace
definované v java.lang, např. Java.lang.Integer apod.
Java. Díky tomu, že Java provádí autoboxing
můžeme pracovat s objektovými
reprezentacemi jako by to byl primitivní datový typ.
Ale autoboxing, něco stojí, kolik ukazuje tyto dvě
jednoduché metody:

public Integer secti(Integer i1, Integer i2) {

return i1 + i2;

}

 

public int secti2(int i1, int i2) {

return i1 + i2;

}

Jak daný autobxing vypadá ukazuje výpis bytecodu

public java.lang.Integer secti(java.lang.Integer,
java.lang.Integer);

Code:

0: aload_1

1: invokevirtual #9; //Method
java/lang/Integer.intValue:()I

4: aload_2

5: invokevirtual #9; //Method
java/lang/Integer.intValue:()I

8: iadd

9: invokestatic #10; //Method
java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

12: areturn

public int secti2(int, int);

Code:

0: iload_1

1: iload_2

2: iadd

3: ireturn

Po provedení testu, kdy jsem jednotlivé metody
volal v cyklu 1 000 000x výsledky jednotivých metod:

  • secti: 117 ms
  • secti2: 0 ms

java.util.Vector x
java.util.ArrayList

Na mnoha místech, zejména v kódech 10 let starém se
používá Vector místo ArrayList po malé diskuzi s
kolegy byly i takový(pracovně déle sloužící), kteří
neví, jaký je rozdíl mezi těmito kolekcemi. Hlavním a
největším rozdílem je, že všechny kolekce, které byly
přidány v rámci Java 1.2 a později nejsou synchronized. Hastable x HashMap, Stack x
LinkedList. Protože stejně se snima v 95% pracuje v
rámci jednoho vlákna a pokud je potřeba přístup do
kolekce v rámci více vláken, existuje utils třída
java.util.Collections a její statické metody
synchronizedXXX, které vytvoří synchronized kolekci.
Rozdíl v časech mezi třídami Vector a ArrayList na
nejvíce používaných operací tj. Metoda add
a iterace přes Iterator. Uvedené časy jsou
po 20 opakování nad kolekcemi o 100 000 objektů. Celý
test viz TestList.java.

  • add Vector: 8.05 ma
  • add ArrayList: 3.4 ms
  • iterator Vector: 14.7 ms
  • iterator ArrayList: 3.95 ms

Shrnutí

Tyto věci neurychlí aplikaci zázračním způsobem,
ale jak se říká „kupka ke kupce a je z toho
hromada
„. A pokud budete mít aplikaci špatně
navrženou a napsanou, tak budete mít asi větší
starosti jak jí vůbec udržovat a rozvíjet, než si
hrát s takovýma drobnostma.

Když už přetěžujete metodu toString(), zejména u
domain objektů pro lepší logování, vyhněte se prvnímu
spůsobu, i když je to taková opičí práce nebuďtě
líní. A ještě lepší řešení, nechte si metodu
vygenerovat. V Netbeans to jde například po zmáčknutí
alt+Insert.

Používejte primitivní datové
typy kde to jen jde, protože s
autoboxingem je spojeno i hodně úskalí, např. musíte
kontrolovat hodnotu na null a to také znamená, že
java.util.Boolean nemá jen true a false, ale má 3
stavy true, false a null.

Další pěknou ukázkou jen si zkuste typnout co
vypíše tučně označený kód 🙂

     Integer a = 128;


     Integer b = 128;





    System.out.println („a >= b : “ +
(a>=b));


    System.out.println („a > b  : “ +
(a>b));


    System.out.println („a == b : “ +
(a==b));






    System.out.println („—————-„);





    Integer x = -128;


    Integer y = -128;





    System.out.println („x >= y : “ +
(x>=y));


    System.out.println („x > y  : “ +
(x>y));
    System.out.println („x == y : “ +
(x==y));
 
 Pokuď se dostanete při čtení až semka uvítal
bych nějaké další příklady, které se třeba vyskytují
na vašich projektech.

Seznam příloh: