Java je tu 30 let: všestranný jazyk formoval moderní informatiku

Včera
Doba čtení: 32 minut

Sdílet

Hrníček s kávou a logem programovacího jazyka Java
Autor: Root.cz s využitím Zoner AI
Právě dnes uběhlo třicet let od představení programovacího jazyka Java i virtuálního stroje Javy. Jak samotný jazyk, tak i její virtuální stroj prošel za tato tři desetiletí poměrně zajímavým vývojem.

Obsah

1. Java oslavuje 30 let od svého vzniku

2. Vznik platformy Javy

3. Vstup do reálného IT světa: JIT překladač

4. Jakým tempem se má programovací jazyk vyvíjet?

5. Java neznamená pouze programovací jazyk, ale celý ekosystém

6. Programovací jazyky pro virtuální stroj Javy aneb zdaleka nejde jen o Javu

7. Stručný přehled jazyků pro JVM

8. Popularita programovacího jazyka Java

9. Třicet let v IT: uvedení do kontextu

10. Nové výzvy pro Javu

11. Java: jazyk pro Internet

12. Java na desktopu

13. Java a hry

14. Závěr

15. Příloha: porovnání rychlosti JVM v režimu interpretru a JITu

16. Výsledky benchmarků

17. Příloha: výsledek překladu metody calcIter C1 a C2 překladačem

18. Odkazy na Internetu

1. Java oslavuje 30 let od svého vzniku

Na stránkách Roota jsme si připomněli (a taktéž trošku oslavili) hned několik kulatých výročí různých programovacích jazyků. Po dvojici článků o třicátých narozeninách Turbo Pascalu 5.5 a šedesátém výročí vzniku programovacího jazyka COBOL jsme si připomněli i sedmdesát let, které uběhly od vzniku nástroje, který dnes nazýváme assembler (i když se původně tento název nepoužíval).

Obrázek 1: Uživatelské rozhraní Turbo Pascalu 5.5.

Nezapomněli jsme ovšem ani na programovací jazyk ALGOL, jehož nejznámější varianta, která se jmenuje ALGOL-60, vznikla skutečně již v roce 1960 a jehož historii jsme si připomněli v tomto článku. Z dalších známých programovacích jazyků jsme oslavili dvacet let Pythonu 2 (článek je to starší, Python 2 již dnes má 25 let a stále na něj kupodivu čas od času narazím, i když méně často, než před pěti lety) a naopak z těch méně známých a populárních jazyků jsme si připomněli 55 let od vzniku jazyka APL.

ibm-5

Obrázek 2: Jedna z populárních dobových učebnic ALGOLU 68 (jeho výročí neslavíme, jak číslovka naznačuje).

Dnes si připomeneme kulaté výročí skutečně těžké váhy v oblasti programovacích jazyků. Třicet let od svého představení totiž slaví Java, tj. jazyk, který byl již relativně krátce po svém vzniku nejpopulárnějším programovacím jazykem vůbec a i dnes se stále (a to s velkým přehledem) drží v první desítce nejpoužívanějších a nejpopulárnějších (což nemusí být ani zdaleka totéž) programovacích jazyků. Java má za sebou poměrně zajímavou historii.

Dokázala totiž nejenom přežít jak zánik původních platforem, pro které původně vznikla, ale přežila i svou „rodnou“ firmu (Sun Microsystems). Co je ale důležitější – Java nezůstala jazykem určeným pro jedinou izolovanou niku, ale adaptovala se v nových oblastech. Tak se stalo, že z programovacího jazyka, který byl původně prezentován jako jazyk určený pro programování mikrovlnných trub a výtahů, se stal jazyk využívaný pro vývoj rozsáhlých systémů běžících na různých platformách (od mobilních telefonů přes desktopová PC až po servery a dokonce i mainframy).

Java 30 let

Obrázek 3: Původní logo programovacího jazyka Java. Toto logo bylo používáno v letech 1996 až 2003. Autorkou tohoto loga je Susan Kare.

2. Vznik platformy Javy

Programovací jazyk Java byl navržen Jamesem Goslingem ze společnosti Sun Microsystems. Mělo se jednat o jazyk umožňující (relativně) snadnou tvorbu aplikací, navíc bez nutnosti řešení správy paměti (ta byla automatická). Z pohledu syntaxe byla Java navržena takovým způsobem, aby se do značné míry podobala jazykům C a C++, což umožnilo snadný přechod programátorů z těchto mainstreamových jazyků (ostatně podobně se postupovalo i u JavaScriptu).

Ovšem z pohledu sémantiky jde o odlišný jazyk, který podporuje objektově orientovaný návrh založený nikoli pouze na hierarchii tříd, ale i na rozhraních (interface). Navíc je to jazyk více dynamický, protože například podporuje reflexi apod. Některé nízkoúrovňové koncepty zůstaly zachovány a zajímavé je, že právě tyto koncepty jsou z dlouhodobého hlediska nejvíce problematické. Jedná se o odlišnou práci s primitivními datovými typy a taktéž o existenci nulové reference (null) – zopakovala se zde tedy (ne)slavná chyba za miliardu dolarů.

Jedním z mot nového programovacího jazyka bylo write once, run anywhere neboli WORA. Nicméně se nejedná o přenositelnost na úrovni zdrojových kódů, ale o přenositelnost již přeloženého kódu. Pokud by se programy napsané v Javě překládaly přímo do strojového kódu dané platformy, pochopitelně by to znamenalo, že přenositelnost nebude zaručena a navíc by jednou přeložené programy nemohly využívat například nová rozšíření instrukčních sad, nové registry atd. (musel by se provést nový překlad). Tento problém byl v případě Javy řešen technologií, která již byla předtím použita u jiných jazyků, například u Pascalu. Namísto překladu programů do strojového kódu se prováděl (a stále provádí) překlad do takzvaného bajtkódu, který je posléze nějakým způsobem spouštěn virtuálním strojem Javy. Bajtkód se buď interpretuje, nebo se překládá JIT (Just in Time) překladačem popř. AOT (Ahead of Time) překladačem.

Java 30 let

Obrázek 4: Novější logo programovacího jazyka Java, které se začalo používat po roce 2003.

3. Vstup do reálného IT světa: JIT překladač

Původní virtuální stroj Javy (JVM) byl interně relativně jednoduchý. Jednalo se totiž o interpret bajtkódu. Zdrojové kódy napsané v Javě byly nejdříve standardním překladačem Javy (javac, ostatně ten je po úpravách používán dodnes) přeloženy do bajtkódu (soubory .class, taktéž používané dodnes, ovšem s vylepšeními). A tento bajtkód byl po spuštění aplikace interpretován, což je sice z implementačního hlediska jednoduché, na druhou stranu však tímto způsobem spouštěné aplikace v žádném případě neoplývaly rychlostí a nemohly v tomto ohledu konkurovat aplikacím přeloženým do nativního kódu. Velkého pokroku bylo dosaženo přidáním Just In Time (JIT) překladače, který se stal nedílnou součástí virtuálního stroje Javy a neustále se vyvíjí.

