ISO duration a Java (ISO 8601 duration format)

Java má metodu Duration.parse("duration-string"), která vypadá, jako by pracovala s ISO duration, ale není tomu tak. Dokáže parsovat použe tyto suffixy D (day), H (hour), M (minute), S (second).

Takže toto je správně:

Duration.parse("P1D") // jeden den

ale toto je chybně

Duration.parse("P1M") // správně by to bylo "PT1M" ale neznamená to 1 měsíc, ale 1 minutu.

Číst dálISO duration a Java (ISO 8601 duration format)

Zobrazení závislostí v Gradle

Pro zobrazení závislostí v Gradle ve stromové struktuře použijte taks dependencies.

./gradlew dependencies
compileClasspath - Compile classpath for compilation 'main' (target  (jvm)).
+--- org.springframework.boot:spring-boot-starter-data-jpa -> 2.1.9.RELEASE
|    +--- org.springframework.boot:spring-boot-starter-aop:2.1.9.RELEASE
|    |    +--- org.springframework.boot:spring-boot-starter:2.1.9.RELEASE
|    |    |    +--- org.springframework.boot:spring-boot:2.1.9.RELEASE
|    |    |    |    +--- org.springframework:spring-core:5.1.10.RELEASE
|    |    |    |    |    \--- org.springframework:spring-jcl:5.1.10.RELEASE
|    |    |    |    \--- org.springframework:spring-context:5.1.10.RELEASE
|    |    |    |         +--- org.springframework:spring-aop:5.1.10.RELEASE
|    |    |    |         |    +--- org.springframework:spring-beans:5.1.10.RELEASE
|    |    |    |         |    |    \--- org.springframework:spring-core:5.1.10.RELEASE (*)
|    |    |    |         |    \--- org.springframework:spring-core:5.1.10.RELEASE (*)
|    |    |    |         +--- org.springframework:spring-beans:5.1.10.RELEASE (*)
|    |    |    |         +--- org.springframework:spring-core:5.1.10.RELEASE (*)
|    |    |    |         \--- org.springframework:spring-expression:5.1.10.RELEASE
|    |    |    |              \--- org.springframework:spring-core:5.1.10.RELEASE (*)
|    |    |    +--- org.springframework.boot:spring-boot-autoconfigure:2.1.9.RELEASE
|    |    |    |    \--- org.springframework.boot:spring-boot:2.1.9.RELEASE (*)
|    |    |    +--- org.springframework.boot:spring-boot-starter-logging:2.1.9.RELEASE
|    |    |    |    +--- ch.qos.logback:logback-classic:1.2.3
|    |    |    |    |    +--- ch.qos.logback:logback-core:1.2.3
|    |    |    |    |    \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.28
|    |    |    |    +--- org.apache.logging.log4j:log4j-to-slf4j:2.11.2
|    |    |    |    |    +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.28
|    |    |    |    |    \--- org.apache.logging.log4j:log4j-api:2.11.2
|    |    |    |    \--- org.slf4j:jul-to-slf4j:1.7.28
|    |    |    |         \--- org.slf4j:slf4j-api:1.7.28
|    |    |    +--- javax.annotation:javax.annotation-api:1.3.2
|    |    |    \--- org.springframework:spring-core:5.1.10.RELEASE (*)
|    |    +--- org.springframework:spring-aop:5.1.10.RELEASE (*)
|    |    \--- org.aspectj:aspectjweaver:1.9.4
|    +--- org.springframework.boot:spring-boot-starter-jdbc:2.1.9.RELEASE
|    |    +--- org.springframework.boot:spring-boot-starter:2.1.9.RELEASE (*)
|    |    +--- com.zaxxer:HikariCP:3.2.0
|    |    |    \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.28
|    |    \--- org.springframework:spring-jdbc:5.1.10.RELEASE
|    |         +--- org.springframework:spring-beans:5.1.10.RELEASE (*)
|    |         +--- org.springframework:spring-core:5.1.10.RELEASE (*)
|    |         \--- org.springframework:spring-tx:5.1.10.RELEASE
|    |              +--- org.springframework:spring-beans:5.1.10.RELEASE (*)
|    |              \--- org.springframework:spring-core:5.1.10.RELEASE (*)

