31 grudnia 2011

17b 79 63 7a 65 6e 69 61 20 6e 6f 77 6f 72 6f 63 7a 6e 65

3 komentarzy
Właśnie dobiega końca 2011 rok i nadeszła pora na życzenia noworoczne. Ostatnio siedzę nad reprezentacją liczb całkowitych w Javie, więc nie inaczej mogło być i dzisiaj (w końcu to taka uroczysta pora, która wymaga specjalnego potraktowania :-))
1010011 1111010 1100011 1111010 100011001 101011011 1101100 1101001 1110111 1100101 1100111 1101111
100000
1001110 1101111 1110111 1100101 1100111 1101111
100000
1010010 1101111 1101011 1110101
100000
110010 110000 110001 110010
100000
101111100 1111001 1100011 1111010 1111001
100000
1001010 1100001 1100011 1100101 1101011
100000
1001100 1100001 1110011 1101011 1101111 1110111 1110011 1101011 1101001
100000
1111010
100000
1110010 1101111 1100100 1111010 1101001 1101110 100000101 101110
Do odkodowania można skorzystać z poniższej aplikacji.
package pl.japila.java7;

import java.util.Scanner;

import javax.swing.JOptionPane;

public class ZyczeniaNoworoczne {

    public static void main(String... args) {
        String userInput = JOptionPane.showInputDialog(null,
                "Wprowadź dane do odkodowania (zastosuj zasadę Copiego & Paste)");

        StringBuilder zyczeniaNoworoczne = new StringBuilder();

        Scanner scanner = new Scanner(userInput);
        while (scanner.hasNext()) {
            zyczeniaNoworoczne.append((char) Integer.parseInt(scanner.next(), 2));
        }

        JOptionPane.showMessageDialog(null, zyczeniaNoworoczne);
    }

}
p.s. Do odkodowania tytułu zastosuj podstawę 16 w linii 17.

30 grudnia 2011

O kodzie uzupełnień do dwóch w Javie raz jeszcze

0 komentarzy
W Kod uzupełnień do dwóch w Javie (reprezentacja binarna liczb całkowitych) zaprezentowałem moją dotychczasową wiedzę na temat reprezentacji binarnej liczb całkowitych w Javie. Uważam to za mój początek w dokładniejszym rozpoznaniu tematu i nie ukrywam, że wciągnął mnie. Przypomnę tylko, że zaczęło się od zmian w Javie 7 z Fork/Join (nowe podejście do współbieżności w Javie z konstrukcjami wyższego poziomu), aby przez operator przesunięcia w prawo bez znaku >>> przejść do kodu uzupełnień do dwóch dla liczb całkowitych w Javie. Właśnie takie przejścia z jednego tematu na drugi w krótkim czasie lubię najbardziej. Nie pozwalają człowiekowi na dłuższy bezruch.

Przez ostatni tydzień dalej zgłębiałem temat i przesiedziałem sporo czasu czytając różnej maści artykuły. O większości pisałem na swoim kanale @jaceklaskowski na twitterze, więc wielu już miało przedsmak tego, o czym teraz będę pisał.

Prawie.

Liczby całkowite w Javie

Specyfikacja The Java Language Specification, Third Edition w rozdziale 4.2.1 Integral Types and Values wymienia typy całkowite z ich zakresami. W kolejności ich długości wyróżniamy: byte na 8 bitach, short na 16 bitach, int na 32 bitach i najdłuższy long na 64 bitach. Jest jeszcze całkowite char, które reprezentowane jest na 16 bitach, z tą różnicą, w porównaniu do poprzednich, że bez bitu znaku (najstarszy bit, pierwszy od lewej strony, albo ostatni z prawej).

I już przy omawianiu dostępnych typów dostrzec można ich różną reprezentację wewnętrzną - byte, short, int i long są z bitem znaku, w przeciwieństwie do char, któremu dano wszystkie dostępne bity do dyspozycji.

Dodawanie i liczba przeciwna w kodzie uzupełnień do dwóch

W artykule na Wikipedii Two's complement trafiłem na zdanie, które wywarło na mnie niesamowite wrażenie i sprawiło, że zrozumiałem sens istnienia tego systemu kodowania. Uważam, że mogłoby stanowić świetne wprowadzenie dla całego artykułu, albo jedyne:

"Two's complement numbers is a way to encode negative numbers into ordinary binary, such that addition still works."

Tylko o jakie dodawanie chodzi?!

Właśnie o zwykłe dodawanie binarne się rozchodzi. Jak mogłem się zorientować przeszukując materiały w Sieci, istnieje wiele systemów reprezentowania liczb całkowitych, ale czy to podwójne zero, czy konieczność rozróżniania znaku dodawanych liczb, sprawiają, że kod uzupełnienia do dwóch wydaje się być najbardziej trafnym. I taki zastosowano w Javie.

W Signed Int: Two's Complement mogłem dalej zgłębiać niuanse kodu uzupełnień do dwóch, który od tej pory będę zapisywał jako 2C (od angielskiego two's complement). Tam dowiedziałem się, że w 2C występuje jedno zero i dodawanie jest spójne dla reprezentacji bitowej z i bez znaku korzystając ze sprzętowej realizacji dodawania bitów (bez względu, czy reprezentują liczbę ze znakiem, czy bez - obie reprezentacje sprowadzane są do reprezentacji bez znaku). Ta cecha 2C jest związana z działaniem sprzętowym dodawania, a tutaj moja wiedza kończy się niezwykle szybko i na tym poprzestanę. I czuję, że więcej nie jest mi potrzebne o maszynowych rozwiązaniach.

Zadanie dla dociekliwych: wykonaj bitowe dodawanie liczb całkowitych, np. 1 i 2.

Najdłuższa liczba całkowita - typu long - ma do dyspozycji 64 bity. Pierwszy bit zarezerwowany jest dla bitu znaku (poza char).

Do uzyskania liczby ujemnej w 2C mamy 3 różne sposoby, z których najczęściej brany jest ten, który polega na odwróceniu wszystkich bitów i dodaniu jedynki, tj. -B = ~B + 1, przy założeniu, że B to dowolna liczba całkowita.

Zadanie dla dociekliwych: znajdź liczbę przeciwną do 1 korzystając z powyższego algorytmu.

I właśnie w tym momencie dociera do mnie jak interesującym jest rozpoznawanie tematu reprezentacji 2C. Dodaj 1 do liczby, której reprezentacja bitowa zawiera wyłącznie 1ki (czyli -1).
1111 1111 1111 1111 1111 1111 1111 1111     // -1
+ 0000 0000 0000 0000 0000 0000 0000 0001     //  1
-------------------------------------------------------------------
 10000 0000 0000 0000 0000 0000 0000 0000     //  0 (na 33 bitach = przepełnienie!)
Obie liczby są typu int. Obie mają do dyspozycji 32 bity z ostatnim bitem (licząc od lewej) zarezerwowanym na znak. Wynik również musi mieścić się w 32 bitach, ale cóż to?! Dodawanie 1 i -1 kończy się przepełnieniem - wynik wymusza 33 bity. W Javie taka sytuacja jest ukrywana przez usunięcie dodatkowego 33 bitu, aby w ten sposób otrzymać liczbę 32-bitową, która składa się wyłącznie z samych 0, a to po prostu 0 w systemie dziesiętnym. Jakież to piękne!

Idąc dalej, możnaby zastanowić się, co stanie się przy wyznaczaniu liczby przeciwnej dwukrotnie? Czy zachodzi zasada wyznaczania liczby przeciwnej podwójnie, która powinna wyznaczyć liczbę początkową, czyli -(-x) = x, w 2C?

Krok 1. Reprezentacja liczby całkowitej w postaci 32 bitów (dla int) lub 64 bitów (dla long). Ja pozostanę przy 32 bitach.

int n0 = 1111 1111 1111 1111 1111 1111 1111 1111 // -1

Krok 2. Odwracamy wszystkie bity

int n1 = 0000 0000 0000 0000 0000 0000 0000 0000 // 0

Krok 3. Dodajemy jedynkę

int n2 = 0000 0000 0000 0000 0000 0000 0000 0001 // 1

Zakończyłem pierwsze wyliczenie liczby przeciwnej do zadanej, czyli -1. Czy kontynuując odwracanie wyliczę wyjściową, czyli -1?

Krok 4 Reprezentacja bitowa liczby 1

int n00 = 0000 0000 0000 0000 0000 0000 0000 0001 // 1

Krok 5 Odwrócenie bitów

int n10 = 1111 1111 1111 1111 1111 1111 1111 1110 // nieistotne

Krok 6 Dodajemy jedynkę

int n20 = 1111 1111 1111 1111 1111 1111 1111 1111 // -1

I jak łatwo zauważyć n20 == n0, czyli parzyste wykonanie wyznaczania liczby odwrotnej do zadanej zawsze zwróci liczbę początkową.

Z Why computers represent signed integers using two’s complement tylko upewniłem się, że 2C jest warte poświęconego czasu i jego zrozumienie uważam od tej pory za obowiązkowe (ja już mam za sobą, więc tym łatwiej jest mi rzucać takie stwierdzenia :)).

"The representation of signed integers is the representation used by modern processors. It is called "two's complement" because to negate an integer, you subtract it from 2N. For example, to get the representation of –2 in 3-bit arithmetic, you can compute 8 – 2 = 6, and so –2 is represented in two’s complement as 6 in binary: 110."

W tym zdaniu znajduje się kolejny sposób na wyznaczanie liczb przeciwnych w 2C. Po prostu odejmujemy liczbę dodanią od 2^N, czyli dla 32 bitowych liczb typu int będzie to 1 + 32 zera w binarnej reprezentacji (wyznaczenie, a co ważniejsze, zapamiętanie tej liczby stanowi nie lada wyzwanie umysłowe, więc pozostańmy przy takim opisie).

Z Kod uzupełnień do dwóch w Javie (reprezentacja binarna liczb całkowitych) wiemy, że mnożenie
package pl.japila.java7;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class TwoCDemo {

    @Test
    public void test() {

        long oneAnd32Zeros = (long)1 << 32; // 0x1_FFFF_FFFF - int overflow!
        int three = 3;  // 0b11
       
        int minusThree = (int)(oneAnd32Zeros - three);
       
        assertThat(minusThree, is(-3));
    }

}
Jako podsumowanie, warto zwrócić uwagę na użycie operatora przesunięcia w lewo, aby uzyskać liczbę podwójnie większą od największej w zakresie int. Nie chciałem pisać tej liczby dziesiętnie, a (czego nie wiedziałem wcześniej) jej reprezentacja w notacji bitowej (z 0b), ósemkowej (z wiodącym 0), albo szesnastkowo (z 0x) nie jest możliwa - są one zarezerwowane wyłącznie dla typów int i mniejszych.

23 grudnia 2011

Kod uzupełnień do dwóch w Javie (reprezentacja binarna liczb całkowitych)

7 komentarzy
Wszystko zaczęło się od mojego przedstawienia zmian w Javie 7, w pakiecie java.util.concurrent podczas 84 spotkania Warszawa JUG - Warszawski Eclipse DemoCamp 2011 - Java 7, JavaFX i Eclipse (prezentacja do pobrania jako JacekLaskowski-EclipseDemoCamp2011-ConcurrencyUtilitiesJava7-2011.11.08.pdf).

Wtedy zaczęła się moja przygoda ze szkieletem Fork/Join. Rozwiązywanie problemu przez zrównoleglanie jego mniejszych składowych wymaga właściwego sposobu podziału (zwykle po połowie) i tak do ustalonego, minimalnego poziomu jego złożoności, a właściwie braku, po którym rozwiązanie można obliczyć "siłowo" (element po elemencie, liniowo).

Kwestią, z którym zwykle zmagają się programiści korzystający z Fork/Join (czy dowolnego problemu rozwiązywanego przez algorytmy typu "dziel i zwycieżaj") to, w jaki sposób dzielić, aby samo dzielenie nie było na tyle skomplikowane, że zysk ze zrównoleglenia zostanie przez niego skonsumowany i ostatecznie wyjdziemy na przysłowiowe "zero".

I tu pojawia się przyczynek do tego wpisu - operator przesunięcia bez znaku w prawo >>> (ang. unsigned right shift) w Javie.

Nie jest to niczym odkrywczym w Javie 7, ale przy Fork/Join nabrał większego znaczenia. Mówiąc wprost, ja na niego zwróciłem uwagę właśnie przy Fork/Join. I tak kończy się w zasadzie rola Fork/Join, które nie będzie już przywoływane, bo posłużył wyłącznie jako tło do rozpoznania operatora przesunięcia i jak się później okazało reprezentacji liczb całkowitych w Javie.

Weźmy następujący problem: W jaki sposób wyznaczyć połowę pewnej liczby nieujemnej x?

Liczba dowolna, acz ustalona, x (teraz dopiero dojrzałem, aby dostrzec piękno tych słów) może być liczbą elementów w tablicy, w którym znajdują się elementy do przetworzenia.

Operator przesunięcia w prawo bez znaku >>> jest złożeniem << i >> w zależności od znaku lewego argumentu - dodatni to >>, a ujemny...cóż...tu sprawa się komplikuje i wygląda (n>>s)+(2<<~s) przy założeniu, że rozważamy n>>>s.

Pamiętam, kiedy dostrzegłem (a właściwie pokazano mi palcem), że n << 1 to po prostu n * 2. Innych zastosowań przesunięcia w lewo jeszcze nie odkryłem, ale pewnie są równie zabójcze dla mojego serca :)

Wtedy zacząłem zgłębiać reprezentację liczb całkowitych w Javie, bo w końcu działanie tych operatorów polega na przesunięciach binarnych.

Zadanie wprowadzające: Czy znasz zapis binarny ujemnej liczby całkowitej w Javie? Niech to będzie -1 lub Integer.MIN_VALUE.

Właśnie wtedy zreflektowałem się, jak niewiele wiem na ten temat. Niewiele?! Delikatnie powiedziane. Nic nie wiem! Zabrałem się za lekturę specyfikacji języka Java (tutaj niewiele znalazłem poza ogólnikami), aby skończyć na pojęciach reprezentacjach liczb ze znakiem i bez oraz kod uzupełnień do dwóch (ang. two's complement).

I tak od rozpoznawania Fork/Join przeszedłem do operatora przesunięcia, aby skończyć na reprezentacji liczb całkowitych w Javie.

W ten sposób powstała moja implementacja zamiany binarnego ciągu znaków (bez wiodącego 0b, które doszło w Javie 7) do postaci liczby całkowitej w zapisie dziesiętnym. Klasa nie jest krótka, ale starałem się dobierać nazwy do ich przeznaczenia, więc sądzę, że stosunkowo łatwo będzie zorientować się, co miałem na myśli.

Przede mną analiza kodów źródłowych java.lang.Integer, która dostarcza większości z poniższych metod. Niedługo więcej w temacie, bo nie czuję, abym go wyczerpał (a mam wrażenie, że jedynie zdrapałem wierzchnią warstwę). Oczekuję uwag i wskazówek od życzliwego czytelnika (w czasie świąt niegodnym nie podzielić się miłym słówkiem).

Gdybyśmy już się nie widzieli, życzę najlepszego z okazji nadchodzących Świąt Bożego Narodzenia. Baw się i świętuj, aby wypoczęty wrócić do dalszych prac poznawczych.
package pl.japila.java7;

public class BinaryToDecimalIntDemo {

    static final char ZERO = '0';
    static final char ONE = '1';

    public static void main(String[] args) {
        for (int number = Integer.MIN_VALUE; number <= Integer.MIN_VALUE + 0xFFFF; number++) {
            String negativeNumber = Integer.toBinaryString(number);
            int intInDecimal = BinaryToDecimalIntDemo.getIntInDecimal(negativeNumber);
            assert number == intInDecimal;
        }
        for (int number = Integer.MAX_VALUE; number >= Integer.MAX_VALUE - 0xFFFF; number--) {
            String negativeNumber = Integer.toBinaryString(number);
            int intInDecimal = BinaryToDecimalIntDemo.getIntInDecimal(negativeNumber);
            assert number == intInDecimal;
        }
    }

    static int getIntInDecimal(String binary) {
        int sum = 0;
        boolean negative = false;
        char[] bits = binary.toCharArray();
        if (bits.length == Integer.SIZE) {
            if (isNegative(bits)) {
                negative = true;
                bits = subtractOne(invertBits(removeSignBit(bits)));
            }
        }
        for (int i = bits.length - 1, j = 0; i >= 0; i--, j++) {
            sum += calculateValueInBinaryRepAt(j, bits[i]);
        }
        return negative ? (sum == 0 ? Integer.MIN_VALUE : -sum) : sum;
    }

    private static char[] subtractOne(final char[] bits) {
        char[] newBits = new char[bits.length];
        System.arraycopy(bits, 0, newBits, 0, newBits.length);
        int i = newBits.length - 1;
        if (newBits[i] == ONE) {
            newBits[i] = ZERO;
        } else {
            newBits[i] = ONE;
            for (int j = i - 1; j >= 0; j--) {
                if (newBits[j] == ZERO) {
                    newBits[j] = ONE;
                } else {
                    newBits[j] = ZERO;
                    break;
                }
            }
        }
        return newBits;
    }

    private static char[] invertBits(char[] bits) {
        char[] newBits = new char[bits.length];
        System.arraycopy(bits, 0, newBits, 0, newBits.length);
        for (int i = 0; i < newBits.length; i++) {
            newBits[i] = (newBits[i] == ZERO ? ONE : ZERO);
        }
        return newBits;
    }

    private static char[] removeSignBit(char[] bits) {
        char[] newBits = new char[bits.length - 1];
        System.arraycopy(bits, 1, newBits, 0, newBits.length);
        return newBits;
    }

    private static boolean isNegative(char[] bits) {
        return bits.length == Integer.SIZE && bits[0] == ONE;
    }

    private static double calculateValueInBinaryRepAt(int i, char c) {
        return Math.pow(2, i) * Character.getNumericValue(c);
    }

}

18 grudnia 2011

Relacja z cracow.mobi w Krakowie

12 komentarzy
Dzień rozpocząłem dosyć wcześnie, bo aż o 5:30 i było to zdecydowanie za wcześnie, aby wystąpić jako prelegent na konferencji, jeśli dodać wydarzenia poprzednich dni

Dzień wcześniej poprowadziłem prezentację na temat IBM WebSphere Application Server V8 u jednego z klientów IBM na południu Polski (nazwa i miejsce nie mają znaczenia, więc pozostańmy przy anonimowych nazwach). Tym razem pobudka o 4:45, aby wyrobić się na 6:17 na pociąg. Oczywiście dzień wcześniej również zeszło mi się do po północy przed kompem. Wszystko takie interesujące i ekscytujące, że kiedy przychodzi wieczór i rodzinka kładzie się spać, albo część już dawno śpi, cisza zapada i tak się siedzi, i siedzi, i siedzi, aż zegar wybija północ (!) Pamiętam, jak uporałem się z tym problemem kilka miesięcy temu, kiedy regularnie chodziłem spać około 22, aby zrekompensować "straty" pobudką wcześnie rano. I człowiek wyspany, i jakoś spokojniej z rana, i wszystko takie dopiero budzące się do życia, a dorzucając do tego, że wszystko działo się w lato, kiedy słońce gorąco prażyło, aż się chciało w tym wszystkim uczestniczyć!

Zmęczenie jest zdecydowanie niewskazane przy jakiejkolwiek aktywności, a ta, która wymaga pełnego skupienia i udziału publiczności, jak wystąpienie na konferencji, jest nadzwyczaj niebezpieczna w takim stanie. Potrafi wydrenować ostatnie resztki energii.

Do Krakowa dotarłem na czas - 10:15. Niedługo po rejestracji trafiłem na Radka Holewę! Jakież było moje zdumienie widząc jego wesołą twarz, która musiała z pewnością kontrastować z moją, na której rysowało się postępujące (i sukcesywnie wyniszczające) zmęczenie. Moja ekscytacja spotkaniem z Radkiem jeszcze bardziej wpłynęła na moją kondycję (tak samo pozytywnie, co i negatywnie, więc możnaby założyć, że saldo pozostało bez zmian, ale wahnięcia również odciskają swoje piętno). Kilka późniejszych rozmów z Konradem "ktosopl", Andrzejem "ags" i dopiero co poznanym Bartkiem Filipowiczem (prelegentem po mnie) tylko pogarszało sprawę. Nawet gdybym o tym wiedział wcześniej, za nic i tak nie zrezygnowałbym z okazji zamienienia z nimi słowa. Właśnie podczas bezpośrednich spotkań dostrzegam ile tracę ślęcząc przed kompem zamiast wyjść "na miasto".

Za zmęczeniem przywlokło się inne "cudo" - niepokój o moje przygotowanie. Konferencja cracow.mobi była moją pierwszą, w której prezentacje były z bardzo wąskiego tematu - tworzenia aplikacji mobilnych na platformę Android. Do tej pory zwykłem brać udział w takich, na których poruszano zagadnienia związane z językiem Java, technologią Java EE i miękkimi technikami wytwarzania oprogramowania. Zakres tematyczny zwykle był na tyle obszerny, że trudno było porównywać poszczególne prezentacje pod względem merytorycznym. Pozostawała jedynie możliwość porównywania ich pod względem estetycznym - przygotowanie prelegenta w temacie, wygląd prezentacji i w ogóle interakcja z publicznością. To dawało stosunkowo obszerne pole do popisu (lub ukrycia swojego niewielkiego praktycznego doświadczenia).

To uzmysłowiłem sobie dopiero, kiedy zacząłem przyglądać się, w jaki sposób swoje tematy prezentują Konrad "ktosopl" Malawski i Marek Defeciński.

Konrad wystąpił z tematem "Deep dive into RoboGuice - beyond "Hello World" apps". Nie trudno było zauważyć jego ponadprzeciętną znajomość Androida - posługiwał się terminami androidowymi, jakby sam je tworzył i kilkukrotnie zapytany z sali, odpowiadał bez trudu. Słabiej, acz wciąż znośnie, wypadł prezentacyjnie. Kiedy wszedłem na salę, Konrad już mówił. Zacząłem uważnie przyglądać się, w jaki sposób przedstawiał temat, bo po raz pierwszy miałem możliwość zobaczyć go w akcji. I gdybym na pierwszym wrażeniu poprzestał i odpuścił sobie, to nota byłaby marna. Trudno było odgadnąć, jaki to temat wybrał sobie Konrad do przedstawienia. Tu miałem nie lada zagwozdkę. Przez pierwsze 30 minut Konrad przedstawiał Guice i założenia DI z @Inject. Ucieszyłem się z udziału Guice, a jednocześnie, przez cały ten czas, zachodziłem w głowę, co tak na prawdę skłania Konrada do jego omawiania. Koniec końców wszystkie prezentacje miały być z założenia o Androidzie, a tu czas mija, a o Androidzie ni widu ni słychu. Slajdy słabej jakości tylko pogarszały sprawę - wymagają dopracowania, bo prawie nic nie było widać. Trudno doszukiwać się problemu z projektorami, których ułożenie - jeden duży na dole i drugi na antresoli, oba z bardzo dobrą rozdzielczością - i sala, niewielka, acz dopasowana do liczby uczestników, gwarantowały komfort prelegentom i słuchaczom. W końcu nie wytrzymałem i zajrzałem do agendy - ma być o RoboGuice. Tego nie znałem. Ponownie podniosłem poziom zainteresowania na wysoki. I tak doczekałem się RoboGuice, aby na końcu doświadczyć testowania z nim. Konrad zasługuje na uznanie pod kątem jego obycia z Androidem i RoboGuice, ale na początku za bardzo odszedł od tematu i pod tym kątem zawiódł mnie. Widać potencjał prezentacyjny u Konrada i zrobię wszystko, co w mojej mocy, aby wziął udział w Confiturze 2012. RoboGuice wchodzi do mojego arsenału narzędziowego i z pewnością niebawem się nad nim będę rozwodził na tym blogu. Dzięki Konrad za inspirację!

Przerwa.

Całą prezentację Konrada przesiedziałem sam, aby móc w pełni skosztować jej smaków. Przesiadłem się do Radka, który rozmawiał z...Ryan'em Gosling'iem (!) Nie żartuję. Kolejny po mnie prelegent Bartek Filipowicz wygląda zupełnie, jakby zdjąć skórę z Ryan'a (nic nie ujmując jednemu czy drugiemu). Kto nie wierzy, niech zajrzy na stronę prelegentów cracow.mobi (na samym dole). Nie mogłem się powstrzymać i powiedziałem mu o tym. W ogóle nie widać było jego zdumienia. Bynajmniej u Radka. Podobno Bartek spotykał się z taką reakcją wcześniej. Nie mogłem zdjąć z niego oczu taki podobny! :) Później doszli do nas Andrzej i Konrad, któremu "sprzedałem" moją ocenę jego wystąpienia. Obiecał naniesienie poprawek. Może już na kolejną Confiturę? Gorąco będę go dopingował, aby zgodził się wziąć w niej udział. Konrad, mordo Ty moja, nie daj się prosić!

Po przerwie, mikrofon przejął Marek Defeciński z "Testowanie w systemie Android". Powiało nudą mimo, że temat i slajdy wręcz krzyczały, aby było inaczej. Gość ma wiedzę i doświadczenie w Androidzie - co do tego, nie mam żadnych wątpliwości, ale zdziwiłbym się, gdyby znalazły się osoby, które nie zarzuciłyby mu braku przygotowania od strony prezentacyjnej. Jak zwrócił uwagę Radek - 16 minut trwał wstęp o sobie! To jak za starych, dobrych czasów moich wystąpień, za które dostawałem cięgi. Później Marek zdecydował się na kod na żywo, ale z takimi wpadkami, że podziwiałem jego upór, aby go mimo trudności zaprezentować. Samoprezentacja przez 16 minut, niedziałające testy i w końcu uwagi odnośnie emulatora Androida, zmusiły mnie do zabrania głosu, aby wyprostować stwierdzenia o wolnym działaniu tego ostatniego. Jakoś w końcu musiałem zrekompensować sobie nudę! Można było odnieść wrażenie, że testy są złe, bo są baaardzo wolne w przypadku aplikacji androidowych. Jakkolwiek trudno mi potwierdzić tę tezę w ogólności, to w tym konkretnym przypadku Marek pracował na sprzęcie, na którym całe środowisko ADT wolno działało! Panowie i panie - nie twierdzę, że ADT to cudo inżynieryjne, ale nie łudźmy się, że procek i RAM to podstawa, aby poradzić sobie z takimi problemami. To na pewno nie pozwala na stwierdzenia, że testy są do kitu, bo...maszyna za wolna i kto je by tam robił.

Jakby tego było mało Marek przekroczył czas prezentacji o dobre 10 minut. Gdyby chcieć podsumować jego wystąpienie jednym zdaniem, to pozwoliłbym sobie na stwierdzenie, że w pewnym momencie stracił kontakt z horyzontem i zaczął pikować niebezpiecznie, ku niechybnemu rozbiciu. Szczęśliwie dla wszystkich nie doszło do niej - koniec wystąpienia nadszedł i ulga pojawiła się po obu stronach.

Mimo tylu gorzkich słów pod adresem Marka, cieszę się, że mogłem uczestniczyć w jego prezentacji, bo zgrabnie zaprezentował Robolectric, który wymaga android.jar, o którym wcześniej Konrad nie wspomniał, a jedynie pozwolił sobie na uwagi odnośnie niekompletności Android API, które kończą się komunikatami "Stub!". Jeśli dobrze rozumiem rozbieżność między Markiem i Konradem, to podobną sytuację mamy z bibliotekami Java EE 6 dostarczanymi przez GlassFish w repozytorium mavenowym, które są potrzebne przy kompilacji i odchudzono je o dostarczanie wyłącznie kompletnego API bez kompletnej implementacji. Nic nowego. Dzięki Marek za skorygowanie poprzednika! Już możesz szykować się na lipcową Confiturę!

Kiedy Marek zademonstrował uruchomienie testów z poziomu Maven'a z pomocą wtyczki Easy shell do Eclipse moja ogólna ocena prezentacji lekko się podniosła. Szkoda, że 30 minut prezentacji było do kosza.

Tak dotarłem do przerwy obiadowej. 1h nie pozwalała na wojaże po Krakowie w poszukiwaniu jedzenia, więc skoczyliśmy z Bartkiem "Ryan'em" do pobliskiej restauracji z kebabem. Zaczęło mnie jednak skręcać z obawy o moje przygotowanie, więc skończyło się na kilku gryzach i reszta wylądowała w koszu. Nerwy przed moim wystąpieniem kompletnie odebrały mi apetyt. Okazało się, że również i Bartkowi. Wspólnie przeszliśmy przez jego slajdy. To było dobre posunięcie, bo później okazało się, że nie dałem rady.

I w końcu moje wystąpienie. Pozostawiam jej ocenę samym uczestnikom. Była to moja pierwsza prezentacja o Androidzie, która pozwoliła mi przypomnieć sobie uczucie tremy, która wiąże gardło przed publicznym wystąpieniem. Na prawdę dało mi się to odczuć i samemu zwróciłem uwagę na mój łamiący się głos. Poprzedni prelegenci nie pozostawiali mi złudzeń, że wodolejstwo nie jest tu mile widziane. Machanie rękoma należy odłożyć na bok i oczekuje się prezentacji na wysokim poziomie. Raczej nie byłem przygotowany do tego.

Mimo wszystko jestem z niej zadowolony pod kątem zaangażowania kilku osób w jej przebieg (w ten sposób próbowałem markować niedostateczne przygotowanie). Udało mi się poznać Jurka "AsyncTask", Grzegorza "Service" i Pawła "wyciek Contextu". Pojawiło się jeszcze kilka innych osób, które zechciały zabrać głos, ale ich niestety nie poznałem z imienia. Brawa dla wszystkich. Życzyłbym sobie, aby cała trójca zechciała przyjąć moje zaproszenie na Confiturę. W ich wypowiedziach dało się słyszeć doświadczenie i pewność swoich tez. Takich ludzi potrzeba więcej, aby ich postawa prowokowała do dyskusji podczas konferencji, co ma służyć dalszej wymianie doświadczeń. Jeśli Panowie czytacie ten wpis, zachęcam do kontaktu. Sam też Was będę poszukiwał. Pawła znam już osobiście, a Grzegorza jedynie mailem, więc zostaje jeszcze Jurek.

Pod względem merytorycznym u mnie było...średnio. Jakim to doświadczeniem mogę się mienić, skoro moje przygody z Androidem zacząłem pół roku temu?! Za to pod względem czasowym wypadłem perfekcyjnie. Zacząłem punktualnie, przygotowany psychicznie i sprzętowo. I tak też skończyłem - równo o czasie. Temat mojej prezentacji "RESTful Android" był nietrafiony, bo zdryfował na tematykę współbieżności na Androidzie, ale skoro przed samym rozpoczęciem wspomniałem o tym, czuję się zrehabilitowany. Jeśli tylko nie uraziłem uczestników swoim poziomem merytorycznym, cieszę się, że mogłem ponownie doświadczyć tego błogiego uczucia braku pewności w moje przygotowanie merytoryczne.

Slajdy dostępne są jako JacekLaskowski-cracow.mobi-RESTful-Android-2011.12.09.pdf.

Po moim wystąpieniu podeszło do mnie dwóch programistów androidowych z Comarchu - Maciej i kolega, którego imienia nie zapamiętałem (wybacz), którzy przedstawili mi problemy z dużą liczbą View w Activity (ponad 80) i problemami z działaniem Galaxy S2. Niestety, mimo, że szukali pomocy u mnie, to nie trwało długo, abym zreflektował się, kto tu potrzebuje pomocy - to nie ja im, ale oni mnie mogą pomóc. Mam do nich kontakt i nie zawaham się go użyć! Takich ludzi chciałbym więcej jako prelegentów na Confiturze 2012. Muszę nad nimi popracować jeszcze, bo nieświadomi moich planów względem nich.

Tak zeszła mi prezentacja Bartka. Wybacz Bartek! Zaproszenie na Confiturę wciąż podtrzymuję, więc pozostajemy w kontakcie.

Tak też skończyła się ścieżka wykładowa, ale nie moje poznawanie nowych twarzy. Mimo, że to wciąż konferencja javowa, to mało było osób, które wcześniej znałem. Wciąż zachodzę w głowę, czy Android to pole dla dotychczasowych znajomych z branży? Jakoś niewielu para się Androidem i trudno mi teraz odpowiedzieć dlaczego. Frapuje mnie to, więc niebawem pewnie jakaś odpowiedź się znajdzie.

Na sam koniec trafiłem na kilku napaleńców konferencyjnych, którzy zapowiedzieli już organizację konferencji o urządzeniach inteligentnych w Katowicach! Pozdrowienia dla Piotra "kosarock" i Marcina! Nie tylko zaskoczyli mnie swoim zdeterminowaniem, ale również wyborem miejsca (a może przede wszystkim tego drugiego). Sądziłem, że Kraków i Wrocław promieniują na okolicę tak silnie, że trudno mówić o kolejnej inicjatywie w pobliżu. W samym Krakowie mamy już GeeCON z ekipą z Polish JUG, JDD Proidei z Andrzejem i Anią na czele, 33rd degree Grześka Dudy, teraz cracow.mobi, a jeszcze są SFI i Eclipse DemoCamp. Dodać do tego silne oddziaływanie Poznania (Eclipse DemoCamp, Code Retreat i potencjalnie GeeCON) oraz Warszawy (Confitura, warsjawa i Eclipse DemoCamp), i nie widzę miejsca na nową propozycję w środkowej i południowej Polsce (może za wyjątkiem Łodzi, w której ostatnio mieliśmy do czynienia z mobilization i Code Retreat). Gdybym tylko mógł oddać zapał katowickich organizatorów, to pewnie wielu z Was nie miałoby złudzeń, że w 2012 będzie się mobilnie działo w Polsce, a Katowice stanie się kolejnym miejscem konferencyjnym po cracow.mobi i mobilization. Będę ich wszystkich gorąco dopingował. Z tyloma konferencjami w okolicy, będzie więcej okazji na wymianę doświadczeń. Bardzo się z tego cieszę i kiedykolwiek poproszony o pomoc, zawsze chętnie jej udzielę. Zresztą organizatorzy odgrażali się, że już jestem zaproszony! Z pewną nieśmiałością przyjmuję zaproszenie. Dziękuję!

O 16:45 byłem już w pociągu, aby przed 21 pojawić się w domu. Zmęczony i podekscytowany cieszyłem się, że wcześniej odwołałem udział w Agile Development Day 2011 w Warszawie, które zaplanowane zostało na całą sobotę! Po prostu nie dałbym rady. Tak bardzo chciałem w nim uczestniczyć, że kiedy już się pojawiła w harmonogramie, okazało się, że nie dane mi w niej wziąć udziału. Tak bardzo chciałem móc zasiąść z Jakubem Nabrdalikiem w parze i przy akompaniamencie Krzyśka Jelskiego ponownie wczuć się w melodię TDD. Następnym razem.

Trójka organizatorów cracow.mobi: Mateusz, Maria i Łukasz, których miałem przyjemność poznać podczas konferencji stanęła na wysokości zadania. Jestem im niezwykle wdzięczny, że umożliwili mi wziąć udział w konferencji i to w zaszczytnej roli prelegenta. Niech to będzie dzień, w którym upewniłem się, że inwestycja mojego czasu w rozpoznanie Androida była dobrym wyborem. Nowa technologia, zupełnie nowa klasa urządzeń, nowi ludzie - w roli uczestników, prelegentów i organizatorów. Jestem pozytywnie naładowany na kolejne androidowe przyjemności. Nie mógłbym sobie wymarzyć lepszego zakończenia roku 2011!

Nagrania z konferencji mają być dostępne na kanale mobiledeveloperpl na YouTube. Zapraszam do ich oglądania i komentowania. Uwagi zawsze mile widziane. Już nie mogę doczekać się, kiedy tylko pojawi się nagranie z mojego wystąpienia. Oj wstyd mi, oj wstyd, że można było tak wiele, a dałem tak niewiele. Kolejne książki czekają na moją przychylność i kolejne pomysły na aplikacje. Końcówkę roku 2011 zaplanowałem androidowo.

15 grudnia 2011

ManagementFactory.getPlatformMXBeans() w Javie 7 i nauka generyków

4 komentarzy
Jestem technicznym recenzentem książki Java 7 New Features Cookbook przed jej oficjalnym wydaniem na początku 2012 (pisałem o tym w Pierwszy rozdział o Java 7 od Packt) i w rozdziale 9. Database, Security and System Enhancements trafiłem na metodę java.lang.management.ManagementFactory.getPlatformMXBeans().

Jej użycie od razu przykuło moją uwagę, przede wszystkim dlatego, że korzysta z typowego użycia typów generycznych w Javie. Zwykle generyki sprawiały mi trudność i postanowiłem tym samym sprawdzić swoją ich znajomość. Po przejrzeniu kodu źródłowego tej metody postanowiłem spróbować swoich sił i napisać własną metodę o podobnej funkcjonalności. Co jednak istotne, to zależało mi na użyciu generyków.

I tak powstała klasa poniżej.
package pl.japila.java7;

import static java.lang.System.out;

public class Demo {

    public static void main(String[] args) throws Exception {
        int i = getInstance(Integer.class);
        out.println("i=" + i);
    }

    public static <T extends Number> T getInstance(Class<T> clazz)
            throws InstantiationException, IllegalAccessException {
        return clazz.newInstance();
    }

}
Czy dostrzegasz błąd, który popełniłem? Czy potrafisz wskazać go bez uruchamiania tej klasy? Ja niestety nie wykazałem się odpowiednią dbałością o szczegóły i umknęło mi to jedno ważne założenie. A jak u Ciebie?

Przy okazji pisania tej klasy znalazłem również sposobność, aby przetestować skrót klawiszowy w Eclipse do utworzenia statycznego importu dla System.out - Cmd+Shift+M. Spróbowałem również odszukać tej funkcjonalności przez odpalenie Quick access i tam też to można znaleźć.


Dzięki Marcinowi Stachniukowi (z Agile Development Day) mogłem nauczyć się czegoś nowego o Eclipse! Dziękuję!

Przeczytałem wpis Marcina, skomentowałem go, zrecenzowałem rozdział, popróbowałem się z generykami i jeszcze zapamiętałem dwa skróty klawiszowe w Eclipse. Nie za dużo jak na jeden dzień?! :)

14 grudnia 2011

Wrażenia pokonferencyjne - o Eclipse DemoCamp w Poznaniu

3 komentarzy
Jak ten czas szybko płynie! Wydaje się, że to wcale nie tak dawno, kiedy pisałem o konferencji JDD w Krakowie, a to już prawie 2 tygodnie mija i dopiero teraz przedstawiam wrażenia z kolejnej, ze mną w roli prelegenta. Potwierdza się stara, dobra zasada, że zadania trzeba robić, a nie o nich mówić i w przypadków moich relacji pokonferencyjnych niestety nie udało mi się jej zastosować. Nadrabiam.

Dobrego złe początki

Że też zawsze muszę sobie wybrać temat na wystąpienie, w którym doświadczenie zdecydowanie odbiega od standardów, których oczekuje się od prezentującego! W końcu zejdę na serce od tego stresu :)

Do Poznania przyjechałem około 17:30 i wydawało się, że była to odpowiednia chwila. Jeśli jednak dodać do tego właśnie rozpoczynające się targi poznańskie (nie wiem, czy to były te targi, czy inne z puli wielu targów w Poznaniu), to niestety było to złe założenie. Kiedy taksówka zajechała przez dworzec, a później ślimaczym tempem dowlokła się pod drzwi pubu na Szyperskiej, było już dawno po rozpoczęciu Eclipse DemoCamp 2011 w Poznaniu.

Zastałem już tłoczną salę słuchaczami, którym Tomek Zarna przedstawiał karierę Eclipse. Nie miałem okazji wysłuchać jego prezentacji, bo nie tylko, że trochę głośno, że jedynie na przodzie można było usłyszeć, co ma do powiedzenia, ale też sama sytuacja spotkania z organizatorami: Natalią Klimasz i Łukaszem Stachowiakiem, a później Adamem Dudczakiem, aby jeszcze później trafić na Darka "egit" Łukszę i...patrz, że też musiałem zapomnieć imienia!...nie pozwalała na wsłuchiwanie się. Zresztą, kto by tam słuchał, kiedy można pogadać z dawno niewidzianymi znajomymi?! Trafiłem również w międzyczasie na Dawida Weissa, ale to było chyba już po jego prezentacji. Wszystkich gorąco pozdrawiam!

"Przebijanie" się przez wrzawę powodowało tylko dalsze jej nakręcanie, więc o rozmowie nie było co marzyć. Za głośno. Jednak próbowaliśmy, co później odbiło się na moim gardle. Do domu zajechałem w stanie, jakbym był po niezłej bibce.

Przysłuchiwałem się prezentacji Dawida, ale wciąż w zasadzie myślałem o moim przygotowaniu tematu i przyglądałem się reakcjom uczestników na to, co ma do powiedzenia. W sali znajdowały się dwa monitory, na których można było zobaczyć slajdy, ale tylko jeden miał obok prezentera, więc było nie lada wyzwaniem zdecydować się, gdzie patrzeć, aby widzieć, albo słyszeć (monitory były różnej rozdzielczości i ich ułożenie sprawiało, że miało to znaczenie). Miałem wrażenie, że atmosfera jest lekko akademicka, tzn. za bardzo nastawiona na odbiór, bez choćby chęci zadawania pytań, co sama atmosfera ogólnego zgiełku dodatkowo "sprzyjała".

Pizza time. Już wspólnie ze Szczecinianami. Spałaszowaliśmy kilka kawałków, aby dalej dywagować na tematy różne. Prezentacje sobie, a my sobie.

Wchodzę na scenę

Przyszła pora na moje wystąpienie. Sądziłem, że EDC to rodzaj spotkania, w którym dużo kodu jest wielce pożądane. Z drugiej strony zastanawiałem się, na ile skuteczny jest przekaz z otwartym IDE i kodowaniem na żywo. Tym razem postawiłem na to drugie. Miało być dużo IBM Rational Application Developer V8 z Java EE 6 na IBM WebSphere Application Server V8. I to był mój błąd. Właśnie przez te monitory i ogólną wrzawę. Kompletnie nie spodziewałem się takiego miejsca i atmosfery, w której ja miałbym prezentować Java EE 6 tworząc aplikacje na żywo. Chciałem dobrze. To wszystko ich wina :)

Najbardziej obawiałem się mojego przygotowania z JAX-RS (z zanurzonym Apache Wink w WAS V8), ale ostatecznie i tak nie pokazałem tego. Dzisiaj bardzo tego żałuję, bo mogło uzupełnić przekaz.

Zaczęły się problemy z mikrofonem - a to za głośno, a to za daleko i tym samym cicho, a ja potrzebowałem wolnych rąk do kodowania. W końcu się dopasowaliśmy - doszedłem do porozumienia z mikrofonem i zabrałem się za demo.