Java 30 let

Obrázek 5: Nejnovější barvová variace loga jazyka Java.

Dnes je JIT nedílnou součástí platformy Javy. Virtuální stroj Javy se tedy vlastně skládá ze tří hlavních subsystémů. Jedná se o zmíněný JIT překladač, dále o správce paměti a taktéž o běhové prostředí (runtime – interpret, standardní class loader, synchronizační mechanismy, správce vláken). Na rychlost (výkon) aplikací má největší vliv právě JIT. V současnosti se můžeme setkat s několika typy JIT překladačů. Z historických důvodů se dělí na client a server, které se v novějších JVM kombinují do takzvaného vícevrstvého překladače tiered compiler.

Právě existence JIT umožnila, aby se v Javě začaly vytvářet i rozsáhlé a sofistikované programy, které navíc měly srovnatelný výpočetní výkon, jako programy napsané v běžných překládaných programovacích jazycích (C, C++, později například Rust). Jednalo se tedy o pomyslnou vstupenku do světa enterprise systémů – Java se začala používat pro messaging, tvorbu aplikačních serverů, ale dokonce i databází atd.

4. Jakým tempem se má programovací jazyk vyvíjet?

Původní verze programovacího jazyka Java byla z dnešního pohledu v několika ohledech omezená, protože v ní chyběly některé důležité programové konstrukce, specifikátory datových typů atd. Tvůrci Javy stáli před rozhodnutím, jakým tempem se má vlastně tento programovací jazyk vyvíjet a jak rychle do sebe má „absorbovat“ nové vlastnosti. V této oblasti (pokud se zaměříme na populární a používané programovací jazyky) můžeme vidět dva extrémy. Na jedné straně jazyk C, jehož vývoj je velmi pomalý a jeho nové verze si velmi přísně hlídají zpětnou kompatibilitu a novinky jsou poměrně malé. A na straně druhé jazyk C++, který za dobu své existence (40 let) prošel několika vlnami velkých změn, z nichž některé jsou dnes považovány za překonané, ale stále se musí z důvodu zpětné kompatibility udržovat. V tomto případě se došlo do situace, kdy se říká, že specifikace jazyka C++ má své vlastní gravitační pole.

Programovací jazyk Java je v tomto ohledu spíše konzervativní, ovšem vývoj jazyka byl a je nutný, protože se vyvíjí i způsoby tvorby aplikací. Některé změny a vylepšení Javy byly spíše kosmetické, jiné naopak jazyk posunuty na jinou úroveň. Ostatně si to můžeme ilustrovat na dvou příkladech.

První změnou v Javě bylo přidání klíčového slova strictfp v Javě 1.2. Toto klíčové slovo se používá jako modifikátor u deklarace proměnných, návratových typů metod, u tříd atd. a ovlivňuje způsob výpočtů s hodnotami s plovoucí řádovou čárkou: toto slovo vynucuje výpočty a zaokrouhlení přesně odpovídající normě IEEE 754. Jedná se tedy o malou změnu, která ale není zpětně kompatibilní, protože zavedení nového klíčového slova může znamenat, že některé zdrojové kódy nebudou přeložitelné.

Druhým příkladem je zavedení podpory pro generické datové typy. Jedná se o zcela novou sémantiku, která je kompatibilní – původní zdrojové kódy bude možné stále bez problémů přeložit. Současně se jedná o posunutí možností jazyka na novou úroveň, protože je možné pracovat s „typově bezpečnými“ kontejnery atd. Na druhou stranu se tato změna dotýká spíše samotného programovacího jazyka a nikoli jeho bajtkódu. Generické datové typy nejsou plnohodnotnými typy a informace o nich se (velmi zjednodušeně řečeno) nepropisuje do bajtkódu, takže je lze obcházet.

Na těchto příkladech je patrné, že zavádění novinek do programovacích jazyků je sice většinou nutné, ale obecně se nejedná o jednoduchou problematiku.

5. Java neznamená pouze programovací jazyk, ale celý ekosystém

V mnoha případech se termínem „Java“ nemyslí pouze samotný programovací jazyk Java, ale i celý ekosystém, který byl okolo tohoto jazyka postupně vytvořen. V první řadě se pochopitelně jedná o samotný virtuální stroj Javy (Java Virtual Machine neboli JVM), ovšem taktéž nesmíme zapomenout na celé běhové prostředí Javy (Java Runtime Environment neboli JRE), které kromě virtuálního stroje obsahuje i základní knihovnu Javy (a to je pěkný otesánek, resp. býval před podporou modularizace) a další pomocné nástroje (práce s databází certifikátů atd.). Do tohoto ekosystému patří i externí nástroje, například (dříve) Ant, dnes Maven, Gradle apod.

Java 30 let

Obrázek 6: Důležitou součástí ekosystému Javy jsou pochopitelně i integrovaná vývojová prostředí. I ta se postupně vyvíjela a po dlouhou dobu se pravděpodobně nejvíce rozšířeným vývojovým prostředím stala platforma Eclipse, která je taktéž naprogramována v Javě.

Okolo JVM resp. JRE postupem času vznikly i mnohé další nástroje – monitorovací aplikace, nástroje, které se k JVM připojují přes JVM TI (Java Virtual Machine Tools Interface), JDI (Java Debugger Interface) či JDWP (Java Debug Wire Protocol), ale i ucelená integrovaná vývojová prostředí (IDE). Různé monitorovací nástroje využívaly další užitečné rozhraní virtuálního stroje Javy – Java Management Extensions neboli JMX.

Java 30 let

Obrázek 7: Další ukázka dobového integrovaného vývojového prostředí pro Javu založeného na platformě Eclipse.

ibm6

Obrázek 8: Eclipse je skutečně platformou, nad níž lze vytvářet další více či méně sofistikované nástroje. Příkladem je integrované vývojové prostředí pro jazyk COBOL. Tak trochu se zde připomíná tvrzení „Java je COBOLem 21.století“.

6. Programovací jazyky pro virtuální stroj Javy aneb zdaleka nejde jen o Javu

Virtuální stroj Javy (JVM), specifikace JVM a dokonce ani jeho instrukční soubor vlastně nikde striktně nepředpokládají, že JVM bude spouštět pouze bajtkód získaný překladem zdrojových kódů naprogramovaných přímo v Javě. Ve specifikaci JVM je dokonce na několika místech explicitně zmíněn předpoklad, že nad virtuálním strojem Javy budou provozovány i další programovací jazyky umožňující přímý či nepřímý překlad do bajtkódu. Kromě toho je samozřejmě možné přímo v Javě vytvořit interpret prakticky libovolného (interpretovaného) programovacího jazyka, takže vlastně nebude velkým překvapením, když zjistíme, že dnes těchto „JVM jazyků“ již existuje relativně velké množství (minimálně několik desítek) a některé z nich jsou dosti populární. V následující tabulce jsou vypsány ty nejznámější a pravděpodobně nejpoužívanější jazyky pro JVM, a to pro úplnost včetně samotné Javy:

