Probuď sílu Javy je za námi a hvězdné ceny jsou rozdány. Známe i všechny MoonWalkery, TexasWalkery a JavaWalkery. Vás teď ale zajímá, jaké byly správné odpovědi našich úkolů. Nadešel ten správný čas odpovědi zveřejnit. Tak jak jste na tom byli JavaWalkeři?

Správné odpovědi na první úkol

Jsi vyhlášený DJ a připravuješ si svůj mixážní pult, abys mohl zahrát na velké taneční soutěži. Tančí se zásadně na Java kroky a vítěz bude prohlášen MoonWalkerem! Než to všechno vypukne, musíš zkontrolovat nastavení svého mixážního

pultu – všechny konektory a přepínače musí být na svém místě. Potřebuješ preset na hudební styl Java Funk, a protože to celé bude jedna velká party, beats per minute (BPM) nastavíš na svižných 150 a hlasitost bude přirozeně 100%!



package cz.moonwalkerdj;

public class MoonWalkerScratchMixer {

    private Integer volume;
    private Integer bpm;
    private MusicStyle musicStyle;

    private enum MusicStyle {
        JAVA_FUNK,
        TECHNO,
        GANGSTA_RAP
    }

    public static void main(String[] args) {
        MoonWalkerScratchMixer mixer = new MoonWalkerScratchMixer();
        mixer.init();
    }

    public void init() {
        volume = getVolume(237L, 237L, new Long(237), new Long(114), 114L, 114L);
        System.out.println("Volume: " + volume + "%");

        bpm = getBeatsPerMinute(null);
        System.out.println("BPM: " + bpm);

        musicStyle = getMusicStyle(0, null, 0);
        System.out.println("Musict style: " + musicStyle);
    }

    private MusicStyle getMusicStyle(int connectorOne, Integer connectorTwo, Integer connectorThree) {
        if (connectorOne == connectorTwo) {
            return MusicStyle.GANGSTA_RAP;
        }

        if (connectorTwo == connectorThree) {
            return MusicStyle.TECHNO;
        }

        if (connectorOne == connectorThree) {
            return MusicStyle.JAVA_FUNK;
        }

        return null;
    }

    private int getVolume(Long connectorOne, Long connectorTwo, Long connectorThree, Long connectorFour, Long connectorFive, Long connectorSix) {
        if (connectorOne == connectorTwo) {
            return 20;
        }

        if (connectorTwo == connectorThree) {
            return 40;
        }

        if (connectorThree == connectorFour) {
            return 60;
        }

        if (connectorFour == connectorFive) {
            return 80;
        }

        if (connectorFive == connectorSix) {
            return 100;
        }

        return 0;
    }

    private int getBeatsPerMinute(Boolean maxLimitSwitch) {
        int result;

        try {
            if (!maxLimitSwitch) {
                result = 200;
            } else {
                result = 150;
            }

            return result;
        } catch (RuntimeException e) {
            return 100;
        } finally {
            return 50;
        }
    }
}


Odpovědi

