Pred pár týždňami sa u nás uskutočnila MoroSnídaně na tému Java 9, kde sme si predstavili najzaujímavejšie novinky z Java 9. Celú prednášku si môžete pozrieť tu.

Java Platform Module System

Posledných niekoľko rokov sa najväčšia pozornosť venovala zavedeniu modulárneho systému (a.k.a. Project Jigsaw). Fyzické oddelenie jednotlivých modulov na úrovni JVM a výkonnostné benefity určite stoja za zmienku. Na druhú stranu aktuálna implementácia nerieši konflikty v závislostiach medzi jednotlivými modulmi. Ale toto nie je predmetom tohto článku. Pokiaľ Vás táto problematika zaujíma viac, pozrite sa na článok Modulární systém Javy 9 od kolegu Romana Mařáka.

Jazyk Java

Zmeny v jazyku Java sú naozaj minoritné. Nič zásadné sa nezmenilo.

  • try-with-resource
    Táto klauzula bola zavedená v Java 7 a zabezpečuje automatické uzatváranie zdrojov, ktoré implementujú rozhranie java.lang.AutoClosable. Pôvodná implementácia vyžadovala, aby došlo k priradeniu do premennej. Teraz to už potrebné nie je. Postačí uviesť finálnu alebo efektívne finálnu premennú.

final InputStream input = new ByteArrayInputStream(dataIn);
try (/* java9 */ input; /* java7 */final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
    output.write(input.readAllBytes());
    assertTrue(Arrays.equals(dataIn, output.toByteArray()));
} catch (Exception e) {
    e.printStackTrace();
}

  • Diamond operator  for anonymous inner classes
    Preberanie definície generického typu do konštruktora vo verzii 9 je možné už aj pri anonymných vnútorných triedach.

final InnerClass<string> obj = new InnerClass<>() {
 
    @Override
    public String getValue() {
        return "abcd";
    }
};

  • Private interface methods
    Java 8 umožnila definíciu default metód v rozhraniach. Vo verzii 9 pribudla podpora private metód.

Collection factory methods

Ak ste používali factory metódy na zjednodušenú tvorbu kolekcii z knižnice Guava. Teraz máte za ne náhradu priamo v JDK. Je tu niekoľko vlastností a obmedzení na ktoré je treba myslieť. Takto vytvorené kolekcie sú nemodifikovateľné. Nie je možné zadať null a to ani pri mapách ako hodnotu. Vstup pri množinách a mapách nemôže obsahovať žiadne duplicity.

  • List.of(1, 1, 1, 2, 3)
  • Set.of(1, 2, 3)
  • Map.of(“key1”, “value1”, “key2”, “value2”)

Stream API improvements

Potrebujete spracovať určitý interval z utriedenej postupnosti prvkov, alebo spracovať hodnoty, ktoré môžu ale nemusia byť null, či vygenerovať nekonečnú postupnosť prvkov? Nové Stream API všetky tieto scenáre pokrýva.

Stream.dropWhile(Predicate)


final List<integer> list = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).dropWhile(i -> (i < = 4)).collect(toList());
assertTrue(list.equals(List.of(5, 6, 7, 8, 9)));

Stream.takeWhile(Predicate)


final List</integer><integer> list = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).takeWhile(i -> (i < = 4)).collect(toList());
assertTrue(list.equals(List.of(1, 2, 3, 4)));

Stream.iterate(Object, UnaryOperator)


final List</integer><integer> list = Stream.iterate(1, i -> (i + 1)).limit(10).collect(toList());
assertTrue(list.equals(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));

Stream.ofNullable(Object)


assertTrue(Stream.ofNullable(null).count() == 0);
assertTrue(Stream.ofNullable(new Object()).count() == 1);

Optional API additions

Implementujete napríklad viacúrovňovú cache alebo chcete Optional spracovať ako Stream? Ak áno, určite sa pozrite na nové metódy.

  • Optional.or(Supplier)

final Optional<string> customValue = Optional.of("custom");
final Optional</string><string> defaultValue = Optional.of("default");
final Optional</string><string> empty = Optional.empty();
assertTrue(customValue.or(() -> defaultValue).get().equals("custom"));
assertTrue(empty.or(() -> defaultValue).get().equals("default"));

  • Optional.stream()

final Optional</string><string> optional = Optional.of("abcd");
final List<integer> length = optional.stream().map(String::length).collect(Collectors.toList());
assertTrue(length.equals(List.of(4)));

Reactive Streams

Hľadáte spôsob ako môžete asynchrónne a neblokujúco spracovať jasne neohraničenú sadu vstupných údajov? Uvažujete aj nad tým ako predídete zahĺteniu počas špičiek? V tomto prípade by ste určite narazili na Reactive Streams. Ich náprotivkom v JDK 9 je trieda java.util.concurrent.Flow a rozhrania Flow.PublisherFlow.SubscriberFlow.Subscription a Flow.Processor.

Reaktívnosť tohto prístupu spočíva v tom, že objem vstupných dát si riadi každý jeden Subscriber samostatne bez ohľadu na objem údajov, ktoré Publisher produkuje. Riadeným spôsobom predchádzame zahĺteniu na strane spracovateľov správ.

Na príklade náhodného generátora čísel a sčítača vygenerovaných hodnôt si ukážeme použitie základnej implementácie rozhrania Flow.Publisher v JDK java.util.concurrent.SubmissionPublisher.


import static cz.morosystems.java9examples.Utils.assertTrue;
 
import java.util.Random;
import java.util.concurrent.Flow;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.SubmissionPublisher;
 
/**
 * Reactive streams - {@link Flow}, {@link Subscriber}, {@link SubmissionPublisher}.
 */
public class ReactiveStreams {
 
    public static void main(String[] args) {
        final NumberGenerator generator = new NumberGenerator();
        final SumSubscriber subscriber = new SumSubscriber();
        generator.getPublisher().subscribe(subscriber);
        generator.start();
    }
 
    private static class SumSubscriber implements Subscriber</integer><integer> {
 
        private Subscription subscription;
 
        private int sum = 0;
 
        @Override
        public void onComplete() {
            System.out.println("Complete. Sum = " + sum);
        }
 
        @Override
        public void onError(final Throwable err) {
            err.printStackTrace();
        }
 
        @Override
        public void onNext(final Integer value) {
            System.out.println("value = " + value);
            sum = sum + value;
            ready();
        }
 
        @Override
        public void onSubscribe(final Subscription subscription) {
            assertTrue(subscription != null);
            this.subscription = subscription;
            ready();
        }
 
        private void ready() {
            subscription.request(1);
        }
    }
 
    private static class NumberGenerator extends Thread {
 
        public final SubmissionPublisher</integer><integer> publisher = new SubmissionPublisher</integer><integer>();
 
        @Override
        public void run() {
            final Random random = new Random();
            for (int i = 0; i < 10; i++) {
                final int value = random.nextInt(2000);
                publisher.submit(value);
                try {
                    sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            publisher.close();
        }
 
        public SubmissionPublisher<Integer> getPublisher() {
            return publisher;
        }
    }
}

CompletableFuture improvements

Chcete spracovať CompletableFuture asynchrónne, oneskorene alebo v definovanom časovom intervale? Vám by sa mohli hodiť práve nasledovné novinky.

  • Async


final CompletableFuture</integer><integer> future = new CompletableFuture</integer><integer>();
future.completeAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 1;
});
assertTrue(!future.isDone());
Thread.sleep(1500);
assertTrue(future.isDone());

  • orTimeout


final CompletableFuture</integer><integer> future = new CompletableFuture</integer><integer>().orTimeout(1, TimeUnit.SECONDS);
Thread.sleep(1100);
try {
    future.get();
} catch (ExecutionException e) {
    // ok - expected
    assertTrue(e.getCause() instanceof TimeoutException);
}

  • Delay

final CompletableFuture</integer><integer> future = new CompletableFuture</integer><integer>();
future.completeAsync(() -> 3, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));
assertTrue(!future.isDone());
Thread.sleep(2000);
assertTrue(future.isDone());

Stack Walking API

Chystáte sa automatizovane spracovávať stack trace? V vo verzii 9 Vás už nečaká žiadne parsovanie reťazcov ani nič podobné.



final List<stackframe> stacktrace =
        StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk((s) -> s.collect(Collectors.toList()));
for (StackFrame stackFrame : stacktrace) {
    System.out.println(stackFrame.getClassName() + "." + stackFrame.getMethodName() + ":" + stackFrame.getLineNumber() + " ("
            + stackFrame.getFileName() + ")");
}

Output


cz.morosystems.java9examples.StackWalkingApi.methodC:28 (StackWalkingApi.java)
cz.morosystems.java9examples.StackWalkingApi.methodB:23 (StackWalkingApi.java)
cz.morosystems.java9examples.StackWalkingApi.methodA:19 (StackWalkingApi.java)
cz.morosystems.java9examples.StackWalkingApi.main:15 (StackWalkingApi.java)

Process API improvements

Používate súčasné Process API? Nová verzia Vás určite príjemne prekvapí.

  • ProcessHandle.current()
  • ProcessHandle.allProcesses()

ProcessHandle.allProcesses().filter(ProcessHandle::isAlive).map(i -> i.info()).forEach(System.out::println);

Output


[user: Optional[ELITEBOOK840G3\Michal Bradiak], cmd: C:\Program Files\Java\jdk-9\bin\javaw.exe, startTime: Optional[2017-10-28T14:14:22.222Z], totalTime: Optional[PT0.453125S]]
[user: Optional[ELITEBOOK840G3\Michal Bradiak], cmd: C:\Users\Michal Bradiak\AppData\Local\Atlassian\SourceTree\git_local\mingw32\bin\git.exe, startTime: Optional[2017-10-28T14:13:04.134Z], totalTime: Optional[PT0.015625S]]

  • ProcessHandle.pid()
  • ProcessHandle.destroy()
  • ProcessHandle.destroyForcibly()
  • ProcessHandle.onExit()
  • ProcessBuilder

HTTP client

Poznáte alebo používate knižnicu OkHttp? Teraz máte k dispozícii alternatívu priamo v JDK 9. Nechýba podpora HTTP/2 ani WebSocket klient. Postačí do module-info.java uviesť závislosť na modul jdk.incubator.httpclient prípadne doplniť VM parameter –add-modules=jdk.incubator.httpclient.

  • jdk.incubator.http.HttpClient, jdk.incubator.http.HttpRequest, jdk.incubator.http.HttpResponse

final HttpClient client = HttpClient.newHttpClient();
final HttpRequest request =
        HttpRequest.newBuilder().uri(new URI("https://www.google.com/")).GET().timeout(Duration.ofMinutes(2)).build();
final HttpResponse<string> response = client.send(request, HttpResponse.BodyHandler.asString());
assertTrue("HTTP_2".equals(response.version().toString()));

  • jdk.incubator.httpclient.WebSocket

Ostatné

  • Multi-Resolution Image API

final MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(allResolutions.toArray(new Image[] {}));
final Image suitable = multiResolutionImage.getResolutionVariant(width, height);

  • Security
    • Secure Hash Algorithm 3 (SHA-3)
    • Datagram Transport Layer Security (DTLS) Protocol – UDP
    • TLS – Application-Layer Protocol Negotiationm Online Certificate Status Protocol
    • Použitie nových CPU inštrukcii – GHASH (zrýchlenie 34-150x) a RSA (zrýchlenie do 50%)
    • SecureRandom – RDRAND – Deterministic Random Bit Generator (DRBG)
    • Znefunkčnenie SHA-1 certifikátov
    • Multi-Release JAR Files

jar root
  - A.class
  - B.class
  - C.class
  - D.class
  - META-INF
     - versions
        - 9
           - A.class
           - B.class
        - 10
           - A.class

  • Parser API for Nashorn
  • Searchable JavaDoc
  • jshell
  • Nový release plan
    • nová verzia raz za 6 mesiacov (18.3, 18.9., 19.3, 19.9, …)
    • LTS raz za 12 mesiacov (18.9, 19.9, …)
    • Java Flight Recorder, Java Mission Control budú súčasťou OpenJDK
    • Oracle JDK nahradí OpenJDK
    • OpenJDK bude pod GPL licenciou

Video


Zajímají tě nejlepší technologie na zajímavých projektech?

Aktuálně hledáme Java EE Developery do kanceláří v Hradci Králové a Brně, ale i na home-office.

Zajímáš se více o front-end (Angular nebo React)? Pokud ano, tak právě hledáme i tebe.

Raději bys vedl týmy nebo tě láká produktový vývoj? Pro tebe bude ideální Product Owner nebo Software Delivery Manager.

Zajímá tě něco jiného? Mrkni na všechny naše otevřené pozice a dej nám o sobě vědět, bez ohledu na to, zda máš rád front-end nebo back-end, jestli nějakou technologii umíš nebo ne. Pokud budeš ty sám chtít, dostaneš u nás příležitost naučit se, co tě zajímá nebo udělat něco výjimečného.