Pokud máte projekt, který se skládá z více modulů/projektů

> Task :projects

------------------------------------------------------------
Root project
------------------------------------------------------------

Root project 'my-service'
+--- Project ':my-service-client'
\--- Project ':my-service-service'

přepněte se v adresářové struktuře do daného modulu tam spusťte příkaz

../gradlew dependencies

Řízení závislostí v Gradle

V Gradlu v bloku dependencies {...} je možné zadat závislost a hlavně také, kdy jsou tyto závislosti potřeba (níže zmíněnou kofiguraci přidává Java plugin). Knihovny, které potřebujete jak pro kompilaci a tak pro běh, zadáte jako implementation (dříve compile). Pokud danou závislost potřebujete pouze při kompilaci použijete compileOnly, pokud pouze v runtime tak runtimeOnly.

Zde je jednoduchý příklad. Mám projekt v Kotlinu a v rámci tohoto projektu používám knihovnu Klaxon pro parsování json. Tuto knihovnu potřebuji jak při kopilaci, tak při běhu programu. Použiji tedy

implementation("com.beust:klaxon:5.0.9")

Pokud bych použil runtimeOnly, projekt by se nezkompiloval. Pokud bych použil compileOnly, projekt by se sice zkompiloval, ale po spuštění, když by chtěl použít knihovnu Klaxon, by skončil chybou.

Java 9 Flow.Subscriber and Flow.Publisher

Java 9 představila Flow API, které umožňuje reaktivní programování. V tomto příspěvku vytvořím aplikaci, která se bude skládat z jednoho publishera, který vytváří data a dvou subscriberů, kteří data zpracovávají. Jeden ze subscriberů je dostatečně rychlý a zvládá data zpracovávat rychleji, než je publisher produkuje, druhý subscriber je výrazně pomalejší.

Číst dálJava 9 Flow.Subscriber and Flow.Publisher

Java 10 a novinka var

Lokální proměnné je od Javy 10 možné deklarovat s použitím klíčového slova var. Přemýšlel jsem, k čemu tato změna je a začal jsem googlit. Narazil jsem na názor, že var má snížit ukecanost (verbosity) Javy. Pokud máte lokální proměnnou, můžete ji deklarovat takto:

var name = "John";
var age = 25;

místo

String name = "John";
int age = 25;

Nevidíte v tom žádnou výhodu? Moc psaní jste neušetřili. Souhlasím. A co teď?

List<Map<String, Set<MyClass>>> cosi;
var cosi;

Zde již nějaké to psaní ušetříme, ALE. Pokud v kódu narazím na takovouto proměnnou a budu s ní pracovat, pravděpodobně si stejně zjistím, jakého je typu. Takže místo toho, abych to rovnou viděl, musím se prokliknout někam, kde je daný typ uveden např. CosiClass.getCosi();. A pokud používáte nástroje svého IDE, pravděpodobně tam je možnost, nechat si přiřadit návratovou hodnotu volání do proměnné (v Idea IDE to je Ctrl + Alt + V), takže to stejně nepíši. Trochu mi to připomíná debaty na téma psaní getterů a setterů, kdy některé jazyky tyto metody generují automaticky na základně specifické syntaxe. V Javě je možné použít knihovnu Lombok a nebo nechat své IDE tyto metody vygenerovat. Asi teprve čas ukáže, zda se tato novinka mezi vývojáři uchytí.

Poznámka ke Kotlinu
Kotlin má var (od variable) a val (od value), kdy val je finální. Místo final String name napíšete val name.

fun main(args: Array) {
    var str1 = "Ahoj"
    val str2 = "Ahoj"

    str1 = "Nazdar"
//    str2 = "Nazdar" - Chyba: value cannot be reassigned
}

Doporučuji k přečtení tyto články:
beyondjava.net/should-you-embrace-var-in-java-10
openjdk.java.net/projects/amber/LVTIstyle.html

Nastavení verze Javy v Idea IDE

Několikrát se mi již stalo, že nově vytvořený, nebo nějak modifikovaný projekt, nešlo sbuildovat z důvodu, že Idea hlásila, že verze Javy je nastavena na 1.5 a daná konstrukce požaduje verzi 7, nebo 8, nebo vyšší. Pozor, existuje více míst, kde je nutné verzi pro projekt (nebo modul) nastavit.