Zacząłem od prostej aplikacji webowej z servletem określonym przez @WebServlet. Zero deskryptora i tylko @WebServlet. Później urlPatterns i @WebFilter. Dalej przyszła pora na demonstrację @Stateless bez jawnego interfejsu biznesowego w ramach WAR. Dalej chwila z CDI i tak przeszliśmy z @EJB do @Inject (ciekawym, ile osób rozróżnia zastosowanie obu?) Dotarłem bodajże do @WebService wygenerowanym z POJO w projekcie javowym i na tym się zakończyła moja batalia o zademonstrowanie produktów IBM wspierających Java EE 6.

Nawet się nie obejrzałem i wnet było już po godzinie.

Losowanie

Na zakończenie organizatorzy przeprowadzili losowanie. Pamiętam, że losowano książki, bo podczas ich rozlosowywania zdążyłem tylko powiedzieć do Darka, że nigdy, ale to nigdy nie udało mi się czegokolwiek wygrać i chyba musiałem mówić to z takim przekonaniem, że kiedy skończyłem, padło "Jacek Laskowski".

Wygrałem książkę!

Cóż za radocha. Miałem do wyboru jedną i padło na "97 Things Every Programmer Should Know". To było doskonałe zakończenie mojego wystąpienia i całego spotkania mimo, że, jak się później okazało, nie był to wcale koniec.

Nocne dyskusje i powrót

Po zakończeniu prezentacji, siedzieliśmy jeszcze dłuższą chwilę. Rozmawialiśmy o różnych rzeczach, aż padło magiczne: "Wychodzimy na miasto". Trafiliśmy na rynek, gdzie przesiedzieliśmy do...4 nad ranem! (mam nadzieję, że nie naciągam, bo już sam nie jestem pewien do której siedzieliśmy). Szczecin odjechał. I ja również zasypiając nad ranem. To na prawdę bolało szczególnie, że zakończyło się moim przespaniem porannego pociągu do Warszawy. W końcu jednak dotarłem do niej i EDC przeszło do historii jako bardzo udane przedsięwzięcie. Upewniło mnie o potrzebie częstszego udziału w nich i coś mi mówi, że nie powinienem odstępować od publicznych wystąpień. Chyba zaczęły mi ponownie sprawiać niesamowitą przyjemność.


Dziękuję Natalii i Łukaszowi za zaproszenie. Możliwość wyłożenia mojej niewiedzy szerszej publiczności była bezcenna :) Czuję się zobowiązany!

05 grudnia 2011

j.u.concurrent.Phaser i wątek onAdvance w Java 7

9 komentarzy
Każdorazowo, kiedy przygotowywałem klasę wspomagającą rozpoznanie java.util.concurrent.Phaser jej uruchomienie wymagało dodania opcji -ea w konfiguracji uruchomieniowej w Eclipse. W ten sposób mogłem prezentować moje doświadczenia w postaci pojedynczej klasy z użyciem assert. To jednak wymagało ode mnie właściwej konfiguracji dla każdej uruchamianej klasy (!) Wystarczy jednak mała zmiana w konfiguracji JRE i po sprawie!


Podczas mojego ostatniego wystąpienia o zmianach w Java 7 w kontekście programowania współbieżnego, w którym przedstawiłem j.u.c.Phaser, padło pytanie o wątek, który uruchamia metodę protected boolean onAdvance(int phase, int registeredParties). Za pomocą tej metody kontrolujemy dostępność obiektu Phaser. Kiedy zwróci true, Phaser kończy swoje działanie. Dzięki niej, mamy również możliwość uruchomienia akcji podsumowującej fazę, kiedy ostatni wątek w danej fazie zgłosi swoje przybycie, a przed przejściem do kolejnej (jeśli takowa w ogóle nastąpi).

Podczas spotkania nie byłem w stanie odpowiedzieć na pytanie o wątek, w którym będzie uruchomiona metoda onAdvance(), co czynię teraz, w poniższej klasie.
package pl.japila.java7.concurrent.phaser;

import java.util.concurrent.Phaser;

public class PhaserOnAdvanceDemo {

    static class MyPhaser extends Phaser {
        String threadName;

        public void setOnAdvanceThreadName(String threadName) {
            this.threadName = threadName;
        }

        protected boolean onAdvance(int phase, int parties) {
            assert threadName.equals(Thread.currentThread().getName());
            return true;
        }
    }