1. Styl hudby se zvolí správně, propojí se až konektory connectorOne a connectorThree. (Podmínka connectorOne == connectorThree by se sice díky autoboxingu splnila, ale k vykonání vůbec nedojde. Na prvním řádku metody vyletí NPE (pokus o autoboxing null hodnoty.)
2. Hlasitost se chybně nastaví na 20%. (Podmínka connectorOne == connectorTwo se nesplní, protože se porovnávají objekty Long se stejnou hodnotou operátorem == (identita instancí), a i když vznikly autoboxingem, hodnota je vyšší než 127, tudíž se jedná o různé instance (hodnoty do 127 vzniklé autoboxingem se cachují a resusují, takže porovnání takových Longů přes == by vrátilo true, v tomto případě však ne.)
3. Nastavení stylu hudby selže a skončí chybou. error (viz. odpověď 1)
4. BPM se nastaví na maximální hodnotu 200, protože jsi zapomněl nastavit omezující přepínač maxLimitSwitch a nechal ho na null. (if (!maxLimitSwitch) způsobí NPE díky autoboxingu null hodnoty typu Boolean, výsledná hodnota bude 50 – viz. odpověď 6)
5. Styl hudby se nezvolí vůbec a proměnná musicStyle zůstane null, connectorOne a connectorThree jsou nekompatibilního typu. (Jednak vyletí NPE (viz 1. odpověď), a i kdyby vykonání došlo až na tuto podmínku, díky autoboxingu by byla splněna (rozdílné typy int a Integer nevadí.)
6. Něco jsi udělal špatně, BPM bude líných 50. error (Veškerý kód metody je v try bloku a ve finally je return 50, proto se 50 vrátí vždy, bez ohledu na kód v try.)
7. Hlasitost se správně nastaví na 100%. error (Porovnávají se Long instance pomocí operátoru ==, takže se splní až poslední podmínka. Porovnává se cachovaná instance Longu s hodnotou pod 127 vzniklá autoboxingem.)
8. Při nastavení BPM nastane chyba, ale BPM se nakonec nastaví na přijatelnou hodnotu 100.  (Bez ohledu na return 100 v catch bloku se vrátí 50 díky return 50 ve finally bloku.)

Správné odpovědi na druhý úkol

Jsi ostřílený TexasWalker a přivolali tě k vyhrocené situaci. Poblíž je bomba, která může každou chvíli vybuchnout. Tvým úkolem je rozhodnout se, jak situaci vyřešíš. Můžeš přestřihnout modrý drát a bombu zneškodnit.

Je tady ale také možnost, že je bomba sestavená tak, že ji zneškodnit nejde. Pak zbývá jediná možnost: Utéct. Co uděláš?

Výbuch bomby nastane, když se objeví výjimka BOOOOOM



final Stream<character> redCableSignals = Stream.of('a','b','c','d');
final Stream</character><character> blueCableSignals = Stream.of('e','f','g','h');

RuntimeException BOOOOOM = new RuntimeException("BOOOOOM");
Integer bombSignal = 97;
Stream.of(redCableSignals, blueCableSignals)
        .peek(value -> {
            //we can peek inside the bomb
        })
        .flatMap(Function.identity())
        .map(Character::charValue)
        .mapToInt(Integer::new)
        .boxed()
        .map(value -> Objects.equals(value, bombSignal))
        .filter(Boolean::booleanValue)
        .findAny()
        .orElseThrow(() -> BOOOOOM);


Odpovědi

  1. Raději uteču, bomba vybuchne, protože u jednoho z drátů došel spouštěcí signál.  (Utíkat není třeba, bomba nevybuchne, viz. odpověď 2)
  2. Pokud nic neudělám, bomba vybuchne protože z jednoho z kabelů došel spouštěcí signál.  (Signál na konec streamu opravdu dojde, protože 97 je ASCII hodnota znaku ‘a’, ale bomba vybuchne díky poslednímu řádku právě tehdy, když signál nedojde. Je to takový dead-man-switch.)
  3. Když přeříznu modrý kabel (= obsahem proměnné blueCableSignals bude prázdný stream), bomba nevybuchne. error (Hodnoty v modrém kabelu nehrají žádnou roli, žádné písmeno nemá hodnotu 97. Bomba nevybuchne s modrým kabelem ani bez něj.)
  4. Nepřítel je amatér, nemusí provádět map (Character::charValue), i když Integer nemá konstruktor Integer(Character ch), je to zbytečný unboxing. error (Zbytečný unboxing, JAVA dělá automaticky.)
  5. Nepřítel je amatér, volání boxed() je tam úplně zbytečné, bude to fungovat i bez něj. (Boxing není zbytečný, protože neobjektový int nemá metodu equals, která se používá níže. Proto zde potřebujeme explicitně Integer.)
  6. Ve funkci peek() můžu bombě přenastavit bombSignal na nějakou bezpečnou hodnotu tak, abych zajistil, že bomba nevybuchne nikdy. (Proměnnou bombSignal nemůžeme v těle lambdy nijak měnit, všechny proměnné vstupující zvenku do lambda, funkcí musí být final, nebo efektivně final. Pokud bychom v těle lambdy měnili takovouto proměnnou, program se nezkompiluje.)
  7. Při výbuchu bomby se nepříteli objeví v logu záznam BOOOOOM výjimky z řádku 17. (Výjimka bude ze řádku 4 tam, kde se výjimka instancovala.)

Správné odpovědi na třetí úkol

Jsi neohroženým pilotem na straně rebelů a dostal jsi velmi nebezpečný a důležitý úkol. Musíš dopravit přísně tajné plány bojové operace na utajovanou základnu uprostřed hvězdného systému plného nepřátelských lodí. Pilotovat budeš nejmodernější a nejrychlejší stíhačku rebelů – Starfighter

páté generace. Ani její rychlost by ale nemusela stačit, proto bude tvá loď maximálně odlehčená a ponese minimum paliva. Snad to inženýři dobře spočítali! Celý let s použitím hyperprostorových skoků nesmí trvat déle než 3 sekundy. Pokud budou plány odhaleny, je s rebely konec.



package cz.starfighter;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class StarFighterV5 {

    private static class FuelTank {

        private AtomicInteger fuelSupply;

        public FuelTank(int capacity) {
            fuelSupply = new AtomicInteger(capacity);
        }

        public void consume(int consumption) {
            int remaining = fuelSupply.addAndGet(-consumption);

            if (remaining < 0) {
                throw new RuntimeException("Out ouf fuel.");
            }
        }

        public void fill(int volume) {
            fuelSupply.addAndGet(volume);
        }

        public int empty() {
            return fuelSupply.getAndSet(0);
        }

        public int getCurrentSupply() {
            return fuelSupply.get();
        }
    }

    public static void main(String[] args) throws Exception {
        long launch = System.currentTimeMillis();

        FuelTank spaceShipTank = new FuelTank(200);
        int numberOfEngines = 1;
        ThreadPoolExecutor enginesReference = null;

        try {
            ThreadPoolExecutor engines = new ThreadPoolExecutor(numberOfEngines, numberOfEngines, 60, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(50));
            enginesReference = engines;

            CompletableFuture<integer> completableFuture = CompletableFuture.supplyAsync(() -> {
                hyperSpaceJump(100, spaceShipTank);
                return spaceShipTank;
            }, engines)
                    .thenCombineAsync(CompletableFuture.supplyAsync(() -> {
                        hyperSpaceJump(50, spaceShipTank);
                        return new FuelTank(100);
                    }, engines), (tank, externalTank) -> {
                        tank.fill(externalTank.empty());
                        hyperSpaceJump(50, tank);
                        return tank;
                    }, engines)
                    .thenComposeAsync(tank -> {
                        hyperSpaceJump(50, tank);
                        return CompletableFuture.supplyAsync(() -> {
                            System.out.println("Almost there!");

                            hyperSpaceJump(50, tank);
                            return tank.getCurrentSupply();
                        }, engines);
                    }, engines);


            System.out.println("All done!");

            Integer remainingFuel = completableFuture.get();

            System.out.println(
                    "Arrived in " + (System.currentTimeMillis() - launch) + " ms with " + remainingFuel + " units of fuel remaining.");
        } finally {
            if (enginesReference != null) {
                enginesReference.shutdownNow();
            }
        }
    }

    private static void hyperSpaceJump(int distance, FuelTank tank) {
        try {
            Thread.sleep(distance * 10);
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted.");
        }

        tank.consume(distance);
    }
}


Odpovědi

  1. Inženýři to spočítali špatně, lodi dojde palivo a stíhačka k cíli nedoletí. error (Palivo nedojde, po posledním skoku bude obsah nádrže na 0.)
  2. Pokud by loď měla 2 motory, doletí k cíli včas. error  (Pokud budou 2 thready, bude čas něco přes 2 500 ms (futures v thenCombine proběhnou paralelně).
  3. Loď doletí k cíli včas. error (S 1 motorem (threadem) bude čas něco přes 3 000 ms.)
  4. Velitel mise v rádiu uslyší nejprve „All done!“ a pak „Almost there!“. error (Vytváření pipeline (thenApply, thenCompose…) je neblokující, kód se vykonává v jiném threadu.)
  5. Pokud by loď měla 2 motory, dojde jí palivo a k cíli nedoletí. error (Počet motorů (threadů) nemá vliv na spotřebu paliva.)
  6. Loď k cíli doletí, ale pozdě, let bude trvat déle než 3 sekundy. error (viz. odpověď 3)
  7. Pokud by loď měla 5 motorů, mohla by se doba letu dostat pod 1 sekundu. error (Žádný další thread od 2 a více nezkrátí dobu vykonání (pouze futures v thenCombine proběhnou paralelně, zrychlení tedy poskytnou už 2 thready, další thready nemají vliv.)

Chceš dál rozvíjet svoji sílu?

Pokud ano, vždy rádi přivítáme výjimečné kluky a holky do našich týmů v Brně, Hradci Králové, Praze, Bratislavě i na home office. Umožníme ti rozvinout tvou sílu k dokonalosti! Jak? Přijď na excelentní kávu a můžeme to probrat.

Pokud už víš, že s námi do toho chceš jít, tak do týmu hledáme nové MoroSystémáky. Podívej se na otevřené pozice.


Za celý tým MoroSystems, který se na této soutěži podílel, děkuji vám všem, kteří si s námi změřili svoji sílu. Věříme, že to byla zábava a že výherci si užili své ceny. Tak zase příště :-)

Ať tě provází síla Javy!