https://www.gnu.org/software/kawa/
# Jazyk pro JVM Stručný popis Odkaz
1 Java primární jazyk pro JVM, bajtkód do značné míry odpovídá právě Javě https://www.oracle.com/ja­va/index.html
2 Clojure moderní dialekt programovacího jazyka Lisp s přidanými funkcionálními prvky https://clojure.org/
3 Groovy dynamicky typovaný jazyk pro JVM http://groovy-lang.org/
4 Rhino jedna z implementací JavaScriptu (dnes již pravděpodobně mrtvý projekt) https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino
5 Nashorn alternativní implementace JavaScriptu (tento projekt je stále živý) https://github.com/openjdk/nashorn
6 JRuby portace jazyka Ruby na JVM http://jruby.org/
7 Jython portace jazyka Python na JVM http://www.jython.org/
8 Kotlin moderní staticky typovaný jazyk http://kotlinlang.org/
9 Scala další moderní jazyk pro JVM https://www.scala-lang.org/
10 Kawa implementace jazyka Scheme s mnoha rozšířeními

Obrázek 9: Logo programovacího jazyka Jython.

7. Stručný přehled jazyků pro JVM

Pro úplnost se ve stručnosti zmiňme o nejznámějších jazycích určených pro běh ve virtuálním stroji Javy.

Kotlin

Prvním programovacím jazykem určeným pro běh nad virtuálním strojem Javy, o němž se dnes alespoň ve stručnosti zmíníme, je jazyk pojmenovaný Kotlin. Jedná se o moderní staticky typovaný programovací jazyk vyvinutý ve společnosti JetBrains a jeho cíl je vlastně velmi podobný cíli, který si dal dále zmíněný a poněkud starší jazyk Scala – efektivní a rychlá tvorba typově bezpečných aplikací určených pro běh nad JVM. Typovost jde ještě o krok dále, než je tomu v Javě, protože například rozlišuje mezi nulovatelnými a nenulovatelnými datovými typy. Na rozdíl od Scaly je však rychlost překladu zdrojových kódů naprogramovaných v Kotlinu rychlejší a blíží se rychlosti překladu kódů napsaných v samotné Javě. Kotlin podporuje různá paradigmata: objektově orientované, procedurální i funkcionální.

Obrázek 10: Logo programovacího jazyka Kotlin.

Scala

Pravděpodobně druhým nejznámějším příkladem programovacího jazyka provozovaného nad JVM je Scala, která nabízí prakticky bezproblémovou spolupráci mezi částmi kódu psanými ve Scale a zbytkem aplikace psaným v Javě (popř. jsou některé projekty psané pouze ve Scale, ovšem provozovány jsou například na ryze javovských serverech – Tomcat, Jetty atd.). Díky tomu, že zdrojové kódy psané ve Scale jsou přímo překládány do bajtkódu, získali tvůrci tohoto programovacího jazyka prakticky zadarmo veškeré vymoženosti, které virtuální stroj Javy (či přesněji řečeno celé JRE) poskytuje – od poměrně pečlivé kontroly bajtkódu při jeho načítání do virtuálního stroje přes použití správců paměti a JIT překladačů (Just in Time Compiler) až po možnost využití rozsáhlých standardních knihoven J2SE a samozřejmě taktéž mnoha dalších knihoven a frameworků, které jsou pro JVM dostupné. Ovšem Scala samozřejmě není jediným programovacím jazykem, který díky překladu do bajtkódu umožňuje využít prakticky veškerého potenciálu JVM/JRE.

Obrázek 11: Logo programovacího jazyka Scala.

Poznámka: ve Scale je částečně naprogramována například Apache Kafka.

Clojure

Z dalších překladačů programovacích jazyků, které pro virtuální stroj Javy vznikly, je podle mého názoru nejzajímavějším jazykem a současně i jazykem s poměrně velkým potenciálem pro budoucnost programovací jazyk s názvem Clojure, jehož autorem a dodnes nejaktivnějším vývojářem a propagátorem je Rich Hickey. Samotný název tohoto jazyka vznikl vložením písmene „j“ (Java/JVM) do slova closure (toto slovo se používá ve smyslu „lexikální uzávěr“ – důležitá abstrakce používaná nejenom ve funkcionálních programovacích jazycích). Velká část předností a pro mnohé vývojáře taktéž záporů programovacího jazyka Clojure vychází z toho, že se jedná o programovací jazyk, jehož syntaxe a sémantika do značné míry vychází z LISPu a Scheme, tedy jazyků známých především tím, že se v programech v nich psaných používá nadměrné množství kulatých závorek. Podrobnější informace o Clojure byly uvedeny v samostatném seriálu, který již vyšel na serveru www.root.cz.

Obrázek 12: Logo programovacího jazyka Clojure.

Groovy

Dalším programovacím jazykem, a nutno říci že jazykem poměrně populárním, je Groovy. Jedná se o jazyk inspirovaný některými dalšími (většinou dynamicky typovanými) programovacími jazyky, jako je Python, Ruby, ale například i Perl. Groovy podporuje objektově orientované programování a oproti Javě umožňuje psát kratší kód, z něhož jsou odstraněny méně podstatné části, které Java jakožto silně staticky typovaný jazyk vyžaduje. Z tohoto důvodu se Groovy velmi často používá všude tam, kde je vyžadovaný skriptovací jazyk běžící nad JVM. Dobrým příkladem je například konzole Jenkinsu, která ve výchozím nastavení používá právě Groovy. Podpora pro tento jazyk je součástí mnoha populárních integrovaných vývojových prostředí, a to včetně IntelliJ IDEA, Netbeans i Eclipse (přes pluginy – doplňkové moduly).

Obrázek 13: Logo programovacího jazyka Groovy.

JRuby, Jython, Rhino a Nashhorn

Zatímco Scala, ClojureGroovy jsou novými jazyky, které původně vznikly přímo a pouze pro potřeby programátorů používajících virtuální stroj Javy (JVM), zmíníme se v této podkapitole alespoň ve stručnosti o jazycích „klasických“, které byly na JVM pouze naportovány. V první řadě se jedná o projekty pojmenované JRuby a Jython, což jsou varianty jazyků Ruby a Python. Původní interpretry Ruby a Pythonu jsou naprogramovány v jazyku C (proto se ostatně tato varianta Pythonu nazývá CPython), JRuby a Jython jsou reimplementace pro JVM (navíc byl Python portován i na platformu .NET ve formě projektu IronPython a existuje i varianta Pythonu nazvaná PyPy naprogramovaná v samotném Pythonu, resp. přesněji řečeno v jeho zjednodušené variantě RPython). Na platformu JVM byl portován i programovací jazyk JavaScript, a to dokonce několikrát. Implementaci JavaScriptu zajišťují projekty Rhino a Nashhorn.

Obrázek 14: Logo programovacího jazyka JRuby.

Kawa

