Programovací jazyk Clojure 9: validátory, pozorovatelé a kooperace mezi Clojure a Javou

Pavel Tišnovský 7. 8. 2012

V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji Javy se již podeváté budeme zabývat popisem jazyka Clojure postaveného nad JVM. Dnes se seznámíme s takzvanými validátory (validators), hlídači/pozorovateli (watchers) a taktéž způsobem kooperace mezi jazykem Clojure a jazykem Java.

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

3. Validátory: validators

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

7. Volání konstruktorů

8. Volání metod javovských objektů

9. Odkazy na Internetu

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:

widgety

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

  1. Clojure.org: Clojure home page
    http://clojure.org/downloads
  2. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  3. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  4. Clojure.org: Atoms
    http://clojure.org/Atoms
  5. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  6. A Couple of Clojure Agent Examples
    http://lethain.com/a-couple-of-clojure-agent-examples/
  7. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  8. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  9. 4Clojure
    http://www.4clojure.com/
  10. ClojureDoc
    http://clojuredocs.org/
  11. Clojure (Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  12. Clojure (Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  13. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  14. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  15. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  16. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  17. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun.com/develo­per/technicalArticles/Dyn­TypeLang/
  18. JSR 223: Scripting for the JavaTM Platform
    http://jcp.org/en/jsr/detail?id=223
  19. JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
    http://jcp.org/en/jsr/detail?id=292
  20. Java 7: A complete invokedynamic example
    http://niklasschlimm.blog­spot.com/2012/02/java-7-complete-invokedynamic-example.html
  21. InvokeDynamic: Actually Useful?
    http://blog.headius.com/2007/01/in­vokedynamic-actually-useful.html
  22. A First Taste of InvokeDynamic
    http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html
  23. Java 6 try/finally compilation without jsr/ret
    http://cliffhacks.blogspot­.com/2008/02/java-6-tryfinally-compilation-without.html
  24. An empirical study of Java bytecode programs
    http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/
  25. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  26. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  27. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  28. Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
    http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/
  29. 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/
  30. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  31. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  32. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  33. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  34. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  35. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  36. BCEL Home page
    http://commons.apache.org/bcel/
  37. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  38. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  39. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  40. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  41. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  42. ASM Home page
    http://asm.ow2.org/
  43. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  44. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  45. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  46. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  47. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  48. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  49. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  50. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  51. Cobertura
    http://cobertura.sourceforge.net/
  52. FindBugs
    http://findbugs.sourceforge.net/
  53. GNU Classpath
    www.gnu.org/s/classpath/
  54. Java VMs Compared
    http://bugblogger.com/java-vms-compared-160/
  55. JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
    http://www.jcp.org/en/jsr/de­tail?id=223
  56. Scripting for the Java Platform
    http://java.sun.com/develo­per/technicalArticles/J2SE/Des­ktop/scripting/
  57. Scripting for the Java Platform (Wikipedia)
    http://en.wikipedia.org/wi­ki/Scripting_for_the_Java_Plat­form
  58. Java Community Process
    http://en.wikipedia.org/wi­ki/Java_Specification_Requ­est
  59. Java HotSpot VM Options
    http://www.oracle.com/technet­work/java/javase/tech/vmop­tions-jsp-140102.html
  60. Great Computer Language Shootout
    http://c2.com/cgi/wiki?Gre­atComputerLanguageShootout
  61. Java performance
    http://en.wikipedia.org/wi­ki/Java_performance
  62. Trying the prototype
    http://mail.openjdk.java.net/pi­permail/lambda-dev/2010-August/002179.html
  63. Better closures (for Java)
    http://blogs.sun.com/jrose/en­try/better_closures
  64. Lambdas in Java: An In-Depth Analysis
    http://www.infoq.com/articles/lambdas-java-analysis
  65. Class ReflectiveOperationException
    http://download.java.net/jdk7/doc­s/api/java/lang/Reflective­OperationException.html
  66. Scala Programming Language
    http://www.scala-lang.org/
  67. Run Scala in Apache Tomcat in 10 minutes
    http://www.softwaresecret­weapons.com/jspwiki/run-scala-in-apache-tomcat-in-10-minutes
  68. Fast Web Development With Scala
    http://chasethedevil.blog­spot.cz/2007/09/fast-web-development-with-scala.html
  69. Top five scripting languages on the JVM
    http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855
  70. Proposal: Indexing access syntax for Lists and Maps
    http://mail.openjdk.java.net/pi­permail/coin-dev/2009-March/001108.html
  71. Proposal: Elvis and Other Null-Safe Operators
    http://mail.openjdk.java.net/pi­permail/coin-dev/2009-March/000047.html
  72. Java 7 : Oracle pushes a first version of closures
    http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/
  73. Groovy: An agile dynamic language for the Java Platform
    http://groovy.codehaus.org/Operators
  74. Better Strategies for Null Handling in Java
    http://www.slideshare.net/Step­han.Schmidt/better-strategies-for-null-handling-in-java
  75. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  76. Java Virtual Machine
    http://en.wikipedia.org/wi­ki/Java_virtual_machine
  77. ==, .equals(), compareTo(), and compare()
    http://leepoint.net/notes-java/data/expressions/22com­pareobjects.html
  78. New JDK7 features
    http://openjdk.java.net/pro­jects/jdk7/features/
  79. Project Coin: Bringing it to a Close(able)
    http://blogs.sun.com/darcy/en­try/project_coin_bring_clo­se
  80. CloseableFinder source code
    http://blogs.sun.com/darcy/re­source/ProjectCoin/Closea­bleFinder.java
  81. Joe Darcy blog about JDK
    http://blogs.sun.com/darcy
  82. Java 7 – more dynamics
    http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/
  83. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun.com/develo­per/technicalArticles/Dyn­TypeLang/index.html
Našli jste v článku chybu?
DigiZone.cz: Ultra HD v praxi a v Portugalsku

Ultra HD v praxi a v Portugalsku

Root.cz: Hořící telefon Samsung Note 7 zapálil auto

Hořící telefon Samsung Note 7 zapálil auto

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

Vitalia.cz: Antibakteriální mýdla nepomáhají, spíš škodí

Antibakteriální mýdla nepomáhají, spíš škodí

Vitalia.cz: Tradiční čínská medicína a rakovina

Tradiční čínská medicína a rakovina

Lupa.cz: Adblock Plus začal prodávat reklamy

Adblock Plus začal prodávat reklamy

Podnikatel.cz: ČSSZ posílá přehled o důchodovém kontě

ČSSZ posílá přehled o důchodovém kontě

Podnikatel.cz: Udělali jsme velkou chybu, napsal Čupr

Udělali jsme velkou chybu, napsal Čupr

Lupa.cz: Proč jsou firemní počítače pomalé?

Proč jsou firemní počítače pomalé?

DigiZone.cz: Parlamentní listy: kde končí PR...

Parlamentní listy: kde končí PR...

Vitalia.cz: Tesco nabízí desítky tun jídla zdarma

Tesco nabízí desítky tun jídla zdarma

Lupa.cz: Cimrman má hry na YouTube i vlastní doodle

Cimrman má hry na YouTube i vlastní doodle

Podnikatel.cz: Letáky? Lidi zuří, ale ony stále fungují

Letáky? Lidi zuří, ale ony stále fungují

DigiZone.cz: Technisat připravuje trojici DAB

Technisat připravuje trojici DAB

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

DigiZone.cz: Numan Two: rozhlasový přijímač s CD

Numan Two: rozhlasový přijímač s CD

Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

TEST: Vyzkoušeli jsme pražské taxikáře

Podnikatel.cz: Nemá dluhy? Zjistíte to na poště

Nemá dluhy? Zjistíte to na poště