Na forum 4programmers.net korzystamy z plików cookies. Część z nich jest niezbędna do funkcjonowania
naszego forum, natomiast wykorzystanie pozostałych zależy od Twojej dobrowolnej zgody, którą możesz
wyrazić poniżej. Klikając „Zaakceptuj Wszystkie” zgadzasz się na wykorzystywanie przez nas plików cookies
analitycznych oraz reklamowych, jeżeli nie chcesz udzielić nam swojej zgody kliknij „Tylko niezbędne”.
Możesz także wyrazić swoją zgodę odrębnie dla plików cookies analitycznych lub reklamowych. W tym celu
ustaw odpowiednio pola wyboru i kliknij „Zaakceptuj Zaznaczone”. Więcej informacji o technologii cookie
znajduje się w naszej polityce prywatności.
szukam fajnych rzeczy z Javy, które w pierwszej chwili nie wydają się intuicyjne. Core Java, bez bibliotek. W ramach quizu z ciekawostkami, a nie na potrzeby rekrutacji ;)
Przykład takiego pytania daję poniżej. Może macie jakieś zachowanie, które w pierwszej chwili Was zaskoczyło? Np. z testu OCP - tam jest chyba sporo smaczków?
Kopiuj
Will it compile?
switch(3) {
case 3:
String x = "abc";
System.out.println(x);
break;
default: {
String x = "bcd";
System.out.println(x);
break;
}
}
Poziom oczywiście subiektywny, szukam inspiracji :)
Co się wypisze na ekranie? :) W końcu synchronizacja na lokalnej zmiennej powinna w ogóle nie mieć wpływu na nic? ;)
I analogiczny kod ale jeśli zmienimy Boolean x = true; na Boolean x = new Boolean(true); (które to IntelliJ oznacza jako WTF i sugeruje zamienić z powrotem)
edit: i druga ciekawostka z życia wzięta:
Kopiuj
packagedeadlocks;importjava.util.List;importjava.util.concurrent.CompletableFuture;importjava.util.stream.Collectors;importjava.util.stream.IntStream;publicclassDeadlock2{publicstaticvoidmain(String[] args){List<Integer> values =IntStream.range(0,100).boxed().collect(Collectors.toList());List<Integer> results = values.parallelStream()// paralell czyli szybciej? ;).map(Deadlock2::process).collect(Collectors.toList());System.out.println(results);}privatestaticIntegerprocess(int x){System.out.println(Thread.currentThread()+" Entered "+ x);CompletableFuture<Integer> async =CompletableFuture.supplyAsync(()->slowFunction(x));// puszczamy w tle, a my cośtam dalej możemy sobie robić bo kiedyś nam sie to policzy...while(!async.isDone()){try{Thread.sleep(1);}catch(InterruptedException e){
e.printStackTrace();}}return async.join();}privatestaticintslowFunction(int x){return x +1;}}
Jak zadziała ten kod i czemu? I co się stanie jak zamienimy parallelStream na stream. W końcu paralell to powinien zadziałać szybciej, prawda? ;)
edytowany 4x, ostatnio: Shalom
Zobacz pozostałe 3 komentarze
Shalom
Tak właśnie jest. A jestem sobie w stanie wyobrazić kod gdzie ktoś synchronizuje się na booleanie, potencjalnie blokując jakiś zupełnie inny wątek w aplikacji albo robiąc deadlock.
W pierwszym przy Boolean x = true mamy w bytcode INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean które zwraca jeden z dwóch obiektów z cache :) Jeśli tworzymy nowy obiekt to mamy rzeczywiście nową instancję INVOKESPECIAL java/lang/Boolean.<init> (Z)V.
Jeszcze lepszym WTF byłoby Integer x = 100; vs Integer x = 1000; :)
Shalom
@damianem: to też kiedyś debugowalem bo ktoś użył == i kod działał ale tylko dla małych wartości. Ale to łatwo zauważyć bo == to bardzo niecodzienny widok. Z tym boolem i z paralellsreamem już tak łatwo nie jest...
@Shalom: No w drugim przykładzie ForkJoinPool sam siebie wysyca ale to już nie jest takie oczywiste - trzeba pamiętać że defaultowo parallelStream i CompletableFuture go używają. Dziwię się twórcom języka że w ogóle ten thread pool wprowadzili, bo to trochę proszenie się o kłopoty :)
w c czy c++ jest chyba bardziej powszechny WTFowy problem. jak robiłem wywołanie method(readInt(), readInt(), readInt()) to mi wczytywało odwrotnie niż chciałem. po pewnym czasie znalazłem przyczynę - gcc oblicza parametry od końca, a clang od początku. w standardach c i c++ nie ma wymuszonej kolejności obliczania argumentów.
uprościłem trochę przykład, na potrzeby zmieszczenia w komentarzu :) ten kod wypisuje true (bo zadziałało przeciążanie): public class Main { public static void main(String[] args) { class Person { boolean equals(Person p) { return true; } } Person p1 = new Person(), p2 = new Person(); System.out.println(p1.equals(p2)); } }
ale jak zmienimy typ referencji z Person na Object to już wypisuje false
To jeszcze takie gówienko, można się naciąć w praktyce.
Kopiuj
class A {
public static final int X = B.Y + 1;
}
class B {
public static final int Y = A.X + 1;
}
public class C {
public static void main(String []args){
System.out.println("X = "+A.X+", Y = "+B.Y);
}
}
@Charles_Ray: @jarekr000000 i teraz mam przez Was zagwozdke: czy w Javie kolejnosc deklaracji pol albo class moze wplynac na wydajnosc apki czy nie. W C++ potrafi, za to Java robi rozne dziwne optymalizacje...
Dodanie „final” może mieć wpływ - kwestie dotyczące memory model i jakie sztuczki jest w stanie wykonać JIT. To już jednak trochę chore ;) https://www.baeldung.com/java-final-performance . Odnośnie kolejności to w sumie nie wiem czy ona jest zachowywana
czy w Javie kolejnosc deklaracji pol albo class moze wplynac na wydajnosc apki czy nie? - kolejność deklaracji pól może, ale jest to niejako poza specyfikacją - zależy jak dana maszyna (implementacja) je układa w fizycznej pamięci i co z tego wyniknie. Kolejność deklaracji klas raczej nie może (!!!), bo nie ma czegoś takiego jak kolejność klas na poziomie JVM - każda klasa to osobny "plik" (bajtocode).
Fedaykin
Hmm, X = 2 i Y = 1? Kolejność ładowania klas i default pól, czy cos czego nie rozumiem?
Stara książka Java Puzzlers jest pełna tego typu zagadek i.... jest strasznie nudna po pierwszych 5 stronach!
Większość z tych cudów zostanie wyłapana i zatrzymana na etapie statycznej analizy kodu.
Dla tych co chcą zrozumieć dlaczego tak a nie inaczej, cmd line'owy util: javap daje odpowiedź - wystarczy zrzucić wygenerowany bytecode i przeanalizować co wypluł kompilator. Na poziomie bytecodu kolejność operacji (nie wielowatkowych) jest dobrze zdefiniowana.
.andy