Obsah
1. Krátké zopakování z minula: identity, stavy a reference v programovacím jazyku Clojure
2. Příklad změny stavu identity – tři verze jednoduchého čítače
4. Demonstrační příklady na použití validátorů
5. Pozorovatelé/hlídači: watchers
6. Kooperace mezi programovacími jazyky Clojure a Java
8. Volání metod javovských objektů
1. Krátké zopakování z minula: identity, stavy a reference v programovacím jazyku Clojure
V minulé části seriálu o Javě i o virtuálním stroji Javy jsme se zabývali technikami, které se v programovacím jazyku Clojure (postaveným nad JVM) používají pro nastavení a změnu stavu v běžící aplikaci. Z čistě teoretického pohledu by sice změna stavu aplikace ve funkcionálních jazycích neměla být vůbec umožněna, čímž by se mimochodem do značné míry vyřešil problém s paralelizací (a s ní souvisejícími deadlocky), ovšem v praxi je většinou nutné se umět se změnou stavu vypořádat takovým způsobem, aby se jednalo o činnost, která je provedena za přesně stanovených podmínek (viz též programovací jazyk Haskell, v němž jsou pro tento účel použité monády, které jsou z teoretického hlediska velmi čistým řešením tohoto problému, ovšem odlišným od řešení, ke kterému se přiklonil Rich Hickey v případě jazyka Clojure).
Kvůli podpoře změny stavu za přesně stanovených podmínek se v programovacím jazyku Clojure zcela záměrně nepoužívá koncept běžných proměnných, které se mohou měnit kdykoli a v jakémkoli vlákně (kde je proměnná viditelná) a namísto toho se zavedl koncept takzvaných identit, které mohou v různém čase běhu aplikace nabývat různých stavů, přičemž se zde pojmem stav označují hodnoty libovolného neměnitelného datového typu (do této kategorie ostatně spadají všechny datové typy nabízené přímo jazykem Clojure). S identitami a jejich stavy se v Clojure pracuje pomocí takzvaných referencí. Změna stavů identit může být provedena buď koordinovaně (v transakci, s využitím softwarově řízené transakční paměti) či naopak nezávisle na ostatních identitách. Koordinovanou změnu stavu umožňují reference typu ref, nezávislou změnu stavu pak reference typu atom a agent.
Změna, resp. změny stavů identit se taktéž odlišují v tom, že mohou být provedeny buď synchronně či asynchronně – opět v závislosti na potřebách konkrétní vyvíjené aplikace. Synchronní změna stavu identit je provedena ihned a tudíž přímo ve vláknu, které tuto změnu provádí (synchronní a současně i nezávislá změna stavu identity je tedy z hlediska vývojáře prakticky totožná se změnou hodnoty proměnné). Naopak asynchronní změna stavu identit(y) nemusí být provedena ihned, ale někdy v blíže neurčené budoucnosti. To znamená, že asynchronní změnu je možné implementovat v jiném vlákně. Synchronní změna stavu je provedena v případě použití referencí typu ref a atom, asynchronní změna stavu identit je prováděna v případě využití referencí typu agent:
Jméno | Var | Ref | Atom | Agent |
---|---|---|---|---|
Změna stavu | synchronní | synchronní | synchronní | asynchronní |
Typ změny | lokální, v rámci jednoho vlákna | koordinovaná | nezávislá | nezávislá |
Podpora transakcí | ne | ano | ne | ne |
2. Příklad změny stavu identity – tři verze jednoduchého čítače
Pokud se programovací jazyk Clojure učí vývojář, který již pracoval v nějakém jiném programovacím jazyce, ať již se jedná o jazyk funkcionální či imperativní, může mu koncept identit, jejich stavů a referencí použitých pro přístup ke stavům identit připadat v některých případech zbytečně složitý a omezující (například mu může vadit nutnost použití transakcí či nutnost dereferencování hodnot při čtení stavu). To je ovšem ve skutečnosti vlastnost a nikoli chyba v návrhu Clojure, protože ve chvíli, kdy by vývojáři mohli používat běžné proměnné a měnit tak jejich stavy prakticky kdykoli, vytratila by se jedna z předností tohoto programovacího jazyka, tj. do značné míry bezproblémový návrh paralelních programů. Pro určitou analogii nemusíme chodit daleko – zavedení silného typového systému taktéž programátory do určité míry omezuje oproti systému slabě typovému, ale výhody silného typového systému nakonec ve většině případů převažují, a to nezávisle na tom, zda je typová kontrola prováděna staticky či dynamicky.
Podívejme se nyní na jednoduchý problém a některé způsoby jeho řešení. Jedná se o implementaci čítače, který má nějakou počáteční hodnotu (pro jednoduchost nulu) a existuje operace pro zvýšení jeho hodnoty a samozřejmě pro přečtení jeho hodnoty. Nejjednodušší implementace čítače by spočívala ve využití reference typu var, což je referenční typ, který se nejvíce přibližuje chápání běžné proměnné v dalších programovacích jazycích. Pokud má však být čítač vytvořen tak, aby ho bylo možné použít ve více vláknech, je vhodnější ho implementovat buď jako atom nebo jako referenci typu ref, jejíž hodnota se zvyšuje v transakci. Podívejme se nejprve na řešení využívající referenci typu atom:
; vytvoření čítače (def counter (atom 0)) ; jeden ze způsobů zvýšení hodnoty čítače (swap! counter + 1) (swap! counter inc) ; přečtení hodnoty čítače @counter
Použití softwarově řízené transakční paměti pro implementaci čítače sice vypadá jako kanón na vrabce, ale může mít v některých případech své opodstatnění, například tehdy, pokud se v transakci nějak pracuje s aktuální hodnotou čítače:
; vytvoření čítače (def counter (ref 0)) ; jeden ze způsobů zvýšení hodnoty čítače (dosync ( (alter counter +1)) (dosync ( (alter counter inc)) ; přečtení hodnoty čítače @counter
Jako malou kuriozitu si můžeme ukázat i použití agentů, ovšem změna hodnoty čítače je v tomto případě provedena asynchronně v jiném vláknu, což znamená, že při čtení hodnoty čítače (přes dereferencování) se musí vlákna opět sesynchronizovat. To je pochopitelně náročnější, než pouhé atomické přičtení jedničky. Jedná se však pouze o demonstrační příklad:
; vytvoření čítače (def counter (agent 0)) ; jeden ze způsobů zvýšení hodnoty čítače (send counter + 1) (send counter inc) ; přečtení hodnoty čítače @counter
Vážený čtenář již asi odhadl, že v tomto případě je nejlepší a z implementačního hlediska i nejefektivnější pro implementaci čítače použít referenci typu atom, proto si ukažme, jak by se dal čítač jednoduše implementovat s využitím uzávěru (closure):
; funkce counter a s ni "uzavrena" hodnota n (let [n (atom 0)] (defn counter [] (swap! n inc))) user=> (counter) 1 user=> (counter) 2 user=> (counter) 3
3. Validátory: validators
Prozatím jsme si popsali pouze čtyři typy operací, které lze s referencemi všech čtyř typů provádět. Jednalo se zejména o vlastní vytvoření nové reference. Dále pak o nastavení reference na určitou hodnotu, resp. přesněji řečeno změnu stavu identity. Třetí operací byla změna hodnoty reference takovým způsobem, že se na stávající hodnotu aplikovala nějaká funkce a poslední popsanou operací bylo získání aktuální hodnoty reference s využitím dereferencování. Všechny čtyři typy operací nad všemi čtyřmi referenčními typy jsou vypsány v následující tabulce:
Typ | Var | Ref | Atom | Agent |
---|---|---|---|---|
Vytvoření | (def name value) | (ref value) | (atom value) | (agent value) |
Nastavení hodnoty | (set! name value) | (ref-set ref value) | (reset! atom value) | × |
Aplikace funkce | × | (alter ref funkce) | (swap! atom funkce) | (send agent funkce) |
Čtení hodnoty | name | @ref | @ref | @ref |
Ovšem zajímavé a možná i poněkud překvapivé je to, že operací prováděných s referenčními typy existuje ještě větší množství, na rozdíl od běžných proměnných, které lze jen nastavit či přečíst k nim přiřazenou hodnotu. Velmi užitečné mohou být takzvané validátory (validators). Tímto slovem jsou v programovacím jazyku Clojure označeny funkce, které se volají ve chvíli, kdy se Clojure snaží změnit stav identity. V tomto okamžiku je možné s využitím validátoru zajistit kontrolu nad tím, že stav nebude nastaven na nějakou nepovolenou hodnotu. Obecně by validátor měl být implementován pomocí funkce bez vedlejších efektů (neměl by se tedy například měnit stav běžícího programu), který v případě, že je nový stav v pořádku, vrátí pravdivostní hodnotu true a v případě, že nastavovaná hodnota je z libovolného pohledu neakceptovatelná, vrátí buď false, nebo se vyvolá výjimka. Validátor se pro libovolnou referenci registruje pomocí funkce set-validator!, což si ukážeme na demonstračních příkladech uvedených ve čtvrté kapitole.
Možnost využití validátorů představuje jednu z variant, jak do vytvářeného programového kódu přidat detekci potenciálně chybových stavů programu. Důležité je taktéž chování Clojure v případě, že již při registraci validátoru je aktuální stav identity nastaven na hodnotu, kterou by validátor měl vyhodnotit jako neakceptovatelnou – v tomto případě se ihned vyvolá výjimka a validátor není zaregistrován, popř. zůstane zaregistrován původní validátor (pokud ovšem nějaký validátor předtím existoval). Zrušení registrovaného validátoru je snadné – funkci set-validator! postačuje namísto skutečné funkce předat pouze hodnotu nil, nezávisle na tom, zda nějaký validátor byl či nebyl zaregistrován.
4. Demonstrační příklady na použití validátorů
V této kapitole si ukážeme způsob použití validátorů. Jak již bylo řečeno v předchozím textu, je možné validátory použít na libovolný typ reference, ovšem my se budeme zabývat jejich použitím společně s referenčními typy ref, atom a agent, protože u referenčního typu ref je použití validátorů omezeno na lokální vazby, nikoli na vazby vytvořené na globální úrovni. V prvním demonstračním příkladu je validátor nastaven na kontrolu referenčního typu ref takovým způsobem, že se kontroluje, zda je nová hodnota sudým číslem:
; vytvoření reference typu ref user=> (def x (ref 42)) #'user/x ; nastavení validátoru pro tuto referenci user=> (set-validator! x (fn [val] (even? val))) nil ; otestujeme, zda validátor skutečně funguje: ; - nastavení nové hodnoty user=> (dosync (ref-set x 10)) 10 ; - změna hodnoty user=> (dosync (alter x + 10)) 20 ; nastavení nevalidní hodnoty user=> (dosync (alter x + 1)) IllegalStateException Invalid reference state clojure.lang.ARef.validate (ARef.java:33)
V posledním případě validátor správně zachytil pokus o změnu stavu identity na hodnotu, která není sudá. Ovšem kontrola se provádí „vně“ transakce, tudíž je možné uvnitř transakce přechodně nastavit i špatnou hodnotu bez toho, aby se nahlásila chyba (opět se zde tedy uplatňují pravidla ACID):
; vytvoření reference typu ref user=> (def x (ref 42)) #'user/x ; nastavení validátoru pro tuto referenci user=> (set-validator! x (fn [val] (even? val))) nil ; dvojí změna hodnoty uvnitř transakce je OK ; i když "mezistav" je špatný user=> (dosync (alter x + 1) (alter x + 1)) 12
Ve druhém demonstračním příkladu je ukázáno použití validátoru pro referenční typ atom:
; vytvoření reference typu atom user=> (def my-atom (atom 42)) #'user/my-atom ; funkce použitá validátorem user=> (defn positive? [val] (> val 0)) #'user/positive? ; nastavení validátoru user=> (set-validator! my-atom (fn [val] (positive? val))) nil ; test funkce validátoru ; - nastavení nové hodnoty user=> (reset! my-atom 20) 20 ; - nastavení špatné hodnoty user=> (reset! my-atom 0) IllegalStateException Invalid reference state clojure.lang.ARef.validate (ARef.java:33) ; test funkce validátoru ; - změna hodnoty user=> (swap! my-atom + 2) 23 ; změna NA špatnou hodnotu user=> (swap! my-atom - 1000) IllegalStateException Invalid reference state clojure.lang.ARef.validate (ARef.java:33)
Podobně je tomu v případě, že je validátor použit pro referenční typ agent:
; vytvoření reference typu agent user=> (def my-agent (agent 42)) #'user/my-agent ; nastavení validátoru user=> (set-validator! my-agent (fn [x] (even? x))) nil ; test funkce validátoru ; - změna hodnoty user=> (send my-agent + 10) #<Agent@e3849c: 52> ; nastavila se nová hodnota? user=> @my-agent 52 ; test funkce validátoru ; - pokus o nastavení špatné hodnoty user=> (send my-agent + 1) #<Agent@e3849c: 52> ; ok, validátor změnu hodnoty povolil ; nastavila se nová hodnota? user=> @my-agent 52 ; nikoli, protože validátor to nepovolil
5. Pozorovatelé/hlídači: watchers
Kromě validátorů popsaných v předchozích dvou kapitolách je možné ke každé referenci zaregistrovat i libovolné množství takzvaných pozorovatelů či hlídačů (watcher) – použití slova „pozorovatel“ je možná v tomto případě vhodnější, protože „hlídač“ evokuje nějaký subjekt, který dokáže vyvolat nějakou další událost, což však v jazyce Clojure neplatí. Podobně jako v případě validátorů je i pozorovatel implementován nějakou funkcí bez vedlejších efektů, která je zavolána tehdy, pokud se změní hodnota nějaké reference (= stav identity). Zatímco však validátor vykonával nějakou aktivní roli a zasahoval tak do procesu změny stavu hodnoty, u pozorovatelů se očekává, že budou v tomto ohledu pasivní, tj. že například pouze zaznamenají, že ke změně stavu hodnoty došlo. Navíc je umožněno, aby pro jednu referenci bylo zaregistrováno větší množství pozorovatelů, které se od sebe odlišují pomocí unikátního klíče (ten je pozorovateli předán při každém jeho zavolání). Třetím rozdílem je to, že pozorovatel při svém zavolání získá jak starou hodnotu reference, tak i hodnotu novou a dokonce může být zavolán i několikrát – to v případě opakování transakcí.
Ukažme si opět několik demonstračních příkladů. Ve všech příkladech bude ve funkci pozorovatele použita funkce on-change vypsaná níže, která sice při striktním pohledu není bez vedlejších efektů, ale vedlejším efektem ve skutečnosti není změna stavu programu, ale pouze výpis textu na standardní výstup, což můžeme akceptovat:
(defn on-change [key identity old-val new-val] (println (str "Old value: " old-val)) (println (str "New value: " new-val)))
Nejprve si ukážeme chování pozorovatele u referenčního typu ref:
; vytvoření reference typu ref user=> (def x (ref 42)) #'user/x ; registrace pozorovatele user=> (add-watch x "watch-1" on-change) #<Ref@1e903d5: 42> ; změna hodnoty reference v transakci user=> (dosync (alter x + 1 )) Old value: 42 New value: 43 43 ; dvojí změna hodnoty reference v transakci user=> (dosync (alter x + 1) (alter x - 1)) Old value: 43 New value: 43 43 ; odstranění pozorovatele user=> (remove-watch x "watch-1") #<Ref@1e903d5: 43> ; změna hodnoty reference v transakci user=> (dosync (alter x + 1)) 44
Ve druhém demonstračním příkladu jsou k referenčnímu typu atom zaregistrováni dva pozorovatelé (zde pro jednoduchost představováni shodnou funkcí):
; vytvoření reference typu atom user=> (def my-atom (atom 42)) #'user/my-atom ; registrace prvního pozorovatele user=> (add-watch my-atom "watch-1" on-change) #<Atom@1ee148b: 42> ; registrace druhého pozorovatele user=> (add-watch my-atom "watch-2" on-change) #<Atom@1ee148b: 42> ; změna hodnoty reference v transakci user=> (reset! my-atom 0) Old value: 42 New value: 0 Old value: 42 New value: 0 0 ; přečtení hodnoty - dereference user=> @my-atom 0
Nyní oba pozorovatele odstraníme:
; vytvoření reference typu agent user=> (remove-watch my-atom "watch-1") #<Atom@1ee148b: 0> user=> (remove-watch my-atom "watch-2") #<tom@1ee148b: 0> ; nastavení nové hodnoty již není sledováno user=> (reset! my-atom 99) 99
6. Kooperace mezi programovacími jazyky Clojure a Java
Zajímavé je, že i když je tento článek již devátým článkem, který vychází v cyklu o novém programovacím jazyce, prozatím jsme si popsali jen poměrně velmi malé množství funkcí, speciálních forem a maker, které se nachází ve standardních knihovnách Clojure. To je způsobeno dvěma fakty. První příčinou je to, že mnohé již popsané funkce je možné aplikovat na různé datové typy, typicky na seznamy, vektory, množiny a někdy též mapy. Navíc se řetězce považují za sekvence znaků, tudíž je mnoho těchto funkcí snadno aplikovatelných i na řetězce. Tento přístup je pro funkcionální jazyky do značné míry typický: nabídnou vývojářům pouze několik univerzálních datových typů a k nim příslušné univerzální funkce (s trochou nadsázky dokonce můžeme říct, že pravý opak představuje klasický objektově-orientovaný přístup s funkcemi/metodami dostupnými pouze pro určitý specifický datový typ – třídu, resp. pro její instance – tím nechci říci, že by OOP přístup byl špatný, má však odlišné uplatnění a dnes se zneužívá i tam, kde není vhodný).
Druhá příčina tohoto stavu je prozaičtější – vzhledem k tomu, že původní implementace jazyka Clojure byla naprogramována přímo pro virtuální stroj Javy (JVM) a programy psané v Clojure jsou překládány do Javovského bajtkódu, bylo by vlastně zbytečné a kontraproduktivní se znovu pokoušet o novou implementaci všech knihoven, které tvoří jak součást Java SE API, tak i externích knihoven a frameworků. Jednalo by se totiž jak o mrhání času vývojářů Clojure (vyvinout a udržovat ucelenou knihovnu skutečně není tak jednoduché, jak se na začátku vývoje může zdát), tak i času programátorů, kteří by chtěli Clojure používat, protože by se museli učit nové API. Tento stav byl sice narušen tím, že Clojure je dnes možné překládat i do JavaScriptu, to však můžeme považovat pouze za indikaci toho, že se začíná jednat o v určitých kruzích dosti populární programovací jazyk (navíc je jeho použití na webu vhodné, například kvůli existenci agentů atd.). V následujících dvou kapitolách si popíšeme první část rozhraní Clojure-Java. Bude se jednat o způsob práce s Javovskými třídami v Clojure.
7. Volání konstruktorů
Při konstrukci instancí javovských tříd i při přístupu k atributům a metodám objektů se v programovacím jazyce Clojure využívá několik speciálních forem. První z těchto forem nese jméno new a způsob jejího použití již vyplývá ze samotného názvu této speciální formy: slouží pro vytvoření instance libovolné javovské třídy, přesněji řečeno takové třídy, u níž lze instance vytvářet. Podívejme se na několik demonstračních příkladů, které použití tohoto makra ozřejmí:
; prázdný řetězec user=> (new String) "" ; řetězec inicializovaný literálem user=> (new String "Hello world") "Hello world" ; vytvoření instance třídy java.util.Date ; (vytvoří se s aktuálním datem) user=> (new java.util.Date) #inst "2012-08-06T21:02:23.348-00:00" ; vytvoření instance třídy java.awt.Color user=> (new java.awt.Color 0.0 1.0 0.0) #<Color java.awt.Color[r=0,g=255,b=0]> ; pokus o zavolání neexistujícího konstruktoru user=> (new Integer) CompilerException java.lang.IllegalArgumentException: No matching ctor found for class java.lang.Integer, compiling:(NO_SOURCE_PATH:6) ; tento příklad je ovšem již v pořádku user=> (new Integer 42) 42 ; ve speciální formě new lze samozřejmě volat i jiné funkce user=> (new Integer (* 6 7)) 42
8. Volání metod javovských objektů
Druhou důležitou speciální formou je forma s prostým názvem . (tečka). Jedná se skutečně o korektní jméno (identifikátor), o čemž se můžeme snadno přesvědčit zavoláním makra doc s předáním tečky jako parametru tohoto makra:
user=> (doc .) ------------------------- . (.instanceMember instance args*) (.instanceMember Classname args*) (Classname/staticMethod args*) Classname/staticField Special Form The instance member form works for both fields and methods. They all expand into calls to the dot operator at macroexpansion time. Please see http://clojure.org/java_interop#dot nil
Speciální forma . se používá pro volání metod, popř. pro přístup k atributům objektů. Opět se podívejme na několik příkladů:
; ekvivalent příkazu Integer.valueOf("42"); user=> (. Integer valueOf "42") 42 ; ekvivalent příkazu Float.MAX_VALUE; user=> (. Float MAX_VALUE) 3.4028235E38 ; ekvivalent příkazu Boolean.TRUE; user=> (. Boolean TRUE) true ; přístup ke konstantnímu atributu user=> (. Math PI) 3.141592653589793
Namísto přímého uvedení jména třídy je možné uvést i jméno navázané na instanci nějakého objektu:
user=> (def my-string "Hello world") #'user/my-string user=> (. my-string length) 11 user=> (. my-string toUpperCase) "HELLO WORLD" user=> (. my-string substring 6) "world"
Poslední důležitou speciální formou je forma s názvem set!, kterou lze použít pro nastavení viditelného atributu objektu. V následujícím příkladu se nejprve vytvoří instance třídy java.awt.Rectangle a posléze se nastaví šířka a výška tohoto obdélníku:
; vytvoření instance třídy java.awt.Rectangle user=> (def rect (new java.awt.Rectangle)) #'user/rect ; převod objektu na řetězec (toString) user=> rect #<Rectangle java.awt.Rectangle[x=0,y=0,width=0,height=0]> ; nastavení šířky obdélníku user=> (set! (. rect width) 320) 320 ; nastavení výšky obdélníku user=> (set! (. rect height) 240) 240 ; převod objektu na řetězec (toString) user=> rect #<Rectangle java.awt.Rectangle[x=0,y=0,width=320,height=240]>
Složitější, praktičtěji zaměřené příklady, si ukážeme příště.
9. Odkazy na Internetu
- Clojure.org: Clojure home page
http://clojure.org/downloads - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - A Couple of Clojure Agent Examples
http://lethain.com/a-couple-of-clojure-agent-examples/ - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc
http://clojuredocs.org/ - Clojure (Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/ - JSR 223: Scripting for the JavaTM Platform
http://jcp.org/en/jsr/detail?id=223 - JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
http://jcp.org/en/jsr/detail?id=292 - Java 7: A complete invokedynamic example
http://niklasschlimm.blogspot.com/2012/02/java-7-complete-invokedynamic-example.html - InvokeDynamic: Actually Useful?
http://blog.headius.com/2007/01/invokedynamic-actually-useful.html - A First Taste of InvokeDynamic
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html - Java 6 try/finally compilation without jsr/ret
http://cliffhacks.blogspot.com/2008/02/java-6-tryfinally-compilation-without.html - An empirical study of Java bytecode programs
http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/ - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/ - Root.cz: JamVM aneb alternativa k HotSpotu nejenom pro embedded zařízení a chytré telefony
http://www.root.cz/clanky/jamvm-aneb-alternativa-k-hotspotu-nejenom-pro-embedded-zarizeni-tablety-a-chytre-telefony/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - BCEL Home page
http://commons.apache.org/bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - FindBugs
http://findbugs.sourceforge.net/ - GNU Classpath
www.gnu.org/s/classpath/ - Java VMs Compared
http://bugblogger.com/java-vms-compared-160/ - JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
http://www.jcp.org/en/jsr/detail?id=223 - Scripting for the Java Platform
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ - Scripting for the Java Platform (Wikipedia)
http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - Java Community Process
http://en.wikipedia.org/wiki/Java_Specification_Request - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - Great Computer Language Shootout
http://c2.com/cgi/wiki?GreatComputerLanguageShootout - Java performance
http://en.wikipedia.org/wiki/Java_performance - Trying the prototype
http://mail.openjdk.java.net/pipermail/lambda-dev/2010-August/002179.html - Better closures (for Java)
http://blogs.sun.com/jrose/entry/better_closures - Lambdas in Java: An In-Depth Analysis
http://www.infoq.com/articles/lambdas-java-analysis - Class ReflectiveOperationException
http://download.java.net/jdk7/docs/api/java/lang/ReflectiveOperationException.html - Scala Programming Language
http://www.scala-lang.org/ - Run Scala in Apache Tomcat in 10 minutes
http://www.softwaresecretweapons.com/jspwiki/run-scala-in-apache-tomcat-in-10-minutes - Fast Web Development With Scala
http://chasethedevil.blogspot.cz/2007/09/fast-web-development-with-scala.html - Top five scripting languages on the JVM
http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855 - Proposal: Indexing access syntax for Lists and Maps
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html - Proposal: Elvis and Other Null-Safe Operators
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html - Java 7 : Oracle pushes a first version of closures
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/ - Groovy: An agile dynamic language for the Java Platform
http://groovy.codehaus.org/Operators - Better Strategies for Null Handling in Java
http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Java Virtual Machine
http://en.wikipedia.org/wiki/Java_virtual_machine - ==, .equals(), compareTo(), and compare()
http://leepoint.net/notes-java/data/expressions/22compareobjects.html - New JDK7 features
http://openjdk.java.net/projects/jdk7/features/ - Project Coin: Bringing it to a Close(able)
http://blogs.sun.com/darcy/entry/project_coin_bring_close - CloseableFinder source code
http://blogs.sun.com/darcy/resource/ProjectCoin/CloseableFinder.java - Joe Darcy blog about JDK
http://blogs.sun.com/darcy - Java 7 – more dynamics
http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/ - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html