    public static void main(String[] args) throws Exception {

        final MyPhaser phaser = new MyPhaser();

        assert 0 == phaser.getPhase();
        assert 0 == phaser.getRegisteredParties();
        assert 0 == phaser.getUnarrivedParties();

        final int parties = 2;

        phaser.bulkRegister(parties); // register 2 threads - main's and one more

        assert 0 == phaser.getPhase();
        assert parties == phaser.getRegisteredParties();
        assert parties == phaser.getUnarrivedParties();

        phaser.arrive(); // main thread arrives

        assert 0 == phaser.getPhase();
        assert parties == phaser.getRegisteredParties();
        assert 1 == phaser.getUnarrivedParties();

        Thread t = new Thread() {
            public void run() {
                phaser.arrive(); // this (sub)thread arrives
            }
        };
        phaser.setOnAdvanceThreadName(t.getName());
        t.start();

        t.join(); // wait till t dies

        assert phaser.isTerminated(); // onAdvance returned true, and hence phaser is terminated
        assert 0 > phaser.getPhase(); // phaser is terminated, and hence getPhase() returns negative number
        assert parties == phaser.getRegisteredParties();
        assert 0 == phaser.getUnarrivedParties();
    }

}
Zanim uruchomisz powyższą klasę, zastanów się, jaka może być odpowiedź. Zmiana kolejności uruchomienia phaser.arrive() ułatwia znalezienie odpowiedzi. Wystarczy przenieść linię 36 z phaser.arrive() dla głównego wątku, po t.join() w linii 50. Potrafisz wytłumaczyć dlaczego? Chętnie odpowiem na wyraźną prośbę (jej brak będzie oznaką znajomości odpowiedzi). Dla mnie to teraz taaaaakie oczywiste, ale trzeba było widzieć moją minę na prezentacji! :)

p.s. W nadchodzący piątek, 9 grudnia, występuję w roli prelegenta na konferencji Cracow.mobi z tematem RESTful Android. Będzie to moje pierwsze, androidowe wystąpienie, a 45 minut na prezentację uważam jedynie za możliwość nakreślenia tematu i jestem zmuszony do potraktowania go wyłącznie slajdami. Sugestie odnośnie sposobu i zawartości prezentacji tematu mile widziane.

02 grudnia 2011

O register() i bulkRegister(int) z j.u.concurrent.Phaser w Java 7

0 komentarzy
Przeglądając źródła j.u.concurrent.Phaser trafiłem na ciekawostkę, która z początku zaskoczyła mnie, ale kiedy się nad tym chwilę zastanowiłem, byłem nie mniej zdumiony swoim zdumieniem.

Phaser oferuje dwie metody do zarejestrowania uczestników faz - public int register() oraz public int bulkRegister(int parties).

Trudno zrozumieć, dlaczego dopiero przegląd kodu źródłowego Phaser uzmysłowiło mi, że pierwsza metoda - public int register() - jest specjalnym przypadkiem drugiej - public int bulkRegister(int parties), dla której parties = 1.

Mam wrażenie, że wynikało to z mojego błędnego zrozumienia działania tych metod, w którym sądziłem, że rejestracja jest w jakiś sposób związana z konkretnym wątkiem. Pamiętam, jak próbowałem przekazać to błędne rozumienie uczestnikom ostatniego spotkania Warszawa JUG i tylko ich czujność doprowadziła do mojego "Nie jestem pewien, jak to dokładnie działa", co w efekcie sprawiło, że zajrzałem do kodu źródłowego i teraz znam prawidłową odpowiedź (!)

A wystarczyło czytać javadoc dla Phaser ze zrozumieniem, w którym napisano:

"As is the case with most basic synchronization constructs, registration and deregistration affect only internal counts; they do not establish any further internal bookkeeping, so tasks cannot query whether they are registered. (However, you can introduce such bookkeeping by subclassing this class.)"

Proste? Teraz tak!

Poniższy przykład powinien pomóc zrozumieć problem bardziej. Od teraz już nie pomylę się i kolejna odsłona moich prezentacyjnych wyczynów wokół java.util.concurrent powinna nosić znamiona bardziej profesjonalnej :)
package pl.japila.java7.concurrent.phaser;

import java.util.concurrent.Phaser;

public class Phaser2Demo {

    public static void main(String[] args) throws Exception {
        final Phaser phaser = new Phaser();

        int parties = 3;
        for (int i = 0; i < parties; i++) {
            phaser.register();
        }

        assert 0 == phaser.getPhase();
        assert 3 == phaser.getRegisteredParties();
        assert 3 == phaser.getUnarrivedParties();

        Thread t;

        (t = new Thread() {
            public void run() {
                phaser.arrive(); // arrive and move on
            }
        }).start();

        t.join(); // awaits thread t's death

        assert 0 == phaser.getPhase();
        assert 3 == phaser.getRegisteredParties();
        assert 2 == phaser.getUnarrivedParties();

        (t = new Thread() {
            public void run() {
                phaser.arrive(); // arrive and move on
                phaser.arrive(); // arrive and move on
            }
        }).start();

        t.join(); // awaits thread t's death

        assert 1 == phaser.getPhase();
        assert 3 == phaser.getRegisteredParties();
        assert 3 == phaser.getUnarrivedParties();
    }

}
Coś niejasne? Wyjaśnić? Służę pomocą. Czym więcej pytań, tym więcej rozpoznania i tym lepsze moje zrozumienie tematu (oby i Twoje).

01 grudnia 2011

Zagadka z Rethrowing Exceptions with More Inclusive Type Checking w Java 7

7 komentarzy
Czytając bardzo krótki, acz treściwy wpis A New Java Exception Handling Idiom o nowej cesze Java 7 - Rethrowing Exceptions with More Inclusive Type Checking pomyślałem o pewnej zagadce, której próba rozwiązania wymusi choćby minimalne zrozumienie zmian wokół obsługi wyjątków w najnowszym wydaniu Javy 7. Takie perełki sprawiają, że określenie zmian jako niewielkich w tym wydaniu jest czymś, z czym mam kłopot, aby się zgodzić.

Zagadka:
package pl.japila.java7;

public class PreciseRethrowDemo {

    public static void main(String[] args) throws Exception {
        PreciseRethrowDemo demo = new PreciseRethrowDemo();
        demo.createFoo();
    }

    Foo createFoo() throws FooException {
        Bar bar = new Bar();
        try {
            return new Foo(bar);
        } catch (Throwable t) {
            t = new SubFooException();
            bar.cleanup();
            throw t;
        }
    }

    @SuppressWarnings("serial")
    static class FooException extends Exception {}
    @SuppressWarnings("serial")
    static class SubFooException extends FooException {}
    static class Foo {
        Foo(Bar bar) throws FooException {
            throw new FooException();
        };
    }
    static class Bar {
        void cleanup() {};
    }

}
Czy powyższe skompiluje się? Jeśli tak, jaki będzie rezultat? Odpowiedzi można umieszczać w komentarzach. Proszę o kolejne zagadki, jeśli spotkałeś/-aś się z podobnymi w obszarze obsługi wyjątków w Java 7.

p.s. Za kilka dni - 17 grudnia 2011 - kończy się możliwość podejścia do testowego egzaminu na Oracle Certified Associate, Java SE 7 Programmer. System wyliczył mi koszt na poziomie 61 USD i przy niekorzystnym kursie USD/PLN mimo wszystko planuję podejść do niego za 2 tygodnie. A Ty?