tifyty

pure Java, what else ?

Java Horror 3

Motto: Olyan dolgok a Java nyelvről, amelyekről nem tudtál, és azt kívánod, bár most se tudnád.

    Map z = new HashMap() {{ put("A",1); put("B",2);}};

Most csak nézel? Aztán előveszed az Eclipse-t. És csodálkozol, mert lefordul, és működik is. Aztán rájössz.

16 responses to “Java Horror 3

  1. kirunews október 10, 2013 12:07 du.

    Ez miért horror? Ha rákeresel arra, hogy initialize Java map akkor ilyeneket találsz (https://www.google.nl/search?q=initialize+java+map). Tényleg érdekel, hogy ez miért ellenjavallott.

    • Peter Verhas október 10, 2013 12:24 du.

      Azért, mert ezzel létrehozol egy inner class-t (nem nested, hanem inner, vagyis nem static class), aminek van egy referenciája arra az objektumra amelyikben létre lett hozva, amelyikhez tartozik, mert elvileg az inner class hozzáférhet a körülvevő osztály mezőihez. Ezen keresztül pedig ez az osztály elérhető marad, és a GC nem tudja kidobni, ami problémát okozhat. Nem feltétlenül okoz, de okozhat.

      Általánosabban ez egy olyan nyelvi konstrukció, amelyik implicit módon olyan struktúrákat generál, amelyek nem látszanak könnyen a nyelvi leírásból, és ezért programozási hibákat indikálhat.

      • Varga Róbert október 17, 2013 2:30 de.

        Szia Péter!

        Őszintén szólva nem egészen értem a GC-s problémádat. Minden élő objektum tartalmaz referenciát az osztályára és ezen keresztül tranzitíven minden ősosztályára, tehát ez semmi különbséget nem jelent a nem anonim akármilyen (esetünkben HashMap) leszármazott osztályhoz képest.

        Szerintem kevered azzal az esettel, mikor vagy egy ThreadLocal-ban vagy egy szülő class-loaderben levő statikus attributumban marad hivatkozás egy osztály objektumra (amire az ember általában nem gondol az az array típus komponens típusra való hivatkozásán keresztül tipizált tömb esetén, hiába üres a tömb) ami ezáltal class-loader szivárgást okoz undeployment és minden objektum eldobása után.

        Mellesleg osztályokat a GC elég ritkán dobál ki (mivel ehhez a permgent kéne szemétgyűjteni amit meg nem régóta csinál csak a Java, másrészt az osztályokra való összes hivatkozást meg kell szüntetni), emiatt szokott a Java időnként OutOfMemoryError: PermGen space-el elszállni.

        • Varga Róbert október 17, 2013 3:05 de.

          Ja már látom hogy nem a leszármazott class-ra hanem a metódust tartalmazó osztályra mutató $0 referenciával van gondod. Bocsi, kicsit fáradt vagyok 🙂

          1. Hozd létre statikus metódusban és akkor nincs $0.

          2. Nem vagyok biztos benne, hogy megmarad-e a $0 referencia JIT után ha nem használod a kódban. Mivel annyit kell szenvedni az attributumok cache line paddingjéhez deklarált haszontalan attributumok életbentartásával, abszolut nem lennék biztos hogy a JIT nem hajitja-e ki úgy ahogy van ha nem hivatkozik senki a ContainingClass.this-re.

          3. Ilyen alapon az összes anonim osztályt tiltsd be, az összes API-t ami callback-eket vár, stb.

          4. Ilyen alapon a closure-öket is tiltsd majd be Java8-tól.

  2. tvk október 10, 2013 12:26 du.

    Ja ez szerintem sem annyira horror mint az előzőek, de azért saját prodaksön kódunkból irtanám, még akkor is ha nem használnánk Guava-t.

  3. Verhás István október 10, 2013 12:42 du.

    Anonymous inner class és instance initializer, de azért még gusztustalan. Ez a szubjektív véleményem. Egyébként meg nem java szerű vagyis a nyelv létrehozójának eredeti szándéka nem ez volt.
    Ha az egyszerűségre vágysz, mondjuk így def z = [“A”:1,”B”:2] akkor használj groovy-t. Ha maradsz a java-nál akkor legyél java szerű.

  4. Mindegy október 10, 2013 1:45 du.

    Nem volna túlzottal jó ha a ” Java Horror ” szóösszefüggés égne be az emberek agyába a Java nyelv kapcsán. Már vagy harmadjára olvasom a hwsw oldalpaneljén ezt a kreténséget. Ne járasd már le a Java platformot ember. Ismered a mondást: “Nem sz@runk oda ahonnan eszünk.”

    • Peter Verhas október 10, 2013 2:21 du.

      El tudom fogadni, hogy ez a véleményed. Eddig ez nem merült fel bennem, és másban sem (vagy ha igen, nekem nem szólt).

      Azt sem gondolom, hogy a személyes hatásom olyan nagy lenne a Java presztízsére, hogy ez lejáratná. Minden nyelvben vannak marhaságok, és minden nyelvnek megvannak a maga erősségei.

      Aki ismeri a nyelvet, az pontosan a helyén tudja kezelni ezt a posztot. Aki nem, az meg sem érti. A baj azokkal van, akik nem ismerik a nyelvet, és mégis, negatívan hatással van rájuk egy ilyen cikk, csupán a címe folytán. Szerintem az ilyen emberek gondolkodásbéli kihívásokkal küzdenek. (politikailag korrekt voltam?) Az ő számukra akadálymentesítésként azt üzenem, hogy

      A Java egy jó nyelv, és jó programozási környezet!

      Még lesz egy negyedik cikk jövő héten, aztán többet nem. OK?

      • Mefi október 10, 2013 10:50 du.

        Szerintem ilyen bejegyzések és kommentek után (amelyek szakmailag itthon értékes kincsnek számítanak), ha valakinek csak annyi marad meg a fejében, hogy a Java nyelv szar, akkor az egyéb aljasságokra is képes.

        Még ilyen poszotkat!

      • kavai október 11, 2013 9:39 de.

        Jöhetnek még a Java Horror-ok, én személy szerint nagyon jókat szórakozok rajtuk!

  5. Norbert Madarász október 11, 2013 1:02 de.

    Jópofa ez a kis horror sorozat, én támogatom a folytatás.
    A stackoverflow-n egész jó beszélgetés van a “double brace initializer” lingvisztikai trükkről:
    http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization
    Ez pedig egy performancia teszt: https://gist.github.com/pablisco/4368924
    A guava-ra szavazok, ezt jobb elkerülni.

  6. Lacas december 19, 2013 5:16 du.

    Szerintem sem horror. Tehát ha jól értem, ez már jobb megoldásnak számít?:

    static Map mTables = new LinkedHashMap(MAX_TABLE_TAB) {
    private static final long serialVersionUID = 1L;
    {
    put(“asd”, “asdf”);
    put(“asd2”, “asdf”2);

    Elég ha staticba teszem? Vagy hogyan tudnám normálisan inicializálni így ahogy szeretném?

    • Varga Róbert december 19, 2013 6:54 du.

      Ez ugyanúgy anonim osztály marad, tehát aki azt nem szereti, az erre is fújni fog.

      Inicializálásnak szerintem a következő megoldás talán korrektebb annyiban, hogy nem használ anonim osztályokat, cserébe nem teljesen intuitíven olvasható a kód:

      static MapUtils {
        static  Map putInMap(Map map, K key, V value) {
          map.put(key, value);
          return map;
        }
      }
      
      import static ...MapUtils.putInMap;
      class Blah {
          
          Map map = putInMap(putInMap(new HashMap<>(), "blah", 5), "blahblah", 42);
      }
      

      Második alternatíva olyan map ami hasonlóképp bővíthető mint egy StringBuilder, tehát a mutáló műveletre saját magát adja vissza, ezáltal jobban infix operátorosra emlékeztet a kód.

      Harmadik alternativa valami map builder használata, pl.

      class MapBuilder<K,V,T extends Map>  {
          
          public static <K,V,T extends Map> MapBuilder forMap(T map) {
              return new MapBuilder(map);
          }
      
          private final T map;
          public MapBuilder(T map) {
             this.map = map;
          }
      
          public MapBuilder put(K key, V value) {
             map.put(key, value);
             return this;
          }
      
          public T get() {
              return map;
          }
      }
      
      class Blah {
           Map map = MapBuilder.<String,Integer,Map>forMap(new HashMap()).put("blah", 5).put("blahblah", 42).get();
      }
      

      Negyedik alternatíva, anonim map osztály példányát paraméterként adni a HashMap konstruktorának, bár ez felesleges másolgatással és memória allokációval jár.

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: