Home - rlip/java GitHub Wiki
- Skróty
- Komendy
- Biblioteki
- Cache
- Hibernate
- Kolekcje
- Wątki
- Moduły
- Wersje
- Szablony
- Projektowanie i dokumentowanie klas przeznaczonych do dziedziczenia
- Equals, Cloneable Comparable
- Ficzery
- Adotacje
- Typy zmiennych
- Zadanie
- FAQ * final * finally * finalize * Pola interfejsu * Autoboxing * Servlet * TDD * SPRING * Typy numeryczne * Uogólnienia (generyki, generic type) * Różnica między == a equals
ctrl + alt + l - formatowanie
Zmiana na raz:
alt + shift + mouseclick lub ctrl + ctrl + up/down lub przytrzymanie środkowego klawisza myszy
ctrl + alt + shift + j - zaznaczenie i edycja wszystkich wystąpień w aktualnym pliku
ctrl strzałka - przeskakiwanie całego wyrazu
alt + f1 - select in
ctrl + shit + z - powtórz
ctrl + shift + j - join - jedna linia
2x shift i builder w actions
ctrl + y - delete line
ctrl + f12 - struktura pliku
/////// Przeszukiwanie
ctrl + f - włączenie
enter (lub f3) - następne znalezione
shift + f3 - poprzednie znalezione
/////// Przejścia
ctrl + b (albo f4) - przejście do deklaracji klasy/interfejsu
ctrl - alt + b - przejście do implementacji klasy / interfejsu
/////// Błędy
F2 - następny błąd
ctrl + f1 - dokumentacja błędu
alt + enter - poprawa błędu
/////// Wydzielanie
ctrl + o - wybór metody klas wyższych do nadpisania
ctrl + alt + v - wydzielenie do zmiennej
ctrl + alt + m - wydzielenie do metody
ctrl + alt + c - wydzielenie stałej
ctrl + alf + f - wydzielenie do zmiennej
ctrl + alt + p - zmienna jako parametr
/////// Zmienianie
shift + f6 zmienia wszędzie w kodzie!
/////// Auto uzupełnianie
ctrl + shift + enter - dopełnia nawiasy np. w for czy if, też po wpisaniu warunku przenosi do wpisywania treści
ctrl + alt + t - dodawanie try/catch, if, etc...
/////// Podpowiedzi:
ctrl + space - wyświetlanie podpowiedzi, można też zmienić stałą - wybranie przez tab podmienia tekst, a nie dopisuje
ctrl + shift + space - wyświetlanie podpowiedzi - tylko odpowiednie dla danego kontekstu
2x (ctrl + shift + space) - podpowiedź przy return
ctrl + p - sygnatura metody
ctrl + q - dokumentacja metody
ctrl + shift + i - definicja w popup
/////// Zaznaczanie:
alt + j - zaznacza te same symbole
alt + shift + j - odznacza te same symbole
ctrl + alt + shift + j - zaznacza te same symbole w całym pliku
ctrl + shift + f7 - podświetla wszystkie użycia w aktualnym pliku
ctrl + w - zaznaczenie bloku - zwiększanie
shift + ctrl + w - zaznaczenie bloku - zmniejszenie
/////// Zwijanie:
ctrl + NumPad -/+ - zwiniecie/rozwinięcie aktualnego bloku
ctrl + shift + NumPad -/+ - zwiniecie/rozwinięcie wszystkich bloków
/////// Przenoszenie:
alt + shift + góra/dół - przenoszenie 1 linii
ctrl + shift + góra/dół - przenoszenie metody
ustawienie wersji: mvn versions:set -DnewVersion=x.y+1.0-SNAPSHOT
C:\apache-maven-3.6.0-bin\apache-maven-3.6.0\bin\mvn package spring-boot:repackage
-Djava.net.preferIPv4Stack=true
### Lombok
@Accessors(chain=true) // chain - setery zwracają this || fluent - getery i setery bez get i set || prefix - usuwa prefix
https://projectlombok.org/features/experimental/Accessors
Guava - duuużo rzeczy
Apache commons
Tak można zmienic path i poziom logowania
logging:
path: /var/logs/
file: TacoCloud.log
level:
root: WARN
org:
springframework:
security: DEBUG
https://www.baeldung.com/spring-cache-tutorial, trzeba wączyc potem
@Cacheable({"addresses", "directory"}) - jak jest coś w cachu to bierze z cacha, jak nie to dodaje
@CacheEvict(value="addresses", allEntries=true) - usuwa z cachu
@CachePut(value="addresses") - zawsze dodaje i uaktualnia
------------
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
------------
With the @CacheConfig annotation, you can streamline some of the cache configuration into a single place
– at the class level – so that you don't have to declare things multiple times:
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
można jeszcze użyć warunków: condition, unless
- Listy:
ArrayList<String>(); // tylko jeśli będziemy co najwyżej usuwać elementy z końca
LinkedList<String>();
- Sety - nie mogą mieć duplikatów
HashSet - szybki, ale bez kolejności
LinkedHashSet - zapamiętuje kolejność
TreeSet - w kolejności naturalnej (interfejs Comparable)
- Mapy - mapa 2 parametrów
HashMap- bez gwarancji kolejności
WeakHashMap - j.w. - z tym, że jak obiektowi dodanemu do mapy ustawimy wartość null to grabage collector może go usunąć
LinkedHashMap - zapamiętuje kolejność
TreeMap - kolejność naturalna
Callable, albo Runnable.
Executors.newFixedThreadPool() // ExecutorService mające 2 wątki
Executors.newScheduledThreadPool(2) // ScheduledExecutorService mające 2 wątki
executorService.schedule(worker1, 5, TimeUnit.SECONDS); //odpali się po 5 sekundach
executorService.scheduleAtFixedRate(worker3, 0, 6, TimeUnit.SECONDS); // będzie odpalał się co 6 sekund
executorService.submit(worker1);
executorService.shutdown();
Callable<Integer> answerToEverything = () -> { // może coś zwrócić
Future<Integer> result = executorService.submit(answerToEverything); // tak możemy przejąc to co zwraca -- taki javascriptowy promise
result.isDone() // czy już jest wynik
Integer integer = result.get(); // to zablokuje aplikację do momentu aż future będzie miało wartość
result.get(4, TimeUnit.SECONDS) // poczeka 4 sekundy, jak nie będzie wyniku to timeoutException
List<Future<Integer>> futures = executorService.invokeAll(callableList); // czeka na wszystkie wyniki i je zwraca
Integer integer = executorService.invokeAny(callableList); // zwraca 1 wynik uzyskany wynik
cfuture1.thenCombine(cfuture2, new BiFunction<Long, Long, Object>() { // przyjmuje 2 cfuture, wywołuje je i zwraca wynik
synchronized public void increase() // dostęp do tej funkcji ma tylko 1 wątek na raz, można też tak jako blok w jakieś fukcji synchronized { ...
i można też użyć zmiennych atomic
volatile - nie zapewnia wzajemnego wykluczenia, ale gwarantuje, że każdy wątek odczytujący to pole będzie "widział" ostatnio zapisaną wartość
Metody, zawierające zmienne dostępne do wielu wątków trzeba albo synchronizować (zapis i odczyt):
public class StopThread {
private sytatic boolean stopRequested;
private static synchroznized void requestStop() {
stopRequest = true;
}
private static synchronized boolean stopRequested(){
return stopRequested;
}
}
/////////////// tak można używać java.util.concurre.atomic
private static final AtomicLong nextSerialNum = new AtomicLong();
public static long generateSerialNumber() {
return nextSerialNum.getAndInclement();
}
Tworzymy pliki module-info.java w katalogu java. To co nie wyexportujemy jest prywatne. Eksport głównego pakietu nie eksportuje podrzędnych pakietów, ale Eksport podrzednych eksportuje też główny pakiet. (Może też trzeba dać nadrzędny) Można też dać require lombok, czy sprigframework
Może będzie potrzebny Maven 2 integration plugin. Przy migracji można użyć programu z bin - jdebs, który wypisze zależne moduły W każdym module w src trzeba utworzyć module-info.java:
module pl.clockworkjava.MainModule {
requires java.logging; // co używany
requires pl.clockworkjava.AccountingModule; // jakieś inne nasze moduły
requires pl.clockworkjava.SupplyModule;
}
module pl.clockworkjava.AccountingModule {
requires java.logging;
exports pl.clockworkjava.accounting; // to trzeba napisać, żeby wystawić na zewnątrz publiczne metody klas, osobno dla każdej package
// zawsze trzeba dodawać pełną paczkę (nie wystarczy rodzic)
}
Jeśli używamy serwisu z innego modułu
module pl.clockworkjava.AccountingModule {
requires pl.clockworkjava.PayrollService; // tu jest sam interfejs serwisu
requires pl.clockworkjava.PolishPayroll; // tu jedna z implementacji
exports pl.clockworkjava.accounting; // to że jest paczka accounting tego modułu jest widoczna na zewnątrz accounting
uses pl.clockworkjava.payroll.PayrollService; // to że używa tego serwisu
}
Potem tak w kodzie mozna dostać się do niego dostać:
ServiceLoader<PayrollService> services = ServiceLoader.load(PayrollService.class);
services.findFirst().ifPresent(PayrollService::getCurrency);
// a to implementacja takiego serwisu:
module pl.clockworkjava.PolishPayroll {
requires pl.clockworkjava.PayrollService;
provides pl.clockworkjava.payroll.PayrollService with pl.clockworkjava.polishpayroll.PayrollServiceImpl;
//ten moduł dostarcza implementacji do tego serwisu
}
Można tez lepiej, czyli w interfejsie serwisu dodajemy statyczną metodę
static PayrollService getInstance(){
ServiceLoader<PayrollService> services = ServiceLoader.load(PayrollService.class);
Optional<PayrollService> first = services.findFirst();
return first.orElseThrow(() -> new RuntimeException("Missing PayrollService implementation"));
}
I w module-info oznaczamy że sam siebie używa
uses pl.clockworkjava.payroll.PayrollService;
Java SE 12 = 56 (0x38 hex)
Java SE 11 = 55 (0x37 hex)
Java SE 10 = 54
Java SE 9 = 53
Java SE 8 = 52
Java SE 7 = 51
Java SE 6.0 = 50
Java SE 5.0 = 49
JDK 1.4 = 48
JDK 1.3 = 47
JDK 1.2 = 46
JDK 1.1 = 45
uwagi | ||
---|---|---|
FreeMarker | spring-boot-starter-freemarker | |
Groovy Templates | spring-boot-starter-groovy-templates | |
JavaServer Pages (JSP) | Brak (dostarczana przez Tomcat lub Jetty) | uwaga - nie można użyć z jar |
Mustache | spring-boot-starter-mustache | |
Thymeleaf | spring-boot-starter-thymeleaf |
Normalnie trzeba wyłączyc cache szablonów, chyba że używamy DevTools - wtedy to robi to za nas
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<p th:text="${message}">Miejsce zarezerwowane dla wiadomości.</p>
<div th:each="ingredient : ${wrap}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}" />
<span th:text="${ingredient.name}">SKŁADNIK</span><br/>
</div>
Konstruktory nie mogą wywoływać metod, które można przesłaniać, bo konstruktor klasy nadrzędnej jest wywoływany przed konstruktorem podklasy. Bezpieczne jest wywoływanie metod prywatnych, metod oznaczonych jako final i metod statycznych z poziomu konstruktora, bo żadnej z nich nie można przesłonić. Podobnie metody clone i readObject jak implementujemy Cloneable i Serializable. Na koniec, jeżeli decydujesz się implementować interfejs Serializable w klasie podlegającej dziedziczeniu, a klasa posiada metodę readResolve lub writeReplace, musisz zadeklarować metody readResolve lub writeReplace jako zabezpieczone, a nie jako prywatne. Jeżeli metody te będą prywatne, zostaną bez żadnego ostrzeżenia zignorowane w klasach pochodnych.
Używa się w obiektach do porównywania wartośći
x.equals(x) musi zwracać true, x.equals(null) musi zwracać false, jak x.equals(y) to y.equals(x) jak x.equals(y) i y.equals(z) to x.equals(z) Trzeba uważać z dziedziczeniem. Zamiast tego można stosować kompozycję - czyli w klasie zapisać obiekt, który miałby być dziedziczony. Czyli porównać czy jest ten sam obiekt (Float.compare(float, float) dla float, Double.compare(double, double), == dla pozostałych prostych, equals dla obiektów
Funkcja, która zwraca int. Dobrze żeby był możliwie unikalny i na postawie wartości. Musi być taka zasada, że jeśli X.equals(Y) == true, to X.hashCode() == Y.hashCode(), ale jeśli mają te same hash code to nie muszą być equals = true, ale jest to zalecane. HashCode musi być stały. Używa się go w kolekcjach, np. przy sprawdzeniu czy dany element jest w zbiorze.
Jak już jakaś klasa go implementuje to trzeba pamiętać, żeby wywołać super.clone na parencie i skopiować wszystkie jej pola (uważać na referencje). Ale lepiej udostępnić konstruktor kopiujący lub fabrykę kopiującą. Tablice można kopiować przez clone.
Implementować, jeśli obiekty klasy mają jakiś naturalny porządek
private static final Comparator<PhoneNumber> COMPARATOR =
comparingInt((PhoneNumber pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.prefix)
.thenComparingInt(pn -> pn.lineNum);
public int compareTo(PhoneNumber pn) {
return COMPARATOR.compare(this, pn);
}
- można importować statycznie, a potem używać np. stałych statycznych bez nazwy klasy: import static com.effectivejava.science.PhysicalConstants.*;
- można używać podkreślnika w długich liczbach, dla lepszej widoczności
@SuppressWarnings("unchecked") - bez ostrzeżenia rzutowania @SafeVarargs - stosować jeśli używamy zmienną liczbę parametrów, ale musi ona być bezpieczna. Lepiej zrobić tak:
static <T> List<T> flatten(List<List<? extends T>> lists) {
List<T> result = new ArrayList<>();
for (List<? extends T> list : lists)
result.addAll(list);
return result;
-----
audience = flatten(List.of(friends, romans, countrymen));
- Nie używać typów surowych np. List, zawsze lepiej zparametryzowane List, żeby była kontrola co wchodzi do listy.
Tablice są kowiarancyjne: Jeśli Sub jest typem podrzędnym względem Super, to tablica typu Sub[] jest typem podrzędnym względem Super[]
Typy ogólne z kolei są niezmiennicze — dla dwóch różnych typów Typ1 i Typ2, List<Typ1> nie jest ani typem podrzędnym, ani nadrzędnym dla List<Typ2>.
Dodatkowo Typy ogólne są zacierane - po kompilacji nie ma już informacji o type z nawiasów
Lista parametrów typu, która deklaruje typ parametru, znajduje się pomiędzy modyfikatorami metody a zwracanym typem. W tym przykładzie listą parametrów typu jest <E>, a zwracanym typem jest Set<E>. Konwencja nazewnictwa dla parametrów typu jest dla metod ogólnych taka sama jak dla typów ogólnych (tematy 29. i 68.):
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}
Jeżeli typ parametryzowany reprezentuje producenta T, to należy użyć <? extends T>; jeżeli T jest konsumentem, należy użyć <? super T>. W naszym przykładzie klasy Stack, parametr src metody pushAll produkuje obiekty E do wykorzystania przez Stack, więc odpowiednim typem dla src jest Iterable<? extends E>; parametr dst metody popAll konsumuje obiekty E z Stack, więc odpowiednim typem dla dst jest Collection<? super E>.
-----------------------------
public class Stack<E> {
private E[] elements;
// Szablon typu dla parametru służącego jako producent E
public void pushAll(Iterable<? extends E> src) { //<? extends E> - tu wymaga dowolny podtyp E jak i sam typ E
for (E e : src)
push(e);
}
// Typ szablonowy dla parametru służącego jako konsument E
public void popAll(Collection<? super E> dst) { // tu wymagana jest kolekcja typu bazowego do E, gdzie typ bazowy jest
//tak zdefiniowany, że E jest typem bazowym dla samego siebie
while (!isEmpty())
dst.add(pop());
}
}
można robić mapy o dowolnym type
public static void main(String[] args) {
Favorites f = new Favorites();
f.putFavorite(String.class, "Java");
f.putFavorite(Integer.class, 0xcafebabe);
f.putFavorite(Class.class, Favorites.class);
String favoriteString = f.getFavorite(String.class);
int favoriteInteger = f.getFavorite(Integer.class);
Class<?> favoriteClass = f.getFavorite(Class.class);
System.out.printf("%s %x %s%n", favoriteString,
favoriteInteger, favoriteClass.getName());
}
------------
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<>();
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(Objects.requireNonNull(type), instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("Podaj 3 słowa:");
List<String> words = new ArrayList<>();
words.add(reader.readLine());
words.add(reader.readLine());
words.add(reader.readLine());
System.out.println(words);
words.sort(Comparator.comparing(String::toString));
System.out.println(words);
words.stream().sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
words.sort(Comparator.comparing(String::length).reversed());
System.out.println(words);
final to modyfikator, którego możemy użyć przy polach, metodach lub klasach. W zależności od tego, gdzie zostanie zastosowany, oznacza on odpowiednio, że do danego pola nie można przypisać innego obiektu w przyszłości, danej metody nie można przysłonić poprzez dziedziczenie lub danej klasy nie można rozszerzyć. Można tez jako argument funkcji - wtedy nie można go zmienić.
finally to elementy bloku try-catch-finally, w którym możemy umieścić kod, który wykona się niezależnie od powodzenia operacji wewnątrz try — jest to dobre miejsce, aby pozamykać otwarte zasoby i ‘wyczyścić’ pamięć.
finalize() to metoda klasy Object, która jest wywoływana dokładnie raz, zanim obiekt zostanie usunięty z pamięci przez garbage collector (może się jednak zdarzyć, że nie zostanie ona wywołana, ponieważ obiekt nie jest usuwany); ogólnie nie jest najlepszą praktyką polegać na tej metodzie, lepszym rozwiązaniem jest samodzielne zarządzanie cyklem życia obiektu
Pola interfejsu są jednocześnie publiczne, statyczne i finalne — trzeba im przypisać wartości już w momencie ich deklaracji. Deklaracja pola interfejsu nie różni się od deklaracji pola klasy. Zgodnie z konwencją przyjmuje się, że nazwy takich pól pisze się wielkimi literami, a poszczególne człony nazwy oddziela się znakiem podkreślenia
Autoboxing to mechanizm języka Java, który pozwala na automatyczną konwersję pomiędzy prymitywami a obiektami odpowiadających typów.
Servlet to specjalny obiekt, który implementuje interfejs javax.servlet.Servlet — jego zadaniem jest obsługa zapytań HTTP i generowanie odpowiedzi na nie. Wiele frameworków dostarcza już gotową implementację — np. DispatcherServlet w przypadku Spring MVC.
TDD - pisanie oprogramowania stymulowane przez testy.
Jak działa Spring (a dokładniej jego kontener IoC)?
W momencie uruchomienia aplikacji Spring tworzy tzw. kontekst. W uproszczeniu można powiedzieć, że jest to kolekcja beanów i związanych z nią konfiguracji. Wewnątrz takiego kontekstu beany ‘widzą się’, ale nie widzą obiektów poza nim.
Początkowo znajdują się tam tylko springowe obiekty — w tym sam kontekst. W zależności od konfiguracji w pierwszym kroku inicjowane są kolejne beany — czyli po prostu tworzone są nowe obiekty i rejestrowane w kontekście (można o nim myśleć także jak o swoistej mapie — kontekst bowiem mapuje nazwy (id) na właściwe obiekty). Ten etap realizuje implementacja interfejsu BeanFactory, która często jest samym kontekstem (np. ClasspathXmlApplicationContext).
Po zakończeniu tego kroku do ‘pracy’ wkraczają implementacje BeanPostProcessor — są one odpowiedzialne za ‘automagię’ springa, czyli np nadawanie wartości polom z adnotacją @Autowired (za to odpowiedzialny jest akurat AutowiredAnnotationBeanPostProcessor). Jest to także sposób, w jaki możemy modyfikować domyślne zachowanie Springa wg własnych potrzeb. W międzyczasie, po wykonaniu pracy przez wszystkie znane kontekstowi implementacje tego interfejsu, wywoływana jest metoda init() beanów (jeśli istnieje), po czym obiekty te mogą wykonać dodatkowe zadania (większość tego nie robi).
W tym momencie inicjowanie jest uznane za zakończone, a aplikacja za uruchomioną.
Jakie typy numeryczne są dostępne w Javie i do jakich zastosowań je używamy?
W Javie mamy dostępnych kilka typów numerycznych — w tym prymitywy oraz obiekty. Ponieważ prymitywy posiadają odpowiedniki w obiektach, omówimy tylko te drugie.
Podstawowym interfejsem, które implementują wszystkie typy numeryczne jest java.lang.Number — zawiera on metody pozwalające pobierać wartość jako prymityw int, byte, short itp. Dokładniej o typach liczbowych przeczytacie w tym tygodniu w kolejnym wpisie z cyklu Niezbędnik Juniora, a póki co ograniczymy się do wypisania dostępnych opcji. Do liczb całkowitych możemy użyć Byte, Short, Character, Integer, Long oraz BigInteger, z kolei do reprezentacji liczb zmiennoprzecinkowych służą klasy Float, Double oraz BigDecimal.
Można uogólniać klasę - zwyczajowo dodaje się literki od T dalej. Można też uogólniać metody
public class Opakowanie<T, v>{
public T val1;
public T val1;
}
------------------
public static<U> void show(U val){
System.out.println(val.toString());
}
taki przykład klasy zwracającej losowy element z przekazanej tablicy
public class Chooser<T> {
private final List<T> choiceList;
public Chooser(Collection<T> choices) {
choiceList = new ArrayList<>(choices);
}
public T choose() {
Random rnd = ThreadLocalRandom.current();
return choiceList.get(rnd.nextInt(choiceList.size()));
}
}
List> is somewhat analogous to List extends Object>. So the difference between List and List> is like the difference between List and List<? extends Number>
Operator == sprawdza tylko czy są to dokładnie te same obiekty, a to nie jest prawda. Stąd metoda equals — jako mechanizm w Javie do porównania, czy obiekty ‘znaczą to samo’ bardziej niż ‘są tym samym obiektem’.
+-----------+
| Throwable |
+-----------+
/ \
/ \
+-------+ +-----------+
| Error | | Exception |
+-------+ +-----------+
/ | \ / | \
\________/ \______/ \
+------------------+
unchecked checked | RuntimeException |
+------------------+
/ | | \
\_________________/
unchecked
Ma w swojej hierarchii dziedziczenia ma Exception i nie ma RuntimeException. Musi zostać obzłużony, bo inaczej będzie błąd kompilacji. Stosuje się, jeśli może zostać naprawiony.
Dziedziczy po Error albo RuntimeException. Nie musi zostać obsłużony, ale wywyali program
deployment - z wrganiem na serwer, deliwery - tylko dostarczenie, wgranie na przycisk