V případě projektu Kawa se jedná o implementaci jazyka Scheme naprogramovanou v Javě a běžící nad virtuálním strojem Javy (JVM). Ovšem současně se v žádném případě nejedná o pouhý primitivní interpret, ale o plnohodnotný překladač jazyka Scheme do bajtkódu JVM. Z benchmarků je patrné, že výsledný kód vůbec není pomalý ale naopak dokáže více než zdárně konkurovat dalším programovacím jazykům, které v současnosti nad JVM existují. Jenže to není vše, protože Kawa dokáže velmi dobře kooperovat i se samotným ekosystémem Javy – lze v ní vytvářet instance Javovských tříd, volat jejich metody, přistupovat k atributům atd. atd. Díky tomu může být Kawa použitelná i v rozsáhlých systémech naprogramovaných v Javě (ostatně LISPovské jazyky již dlouho slouží i ve funkci „lepidel“ mezi jednotlivými částmi aplikace).

Kawa

Obrázek 15: Logo programovacího jazyka Kawa.

Další programovací jazyky portované na JVM

Na virtuální stroj Javy bylo portováno i mnoho dalších programovacích jazyků, ať již se jednalo o překladače či o interpretry. V následující tabulce jsou některé z těchto jazyků vypsány. V prvním sloupci je zobrazen název původního jazyka popř. rodiny jazyků, ve sloupci druhém pak jméno jeho konkrétní implementace pro JVM. Povšimněte si, že některé jazyky byly portovány několikrát (to se ostatně týkalo již výše zmíněného JavaScriptu):

Jazyk Implementace pro JVM
Ada JGNAT
Arden Syntax Arden2ByteCode
COBOL Micro Focus Visual COBOL
ColdFusion Markup Language (CFML) Adobe ColdFusion
ColdFusion Markup Language (CFML) Railo
ColdFusion Markup Language (CFML) Lucee
ColdFusion Markup Language (CFML) Open BlueDragon
Common Lisp Armed Bear Common Lisp
Cypher Neo4j
Mercury Mercury (Java grade)
Pascal MIDletPascal
Pascal Oxygene
Perl 6 Rakudo Perl 6
PHP Quercus
Prolog JIProlog
Prolog TuProlog
R Renjin
Rexx NetRexx
Ruby JRuby
Ruby Mirah
Scheme Bigloo
Scheme Kawa
Scheme SISC
Scheme JScheme
Tcl Jacl
Visual Basic Jabaco

8. Popularita programovacího jazyka Java