File -> Settings -> Build, Execution, Deployment -> Compiler -> Java Compiler
File -> Project Structure -> Project
File -> Project Structure -> Modules -> Sources
File -> Project Structure -> SDKs

Rozdíl mezi rozhraním a statickou třídou v Javě

Java 8 zavedla defaultní metody v rozhraní, čímž trochu smyla rozdíl mezi rozhraním a abstraktní třídou. V tomto příspěvku se tedy podíváme blíže na rozhraní, jejich defaultní metody, abstraktní třídy a rozdíly mezi rozhraními a abstraktními třídami. Defaultním metodám se věnoval i tento dřívější příspěvek.

Rozhraní:
Může obsahovat statické metody.
Může obsahovat metody, které jsou implementovány (mají tělo).
Pro implementaci rozhraní se používá klíčové slovo implements.
Rozhraní nemůže mít instanční proměnné.
Rozhraní může mít pouze proměnné typu public static final (konstanty).
Metody v rozhraní jsou defaultně public abstract.

Číst dálRozdíl mezi rozhraním a statickou třídou v Javě

Přidání jiné webové stránky do Vaadin view

Do Vaadin view lze jinou webovou stránku přidat velmi jednoduše. Pro vložení jiného webu do aktuální stránky se v HTML používá element <iframe>. IFrame (Inline Frame, do češtiny se překládá jako plovoucí rám) vymezuje plochu v aktuální stránce pro vložení jiné webové stránky. Do Vaadin view lze <iframe> vložit pomocí objektu BrowserFrame.

final BrowserFrame browserFrame = new BrowserFrame("Stránka inITjobs.cz", new ExternalResource("https://www.initjobs.cz"));
browserFrame.setWidth("100%");
browserFrame.setHeight("600px");
addComponent(browserFrame);

Pro zvýraznění jsem přidal elementu <iframe> ohraničení.

.v-browserframe iframe {
  padding: 10px;
  border: 1px solid black;
}

Regulární výrazy v Javě

Pomocí regulárních výrazů definujeme vzory hledání pro řetězce. Vzor může být jediný znak, přesný řetězec, nebo složitý výraz obsahující speciální znaky.

Regulární výraz Popis
. Jakýkoliv znak
* Výskyt 0 nebo vícekrát
+ Výskyt 1 nebo vícekrát
? Výskyt 0 nebo jedenkrát
^ Začátek řádky (^A – začátek řádku musí začínat na A)
$ Konec řádky (z$ – řádek musí končit na z)
[] Definice možných výskytů ([123] – obsahuje 1, 2 nebo 3)
{} Počet možných výskytů ({5,7} – vyskytuje se alespoň 5x a maximálně 7x)
() Seskupení výrazů
| Nebo (a|b – a nebo b)
?! Negace (a?!b – a pokud není následováno b)
(?i) Regulární výraz není citlivý na malá a velká písmena (pozor na písmena s diakritikou)
\d Jakékoliv číslo
\D Cokoliv kromě čísla
\s Jakýkoliv bílý znak
\S Cokoliv kromě bílých znaků
\w Písmeno, číslice nebo podtržítko
\W Cokoliv kromě písmena, číslice nebo podtržítka

Java String má následující metody, které jako parametr mají regulární výraz:

string.matches("regex")
string.split("regex")
string.replaceFirst("regex", "replacement")
string.replaceAll("regex", "replacement")

Pro pokročilejší práci s regulárními výrazy se používají třídy Pattern a Matcher.

final String text = "Nějaký text";
final String regex = "Regulární výraz";
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(text);
matcher.find()

Změna verze Javy z 8 na 11

Nedávno jsem prováděl změny verze Javy na projektu, který používá Spring Boot. Měnil jsem verzi Javy z verze 8 na verzi 11. Nebylo to až tak strašné, jak jsem čekal (spíše naopak), přesto se ale některé komplikace objevily. V tomto příspěvku budu postupovat od chyby k chybě, tak jak se u mě objevovaly.

Číst dálZměna verze Javy z 8 na 11