Programovací jazyk Java se přibližně po dvě desetiletí (a to je v oboru informatiky velmi dlouhá doba) pohyboval na samotné špičce popularity programovacích jazyků. Netýkalo se to „pouze“ IT profesionálů, protože se Java na některých univerzitách stala primárním programovacím jazykem, který se používal pro jak v kurzech pro výuku programování, tak i například návrhu architektury distribuovaných systémů (messaging) atd. V současnosti sice popularita Javy relativně klesá v porovnání s přímou i nepřímou konkurencí, nicméně se stále jedná o jeden z nejpopulárnějších jazyků současnosti. Z relativně velkého množství různých statistik se podívejme na známý Tiobe index, v němž se Java tento měsíc umístila na velmi dobré čtvrté příčce (dokonce před svým nejbližším konkurentem – jazykem C#):

#
1 Python
2 C++
3 C
4 Java
5 C#
6 JavaScript
7 Go
8 Visual Basic
9 Delphi
11 Fortran

Dlouhodobější trend vývoje popularity Java je zobrazen na tomto grafu.

Ovšem nemůžeme věřit pouze jedné statistice, u které navíc nejsou zcela zřejmé použité metriky. Podívejme se na známý žebříček PYPL PopularitY of Programming Language, ve kterém se Java dokonce umístila na druhém místě, ihned za Python:

1 Python 30.41 % +1.3 %
2 Java 15.12 % –0.5 %
3 JavaScript 7.93 % –0.6 %
4 C/C++ 6.98 % +0.6 %
5 C# 6.09 % –0.7 %
6 R 4.59 % –0.1 %
7 PHP 3.71 % –0.8 %
8 Rust 3.09 % +0.5 %
9 TypeScript 2.80 % –0.1 %
10 Objective-C 2.76 % +0.3 %

Na grafu získaném z této stránky je opět patrný relativní pokles popularity Javy, i když pouze pozvolný:

PYPL Java

Obrázek 16: Popularita Javy měřená podle PYPL.

9. Třicet let v IT: uvedení do kontextu

Připomínáme si třicet let existence programovacího jazyka Java, takže je dobré uvést tento věk do kontextu. V další tabulce je vypsáno deset nejpopulárnějších programovacích jazyků podle Tiobe (vyměnil jsem jen SQL za Fortran z jedenácté pozice). Nyní nás však bude zajímat doba existence těchto jazyků. Jejich věk je uveden v posledním sloupci:

# Jazyk Vznik Věk
1 Python 1991 34
2 C++ 1985 40
3 C 1972 53
4 Java 1995 30
5 C# 2000 25
6 JavaScript 1995 30
7 Go 2009 16
8 Visual Basic (Classic) 1991 24
9 Delphi 1995 30
11 Fortran 1957 68

Povšimněte si, že většina nejpopulárnějších jazyků je starších než 20 let. Jedinou výjimkou je Go, což ovšem na druhé straně vyvažuje Fortran (resp. původně FORTRAN). Tento údaj je zajímavý při porovnání s dalším statistikou, a to konkrétně věkem profesionálních vývojářů:

Věková skupina Zastoupení
méně než 18 5%
18–24 20%
25–34 37%
35–44 23%
45–54 9%
55–64 4%
65-.. 1%
Poznámka: součet není roven 100% kvůli zaokrouhlení na celá procenta.

Co to znamená? 85% profesionálních vývojářů je mladších než 45 let a pokud začali svoji kariéru řekněme ve věku dvaceti let, znamená to, ze s velmi vysokou pravděpodobností pracují s programovacími jazyky, které byly používány ještě před jejich příchodem do praxe. Oblast programovacích jazyků je tedy v oblasti IT kupodivu velmi stabilní, i když to tak nemusí na první pohled vypadat díky velkému množství článků a zmínek o nových a stále rostoucích jazycích (typu Rust, Zig, před několika lety Clojure atd.).

10. Nové výzvy pro Javu

Jak jsme si již řekli v úvodní části dnešního článku, byla Java původně určena pro programování mikrovlnných trub a výtahů (alespoň tak vypadaly první prezentace). Nutno říci, že v této oblasti (mikrořadiče) se vlastně nikdy neujala, mj. i kvůli velkým paměťovým požadavkům virtuálního stroje (naopak se zde drží C popř. typicky „C s třídami“, tj. očesané C++). Ovšem právě v době vydání Javy došlo k velkému rozmachu Internetu, což již byla oblast, ve které se mohly projevit dobré vlastnosti tohoto jazyka i celé platformy – bezpečnější a přenositelnější aplikace, později relativně dobrá podpora pro paralelní běh či alespoň souběh většího množství vláken, automatický správce paměti atd.

11. Java: jazyk pro Internet

Java se začala používat pro tzv. middleware (aplikační servery a aplikace pro ně určené), vzniklo několik technologií pro dynamické generování HTML stránek (JSP, RichFaces apod.), v Javě byly vytvořeny message brokery a streaming platformy (ActiveMQ resp. Artemis a vlastně částečně i Apache Kafka) apod. Jedná se o technologie určené pro back end, nikoli pro front end.

Zapomenout nesmíme ani na Java applety, které umožňovaly běh i relativně složitých aplikací v rámci okna (plochy) webového prohlížeče. Názory na vhodnost či nevhodnost appletů se liší, ovšem díky sandboxingu (izolaci appletů) od celého desktopu se nejednalo o špatnou technologii – její plnohodnotná náhrada vlastně dodnes neexistuje, protože WebAssembly se stále vyvíjí a postrádá vlastnosti JVM (JIT a správce paměti).

12. Java na desktopu

Naproti tomu, i přes snahu některých společností, se Java příliš neprosadila na desktopu (a to existovaly snahy o vytvoření operačního systému založeného přímo na JVM). Do určité míry za to mohla problematická instalace takových aplikací (i když existovala technologie Java Web Start, dnes již nepodporovaná), ale i odlišný vzhled a chování Javovských aplikací a v neposlední řadě taktéž relativně pomalé reakce grafického uživatelského rozhraní. Systém událostí a handlerů pro každou akci generoval nové a nové objekty, o které se musel starat správce paměti.

13. Java a hry

Tradovalo se, že se programovací jazyk s automatickou správou paměti příliš nehodí pro tvorbu her; ostatně v této oblasti se stále na prvním místě používá jazyk C++. Java sice do určité míry podporovala tvorbu her, například bylo možné využít třídu VolatileImage pro kreslení v režimu celé obrazovky popř. použít BufferedImage s podporou operací typu BLT (bit block transfer). Existovaly i rozhraní pro OpenGL a Direct3D, ovšem Java se stále považovala v této oblasti za spíše druhořadý jazyk. Jenže pak přišel Minecraft, který byl (podle různých statistik) druhou nejhranější hrou roku 2024 (140 milionů hráčů, první je Roblox s 380 miliony). Minecraft ukázal, že optimalizovaný kód psaný v Javě a vhodná GUI knihovna mohou být využity pro tvorbu velmi úspěšné a graficky náročné hry.

14. Závěr

S trochou nadsázky se tvrdí, že Java je COBOLem 21.století. V oblasti enterprise systémů a middleware není toto tvrzení daleko od pravdy – a to v dobrém smyslu. Java je totiž velmi stabilní platformou, která však neustrnula ve vývoji a neustále se vylepšuje (modularita, streaming, vylepšené režimy JIT a AOT překladu atd.), takže se stále používá a pravděpodobně i bude používat. Pokud nedojde v oblasti IT k zásadní revoluci, lze předpokládat, že i za dalších třicet let se ještě s aplikacemi vytvořenými v Javě setkáme, i když nelze odhadnout, do jaké míry bude Java populární mezi mainstreamovými programátory.

15. Příloha: porovnání rychlosti JVM v režimu interpretru a JITu

Ve třetí kapitole jsme se zmínili o Just in Time překladači Javy (JIT) i o rozdílech oproti pouhé interpretaci Javovského bajtkódu. Rozdíl mezi interpretrem a JIT překladačem si ukážeme na výpočtu, který na stránkách Roota používám poměrně často (a to v různých programovacích jazycích). Jedná se o výpočet a vykreslení (rendering) Mandelbrotovy množiny s uložením výsledku do rastrového obrázku:

benchmark

Obrázek 17: Výsledek běhu benchmarku by měl vypadat takto.

Úplný zdrojový kód jednoduchého benchmarku, který vykreslí Mandelbrotovu množinu, vypadá následovně:

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
 
import javax.imageio.ImageIO;
 
public class DrawMandelbrot
{
    private static final int MAXITER = 1200;
    private static final int WIDTH = 1024;
    private static final int HEIGHT = 1024;
 
    public void drawMandelbrot()
    {
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        calcMandelbrot(image);
        writeImage(image);
    }
 
    private void writeImage(BufferedImage image)
    {
        try
        {
            ImageIO.write(image, "png", new File("mandel.png"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
 
    private void calcMandelbrot(BufferedImage image)
    {
        double cy = -1.5;
        for (int y = 0; y < HEIGHT; y++)
        {
            double cx = -2.0;
            for (int x = 0; x < WIDTH; x++)
            {
                double zx = 0.0, zy = 0.0;
                int iter = calcIter(cy, cx, zx, zy);
                int rgb = calcRGBColor(iter);
                image.setRGB(x, y, rgb);
                cx += 3.0/WIDTH;
            }
            cy += 3.0/HEIGHT;
        }
    }
 
    private int calcRGBColor(int iter)
    {
        Color color = Color.BLACK;
        if (iter < MAXITER) {
            color = new Color(iter&0xff, (iter*256/16)&0xff, (iter*256/32)&0xff);
        }
        int rgb = color.getRGB();
        return rgb;
    }
 
    private int calcIter(double cy, double cx, double zx, double zy)
    {
        double zzx = zx;
        double zzy = zy;
        int iter = 0;
        while (iter < MAXITER)
        {
            double zx2 = zzx * zzx;
            double zy2 = zzy * zzy;
            if (zx2 + zy2 > 4.0)
            {
                break;
            }
            zzy = 2.0 * zzx * zzy + cy;
            zzx = zx2 - zy2 + cx;
            iter ++;
        }
        return iter;
    }
 
    public static void main(String[] args)
    {
        new DrawMandelbrot().drawMandelbrot();
    }
 
}

16. Výsledky benchmarků

Rozdíl mezi rychlostí (resp. pomalostí) interpretru oproti JIT překladačům můžeme zjišťovat jak různými sofistikovanými metodami, tak i triviálním porovnáním celkové doby běhu výše ukázaného benchmarku pro výpočet Mandelbrotovy množiny. Nejdříve je vypsán čas při použití C2 a C1 překladače a posléze i čas při přepnutí do režimu interpretace. Z výsledků je patrné, že interpretace je přibližně třikrát pomalejší (mnohdy ale bývá rozdíl i větší, například při manipulacích s poli atd.):

zabbix_tip

$ time java -server -XX:CompileThreshold=1000 DrawMandelbrot.java
 
real    0m1.973s
user    0m4.074s
sys     0m0.225s
 
$ time java -client -XX:CompileThreshold=1000 DrawMandelbrot.java
 
real    0m1.988s
user    0m3.968s
sys     0m0.237s
 
$ time java -Xint DrawMandelbrot.java
real    0m13.920s
user    0m13.849s
sys     0m0.065s
Poznámka: na některých platformách je volba –client ignorována a vždy se použije kombinace C1+C2 překladače.

17. Příloha: výsledek překladu metody calcIter C1 a C2 překladačem

Pro zajímavost se podívejme, jak vypadá výsledek just in time překladu metody calcIter použité v benchmarku. První varianta byla přeložena C1 překladačem (ten je rychlejší, ale neprovádí všechny optimalizace). Povšimněte si, že se jedná o 64bitový kód využívající i moderní rozšíření instrukční sady (vektorové instrukce). Navíc se parametry předávají přes registry a nikoli přes zásobník – Java zde nemusí dodržovat standardní ABI:

[Entry Point]
  # {method} {0x00007f93cfa888d8} 'calcIter' '(DDDD)I' in 'DrawMandelbrot'
  # this:     rsi:rsi   = 'DrawMandelbrot'
  # parm0:    xmm0:xmm0   = double
  # parm1:    xmm1:xmm1   = double
  # parm2:    xmm2:xmm2   = double
  # parm3:    xmm3:xmm3   = double
  #           [sp+0x40]  (sp of caller)
  0x00007f943b9716e0:   mov    0x8(%rsi),%r10d              ;   {no_reloc}
  0x00007f943b9716e4:   movabs $0x7f93d3000000,%r11
  0x00007f943b9716ee:   add    %r11,%r10
  0x00007f943b9716f1:   cmp    %rax,%r10
  0x00007f943b9716f4:   jne    0x00007f9442cad080           ;   {runtime_call ic_miss_stub}
  0x00007f943b9716fa:   nopw   0x0(%rax,%rax,1)
[Verified Entry Point]
  0x00007f943b971700:   mov    %eax,-0x14000(%rsp)
  0x00007f943b971707:   push   %rbp
  0x00007f943b971708:   sub    $0x30,%rsp
  0x00007f943b97170c:   cmpl   $0x1,0x20(%r15)
  0x00007f943b971714:   je     0x00007f943b97171b
  0x00007f943b971716:   call   Stub::nmethod_entry_barrier  ;   {runtime_call StubRoutines (final stubs)}
  0x00007f943b97171b:   movabs $0x7f93cfa88d00,%rax
  0x00007f943b971725:   mov    0x8(%rax),%edi
  0x00007f943b971728:   add    $0x2,%edi
  0x00007f943b97172b:   mov    %edi,0x8(%rax)
  0x00007f943b97172e:   and    $0xffe,%edi
  0x00007f943b971734:   test   %edi,%edi
  0x00007f943b971736:   je     0x00007f943b9717fe           ;*dload {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@0 (line 63)
  0x00007f943b97173c:   mov    $0x0,%eax
  0x00007f943b971741:   jmp    0x00007f943b9717e0           ;*iload {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@11 (line 66)
  0x00007f943b971746:   xchg   %ax,%ax
  0x00007f943b971748:   vmovapd %xmm2,%xmm4
  0x00007f943b97174c:   vmulsd %xmm2,%xmm4,%xmm4
  0x00007f943b971750:   vmovapd %xmm3,%xmm5
  0x00007f943b971754:   vmulsd %xmm3,%xmm5,%xmm5
  0x00007f943b971758:   vmovapd %xmm4,%xmm6
  0x00007f943b97175c:   vaddsd %xmm5,%xmm6,%xmm6
  0x00007f943b971760:   vmovsd -0xa8(%rip),%xmm7        # 0x00007f943b9716c0
                                                            ;   {section_word}
  0x00007f943b971768:   vucomisd %xmm7,%xmm6
  0x00007f943b97176c:   mov    $0xffffffff,%esi
  0x00007f943b971771:   jp     0x00007f943b97178b
  0x00007f943b971777:   jb     0x00007f943b97178b
  0x00007f943b97177d:   mov    $0x0,%esi
  0x00007f943b971782:   je     0x00007f943b97178b
  0x00007f943b971788:   inc    %rsi                         ;*dcmpl {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@41 (line 70)
  0x00007f943b97178b:   test   %esi,%esi
  0x00007f943b97178d:   jg     0x00007f943b9717eb           ;*ifle {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@42 (line 70)
  0x00007f943b971793:   vmulsd -0xd3(%rip),%xmm2,%xmm2        # 0x00007f943b9716c8
                                                            ;   {section_word}
  0x00007f943b97179b:   vmulsd %xmm3,%xmm2,%xmm2
  0x00007f943b97179f:   vaddsd %xmm0,%xmm2,%xmm2
  0x00007f943b9717a3:   vsubsd %xmm5,%xmm4,%xmm4
  0x00007f943b9717a7:   vaddsd %xmm1,%xmm4,%xmm4
  0x00007f943b9717ab:   inc    %eax
  0x00007f943b9717ad:   movabs $0x7f93cfa88d00,%rsi
  0x00007f943b9717b7:   mov    0xc(%rsi),%edi
  0x00007f943b9717ba:   add    $0x2,%edi
  0x00007f943b9717bd:   mov    %edi,0xc(%rsi)
  0x00007f943b9717c0:   and    $0x7ffe,%edi
  0x00007f943b9717c6:   test   %edi,%edi
  0x00007f943b9717c8:   je     0x00007f943b97181f           ;*goto {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@73 (line 77)
  0x00007f943b9717ce:   mov    0x450(%r15),%r10             ; ImmutableOopMap {}
                                                            ;*goto {reexecute=1 rethrow=0 return_oop=0}
                                                            ; - (reexecute) DrawMandelbrot::calcIter@73 (line 77)
  0x00007f943b9717d5:   test   %eax,(%r10)                  ;   {poll}
  0x00007f943b9717d8:   vmovapd %xmm2,%xmm3
  0x00007f943b9717dc:   vmovapd %xmm4,%xmm2                 ;*goto {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@73 (line 77)
  0x00007f943b9717e0:   cmp    $0x4b0,%eax
  0x00007f943b9717e5:   jl     0x00007f943b971748           ;*if_icmpge {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@16 (line 66)
  0x00007f943b9717eb:   add    $0x30,%rsp
  0x00007f943b9717ef:   pop    %rbp
  0x00007f943b9717f0:   cmp    0x448(%r15),%rsp             ;   {poll_return}
  0x00007f943b9717f7:   ja     0x00007f943b97183d
  0x00007f943b9717fd:   ret
  0x00007f943b9717fe:   movabs $0x7f93cfa888d8,%r10         ;   {metadata({method} {0x00007f93cfa888d8} 'calcIter' '(DDDD)I' in 'DrawMandelbrot')}
  0x00007f943b971808:   mov    %r10,0x8(%rsp)
  0x00007f943b97180d:   movq   $0xffffffffffffffff,(%rsp)
  0x00007f943b971815:   call   0x00007f9442d74c00           ; ImmutableOopMap {rsi=Oop }
                                                            ;*synchronization entry
                                                            ; - DrawMandelbrot::calcIter@-1 (line 63)
                                                            ;   {runtime_call counter_overflow Runtime1 stub}
  0x00007f943b97181a:   jmp    0x00007f943b97173c
  0x00007f943b97181f:   movabs $0x7f93cfa888d8,%r10         ;   {metadata({method} {0x00007f93cfa888d8} 'calcIter' '(DDDD)I' in 'DrawMandelbrot')}
  0x00007f943b971829:   mov    %r10,0x8(%rsp)
  0x00007f943b97182e:   movq   $0x49,(%rsp)
  0x00007f943b971836:   call   0x00007f9442d74c00           ; ImmutableOopMap {}
                                                            ;*goto {reexecute=1 rethrow=0 return_oop=0}
                                                            ; - (reexecute) DrawMandelbrot::calcIter@73 (line 77)
                                                            ;   {runtime_call counter_overflow Runtime1 stub}
  0x00007f943b97183b:   jmp    0x00007f943b9717ce
  0x00007f943b97183d:   movabs $0x7f943b9717f0,%r10         ;   {internal_word}
  0x00007f943b971847:   mov    %r10,0x460(%r15)
  0x00007f943b97184e:   jmp    0x00007f9442cb4000           ;   {runtime_call SafepointBlob}
  0x00007f943b971853:   mov    0x4f8(%r15),%rax
  0x00007f943b97185a:   movq   $0x0,0x4f8(%r15)
  0x00007f943b971865:   movq   $0x0,0x500(%r15)
  0x00007f943b971870:   add    $0x30,%rsp
  0x00007f943b971874:   pop    %rbp
  0x00007f943b971875:   jmp    0x00007f9442d6db00           ;   {runtime_call unwind_exception Runtime1 stub}
  0x00007f943b97187a:   hlt
  0x00007f943b97187b:   hlt
  0x00007f943b97187c:   hlt
  0x00007f943b97187d:   hlt
  0x00007f943b97187e:   hlt
  0x00007f943b97187f:   hlt
[Exception Handler]
  0x00007f943b971880:   call   0x00007f9442d71100           ;   {no_reloc}
  0x00007f943b971885:   movabs $0x7f945972c169,%rdi         ;   {external_word}
  0x00007f943b97188f:   and    $0xfffffffffffffff0,%rsp
  0x00007f943b971893:   call   0x00007f94591cbbf0           ;   {runtime_call MacroAssembler::debug64(char*, long, long*)}
  0x00007f943b971898:   hlt
[Deopt Handler Code]
  0x00007f943b971899:   movabs $0x7f943b971899,%r10         ;   {section_word}
  0x00007f943b9718a3:   push   %r10
  0x00007f943b9718a5:   jmp    0x00007f9442cb32a0           ;   {runtime_call DeoptimizationBlob}
  0x00007f943b9718aa:   hlt
  0x00007f943b9718ab:   hlt
  0x00007f943b9718ac:   hlt
  0x00007f943b9718ad:   hlt
  0x00007f943b9718ae:   hlt
  0x00007f943b9718af:   hlt
--------------------------------------------------------------------------------
[/Disassembly]

Naproti tomu C2 překladač vyprodukoval poněkud odlišný strojový kód, který je navíc kratší:

[Entry Point]
  # {method} {0x00007feabfa888d8} 'calcIter' '(DDDD)I' in 'DrawMandelbrot'
  # this:     rsi:rsi   = 'DrawMandelbrot'
  # parm0:    xmm0:xmm0   = double
  # parm1:    xmm1:xmm1   = double
  # parm2:    xmm2:xmm2   = double
  # parm3:    xmm3:xmm3   = double
  #           [sp+0x30]  (sp of caller)
  0x00007feb2fe2acc0:   mov    0x8(%rsi),%r10d              ;   {no_reloc}
  0x00007feb2fe2acc4:   movabs $0x7feac3000000,%r11
  0x00007feb2fe2acce:   add    %r11,%r10
  0x00007feb2fe2acd1:   cmp    %r10,%rax
  0x00007feb2fe2acd4:   jne    0x00007feb2f6ad080           ;   {runtime_call ic_miss_stub}
  0x00007feb2fe2acda:   xchg   %ax,%ax
  0x00007feb2fe2acdc:   nopl   0x0(%rax)
[Verified Entry Point]
  0x00007feb2fe2ace0:   mov    %eax,-0x14000(%rsp)
  0x00007feb2fe2ace7:   push   %rbp
  0x00007feb2fe2ace8:   sub    $0x20,%rsp
  0x00007feb2fe2acec:   cmpl   $0x1,0x20(%r15)
  0x00007feb2fe2acf4:   jne    0x00007feb2fe2adaa           ;*synchronization entry
                                                            ; - DrawMandelbrot::calcIter@-1 (line 63)
  0x00007feb2fe2acfa:   xor    %eax,%eax
  0x00007feb2fe2acfc:   mov    $0x3e8,%r11d
  0x00007feb2fe2ad02:   mov    $0x4b0,%r10d
  0x00007feb2fe2ad08:   sub    %eax,%r10d
  0x00007feb2fe2ad0b:   cmp    $0x3e8,%r10d
  0x00007feb2fe2ad12:   cmova  %r11d,%r10d
  0x00007feb2fe2ad16:   add    %eax,%r10d
  0x00007feb2fe2ad19:   jmp    0x00007feb2fe2ad24
  0x00007feb2fe2ad1b:   nopl   0x0(%rax,%rax,1)
  0x00007feb2fe2ad20:   vmovapd %xmm4,%xmm2                 ;*dload {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@19 (line 68)
  0x00007feb2fe2ad24:   vmulsd %xmm3,%xmm3,%xmm4            ;*dmul {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@30 (line 69)
  0x00007feb2fe2ad28:   vmulsd %xmm2,%xmm2,%xmm5            ;*dmul {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@23 (line 68)
  0x00007feb2fe2ad2c:   vaddsd %xmm4,%xmm5,%xmm6
  0x00007feb2fe2ad30:   vucomisd -0x98(%rip),%xmm6        # 0x00007feb2fe2aca0
                                                            ;   {section_word}
  0x00007feb2fe2ad38:   jbe    0x00007feb2fe2ad4d           ;*ifle {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@42 (line 70)
  0x00007feb2fe2ad3a:   add    $0x20,%rsp
  0x00007feb2fe2ad3e:   pop    %rbp
  0x00007feb2fe2ad3f:   cmp    0x448(%r15),%rsp             ;   {poll_return}
  0x00007feb2fe2ad46:   ja     0x00007feb2fe2ad94
  0x00007feb2fe2ad4c:   ret
  0x00007feb2fe2ad4d:   vsubsd %xmm4,%xmm5,%xmm4
  0x00007feb2fe2ad51:   vaddsd %xmm1,%xmm4,%xmm4            ;*dadd {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@67 (line 75)
  0x00007feb2fe2ad55:   vaddsd %xmm2,%xmm2,%xmm2
  0x00007feb2fe2ad59:   vmulsd %xmm3,%xmm2,%xmm2
  0x00007feb2fe2ad5d:   vaddsd %xmm0,%xmm2,%xmm3            ;*dadd {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@58 (line 74)
  0x00007feb2fe2ad61:   inc    %eax                         ;*iinc {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@70 (line 76)
  0x00007feb2fe2ad63:   cmp    %r10d,%eax
  0x00007feb2fe2ad66:   jl     0x00007feb2fe2ad20           ;*goto {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@73 (line 77)
  0x00007feb2fe2ad68:   mov    0x450(%r15),%r10             ; ImmutableOopMap {}
                                                            ;*goto {reexecute=1 rethrow=0 return_oop=0}
                                                            ; - (reexecute) DrawMandelbrot::calcIter@73 (line 77)
  0x00007feb2fe2ad6f:   test   %eax,(%r10)                  ;*goto {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@73 (line 77)
                                                            ;   {poll}
  0x00007feb2fe2ad72:   cmp    $0x4b0,%eax
  0x00007feb2fe2ad77:   jge    0x00007feb2fe2ad7f
  0x00007feb2fe2ad79:   vmovapd %xmm4,%xmm2
  0x00007feb2fe2ad7d:   jmp    0x00007feb2fe2ad02
  0x00007feb2fe2ad7f:   mov    $0xffffff45,%esi
  0x00007feb2fe2ad84:   mov    %eax,(%rsp)
  0x00007feb2fe2ad87:   call   0x00007feb2f6b2f00           ; ImmutableOopMap {}
                                                            ;*if_icmpge {reexecute=1 rethrow=0 return_oop=0}
                                                            ; - (reexecute) DrawMandelbrot::calcIter@16 (line 66)
                                                            ;   {runtime_call UncommonTrapBlob}
  0x00007feb2fe2ad8c:   nopl   0x100027c(%rax,%rax,1)       ;*if_icmpge {reexecute=0 rethrow=0 return_oop=0}
                                                            ; - DrawMandelbrot::calcIter@16 (line 66)
                                                            ;   {other}
  0x00007feb2fe2ad94:   movabs $0x7feb2fe2ad3f,%r10         ;   {internal_word}
  0x00007feb2fe2ad9e:   mov    %r10,0x460(%r15)
  0x00007feb2fe2ada5:   jmp    0x00007feb2f6b4000           ;   {runtime_call SafepointBlob}
  0x00007feb2fe2adaa:   call   Stub::nmethod_entry_barrier  ;   {runtime_call StubRoutines (final stubs)}
  0x00007feb2fe2adaf:   jmp    0x00007feb2fe2acfa
  0x00007feb2fe2adb4:   hlt
  0x00007feb2fe2adb5:   hlt
  0x00007feb2fe2adb6:   hlt
  0x00007feb2fe2adb7:   hlt
[Exception Handler]
  0x00007feb2fe2adb8:   jmp    0x00007feb2f777500           ;   {no_reloc}
[Deopt Handler Code]
  0x00007feb2fe2adbd:   call   0x00007feb2fe2adc2
  0x00007feb2fe2adc2:   subq   $0x5,(%rsp)
  0x00007feb2fe2adc7:   jmp    0x00007feb2f6b32a0           ;   {runtime_call DeoptimizationBlob}
  0x00007feb2fe2adcc:   hlt
  0x00007feb2fe2adcd:   hlt
  0x00007feb2fe2adce:   hlt
  0x00007feb2fe2adcf:   hlt
--------------------------------------------------------------------------------
[/Disassembly]
Poznámka: tento výpis můžete získat i pro vaše metody, ovšem potřebovat budete dynamickou knihovnu hsdis.so.

18. Odkazy na Internetu

  1. Tiobe index
    https://www.tiobe.com/tiobe-index/
  2. PYPL PopularitY of Programming Language
    https://pypl.github.io/PYPL.html
  3. StackOverflow developer survery 2024: technology
    https://survey.stackoverflow­.co/2024/technology
  4. Java version history
    https://en.wikipedia.org/wi­ki/Java_version_history
  5. Java history
    https://en.wikipedia.org/wi­ki/Java_(software_platfor­m)#History
  6. Is Java the NEW COBOL in 2024?
    https://blog.stackademic.com/is-java-the-new-cobol-in-2024–4b82de559f54
  7. Future of Java: The Top 7 Java Trends (2025)
    https://www.finoit.com/articles/future-of-java/
  8. The Future of a Java Developer in 2025: Navigating the Evolution
    https://medium.com/@internshipgate/the-future-of-a-java-developer-in-2025-navigating-the-evolution-3c8531102c38
  9. Top 10 Programming Languages For 2025
    https://www.geeksforgeeks.org/top-programming-languages-of-the-future-2025/
  10. Software Developers Are Aging Out. Here Are The Facts.
    https://medium.com/@tsecret­developer/software-developers-are-aging-out-here-are-the-facts-9ac112640d14
  11. Age Demographics Among Professional Developers: Trends and Transformations in the IT Industry
    https://itstarter.net/en/age-demographics-among-professional-developers/
  12. Java's 20 Years Of Innovation
    https://www.forbes.com/si­tes/oracle/2015/05/20/javas-20-years-of-innovation/
  13. The Java Story: History and Background
    https://cs.smu.ca/~porter/csc/465/no­tes/java_story_history.html
  14. May 23, 1995: Sun Released Java Programming, MySQL Released RDBMS
    https://dayintechhistory.com/dith/23–1995-sun-released-java-programming-mysql-released-rdbms/
  15. Java Logo
    https://examples.javacode­geeks.com/java-logo/
  16. Kawa scheme language
    https://www.gnu.org/software/kawa/
  17. Třicet let od vydání revolučního Turbo Pascalu 5.5
    https://www.root.cz/clanky/tricet-let-od-vydani-revolucniho-turbo-pascalu-5–5/
  18. The future's bright… the future's Cobol
    https://www.root.cz/clanky/the-future-s-bright-the-future-s-cobol/
  19. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  20. Šedesátiny převratného programovacího jazyka ALGOL-60
    https://www.root.cz/clanky/sedesatiny-prevratneho-programovaciho-jazyka-algol-60/
  21. Další kulaté výročí v IT: dvacet let existence Pythonu 2
    https://www.root.cz/clanky/dalsi-kulate-vyroci-v-it-dvacet-let-existence-pythonu-2/
  22. Oslava 55 let od vzniku první implementace jazyka APL
    https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/
  23. Clojure
    https://clojure.org/
  24. Groovy
    http://groovy-lang.org/
  25. Nashorn
    https://github.com/openjdk/nashorn
  26. JRuby
    http://jruby.org/
  27. Jython
    http://www.jython.org/
  28. Kotlin
    http://kotlinlang.org/
  29. Scala
    https://www.scala-lang.org/
  30. Kawa
    https://www.gnu.org/software/kawa/
  31. Most used programming languages among developers worldwide 2024
    https://www.statista.com/sta­tistics/793628/worldwide-developer-survey-most-used-languages/
  32. Susan Kare
    https://en.wikipedia.org/wi­ki/Susan_Kare
  33. Java Debug Wire Protocol
    https://en.wikipedia.org/wi­ki/Java_Debug_Wire_Protocol
  34. Java Virtual Machine Tools Interface
    https://en.wikipedia.org/wi­ki/Java_Virtual_Machine_To­ols_Interface
  35. Java Management Extensions
    https://en.wikipedia.org/wi­ki/Java_Management_Extensi­ons
  36. Seriál Programovaci jazyk Java a JVM
    https://www.root.cz/seria­ly/programovaci-jazyk-java-a-jvm/
  37. NULL: The Billion Dollar Mistake
    https://hackernoon.com/null-the-billion-dollar-mistake-8t5z32d6

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.

'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »