Tenzan Academy
Motyw
  • 8 sekcji
  • 24 pytania
  • 20 fiszek

Java

Semantyka Javy 21 LTS: wyjątki, kontrakt equals/hashCode, rekordy, sealed classes, generyki, Stream API i wątki wirtualne.

Java

Semantyka Javy 21 LTS: wyjątki, kontrakt equals/hashCode, rekordy, sealed classes, generyki, Stream API i wątki wirtualne.

Quiz

Wyjątki: checked vs unchecked i try-with-resources

na egzaminie

Throwable dzieli się na Error (błędy poziomu JVM, nie do przechwytywania w normalnym kodzie) i Exception. Exception dzieli się dalej: podklasy RuntimeException to wyjątki niekontrolowane (unchecked), reszta to wyjątki kontrolowane (checked), wymuszane przez kompilator.

Hierarchia

Throwable → Error | Exception. Exception → RuntimeException (unchecked) | pozostałe klasy (checked, np. IOException, SQLException).

Termin kluczowy

Checked exception: Wyjątek niebędący podklasą RuntimeException; kompilator wymaga jego obsłużenia (catch) lub zadeklarowania (throws) w sygnaturze metody.

Termin kluczowy

Unchecked exception: Podklasa RuntimeException (lub Error); kompilator nie wymaga catch ani throws, np. NullPointerException, IllegalArgumentException, IllegalStateException.

Checked wymusza throws, unchecked nie java
// Checked: wywołujący MUSI obsłużyć lub zadeklarować
void readConfig(String path) throws IOException {
    Files.readString(Path.of(path));
}

// Unchecked: wywołujący MOŻE obsłużyć, kompilator nie wymusza
int divide(int a, int b) {
    if (b == 0) throw new IllegalArgumentException("Divisor cannot be zero");
    return a / b;
}
Pułapka

Łapanie wyjątku i ignorowanie go pustym catch(Exception e) {} ukrywa błąd i utrudnia debugowanie: loguj albo propaguj dalej, nigdy nie połykaj w ciszy.

  • Unchecked dla błędów programistycznych (złe argumenty, zły stan): klient i tak nie mógł się przed nimi zabezpieczyć w runtime.
  • Checked tylko gdy wywołujący realnie może i powinien się odzyskać (np. brak pliku, retry po timeout sieciowym).
  • Nadużywanie checked exceptions w warstwie domenowej prowadzi do zaśmieconych sygnatur i przechwytywania na wszelki wypadek.
Zasób AutoCloseable zamykany automatycznie java
static void readFirstLine(Path path) throws IOException {
    try (BufferedReader reader = Files.newBufferedReader(path)) {
        System.out.println(reader.readLine());
    }
}
Kolejność zamykania

Przy wielu zasobach w jednym try(...) zamykane są w kolejności odwrotnej do deklaracji: ostatni zadeklarowany zamyka się pierwszy.

Suppressed exceptions

Jeśli wyjątek wystąpi zarówno w bloku try, jak i w close(), wyjątek z try jest wyjątkiem głównym. Wyjątek z close() trafia do niego jako suppressed (Throwable.getSuppressed()).

Mnemonik

Checked to kompilator pilnujący jak nauczyciel; unchecked to błąd programisty, którego kompilator nie wyłapie za ciebie.

Dalej: 02 equals(), hashCode() i pułapki autoboxingu

equals(), hashCode() i pułapki autoboxingu

na egzaminie

Object.equals() domyślnie porównuje referencje (==), a Object.hashCode() zwraca wartość zależną od JVM (zwykle powiązaną z adresem w pamięci). Nadpisanie jednej metody bez drugiej to najczęstszy sposób na złamanie kolekcji haszujących.

  • Zwrotność: x.equals(x) zawsze true
  • Symetria: x.equals(y) wtedy i tylko wtedy, gdy y.equals(x)
  • Przechodniość: x.equals(y) i y.equals(z) implikuje x.equals(z)
  • Spójność: powtarzane wywołania dają ten sam wynik, jeśli pola się nie zmieniły
  • x.equals(null) zawsze zwraca false
Kontrakt hashCode()

Obiekty równe wg equals() MUSZĄ mieć ten sam hashCode(). Obiekty nierówne MOGĄ mieć ten sam hashCode() (kolizja dozwolona, ale pogarsza wydajność HashMap).

Poprawna para equals/hashCode z Objects.hash java
final class Point {
    private final int x, y;

    Point(int x, int y) { this.x = x; this.y = y; }

    @Override
    public boolean equals(Object o) {
        return o instanceof Point p && x == p.x && y == p.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}
Pułapka

Nadpisanie equals() bez hashCode() sprawia, że obiekt znika z HashSet/HashMap: dwa logicznie równe obiekty trafiają do różnych kubełków, bo mają różny hashCode().

Termin kluczowy

Autoboxing: Automatyczna konwersja typu prymitywnego na jego wrapper (np. int na Integer) i odwrotnie (unboxing), wykonywana niejawnie przez kompilator.

Cache Integer

Integer.valueOf(int) cache'uje instancje dla wartości od -128 do 127 (JLS 5.1.7); autoboxing w tym zakresie zwraca tę samą instancję, poza nim tworzy nowy obiekt.

Pułapka == na typach opakowujących java
Integer a = 127, b = 127;
System.out.println(a == b); // true, cache -128..127

Integer c = 128, d = 128;
System.out.println(c == d); // false, poza cache, różne obiekty

System.out.println(c.equals(d)); // true, poprawne porównanie wartości
Pułapka

Kod testowany na małych liczbach (np. w pętli 0..10) może działać z ==, bo trafia w cache. W produkcji, na większych wartościach, ten sam kod daje ciche, losowe błędy logiczne.

Fakt na test

Zawsze .equals() do porównania wartości, == tylko do celowego porównania referencji.

NullPointerException przy unboxingu

Integer x = null; int y = x; rzuca NullPointerException w momencie unboxingu, nie w momencie przypisania null.

Mnemonik

equals mówi CO jest równe, hashCode mówi GDZIE tego szukać w tablicy haszującej: muszą się zgadzać.

Dalej: 03 String: niezmienność i string pool

String: niezmienność i string pool

na egzaminie

String w Javie jest niezmienny (immutable): raz utworzonego obiektu String nie da się zmodyfikować. Każda operacja pozornie modyfikująca (np. concat, replace, toUpperCase) zwraca nowy obiekt.

  • Bezpieczeństwo wątkowe bez synchronizacji: niezmienny obiekt można bezpiecznie współdzielić między wątkami
  • Bezpieczne cache'owanie hashCode() (pole prywatne liczone raz, potem zwracane bez przeliczania)
  • Bezpieczeństwo w classloaderach, ścieżkach plików, połączeniach sieciowych: wartość nie może się zmienić pod spodem po walidacji
  • Współdzielenie literałów w string pool bez ryzyka, że jeden fragment kodu zmodyfikuje string używany gdzie indziej
Termin kluczowy

String pool: Pula literałów String w pamięci JVM (część sterty od Javy 7), w której kompilator automatycznie interniuje literały. Identyczne literały wskazują na ten sam obiekt.

Literały dzielą jedną instancję z puli, new String() nie java
String a = "Tenzan";
String b = "Tenzan";
System.out.println(a == b); // true, ten sam obiekt z string pool

String c = new String("Tenzan");
System.out.println(a == c);          // false, nowy obiekt na stercie
System.out.println(a == c.intern()); // true, intern() zwraca referencję z puli
Pułapka

String c = new String("Tenzan") celowo omija pulę i tworzy nowy obiekt na stercie; porównywanie go przez == z literałem da false, mimo identycznej wartości. To najczęstsza pułapka na rozmowach rekrutacyjnych.

intern()

String.intern() zwraca referencję z puli dla danej wartości, dodając ją do puli, jeśli jeszcze tam nie ma. Po intern() porównanie == z literałem o tej samej treści zwraca true.

Pułapka

Konkatenacja stringów operatorem + wewnątrz pętli tworzy nowy obiekt String przy każdej iteracji (bo String jest niezmienny). Kompilator optymalizuje pojedyncze wyrażenie +, ale nie serię dołączeń w pętli.

StringBuilder zamiast + w pętli: jeden mutowalny bufor java
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i).append(',');
}
String result = sb.toString();
Compact Strings (Java 9+)

Od Javy 9 (JEP 254) String przechowuje dane w byte[] z kodowaniem Latin-1, gdy to możliwe, zamiast char[] UTF-16. Oszczędza to zwykle około połowę pamięci dla typowych tekstów ASCII/Latin.

Mnemonik

String się nie zmienia, tylko referencja wskazuje gdzie indziej: +, replace, substring zawsze zwracają nowy obiekt.

Dalej: 04 Rekordy (records): nowoczesny nośnik danych

Rekordy (records): nowoczesny nośnik danych

na egzaminie

Rekord (Java 16+, JEP 395) to zwięzła, niezmienna klasa danych. Jedna deklaracja generuje konstruktor kanoniczny, prywatne pola final, publiczne akcesory, equals(), hashCode() i toString(), eliminując boilerplate ręcznie pisanych DTO.

Jedna linijka zamiast klasy z gettersami, equals, hashCode, toString java
public record Employee(String name, String email, double salary) {}

Employee e = new Employee("Anna Kowalska", "anna@firma.pl", 9500.0);
System.out.println(e.name()); // "Anna Kowalska", brak prefiksu "get"
System.out.println(e);        // Employee[name=Anna Kowalska, email=anna@firma.pl, salary=9500.0]
Co generuje kompilator

Konstruktor kanoniczny (parametry = komponenty rekordu). Prywatne pola final o tych samych nazwach. Publiczne metody akcesorów o nazwie pola bez prefiksu get (np. name(), nie getName()). Metody equals()/hashCode() porównujące wszystkie komponenty. Metoda toString() w formacie NazwaRekordu[pole=wartość, ...].

Termin kluczowy

Compact constructor: Konstruktor bez jawnej listy parametrów (używa niejawnie parametrów o nazwach komponentów), pozwala walidować lub normalizować dane wejściowe przed niejawnym przypisaniem do pól.

Walidacja bez powtarzania listy parametrów java
public record Range(int min, int max) {
    public Range {
        if (min > max) {
            throw new IllegalArgumentException("min > max");
        }
        // brak this.min = min: przypisanie pól jest niejawne
    }
}
Pułapka

W konstruktorze kompaktowym nie wolno pisać this.min = min; jawnie: przypisanie do pól jest niejawne i następuje automatycznie po jego zakończeniu. Wolno tylko modyfikować same parametry (np. min = Math.abs(min);).

  • Rekord jest niejawnie final: nie można go rozszerzyć
  • Rekord nie może extends innej klasy (niejawnie dziedziczy po java.lang.Record), ale może implements dowolną liczbę interfejsów
  • Nie można deklarować dodatkowych pól instancyjnych poza komponentami rekordu (statyczne pola/metody są dozwolone)
  • Można nadpisać wygenerowane equals()/hashCode()/toString() lub dodać własne metody i konstruktory pomocnicze
Pułapka

Rekordy nie nadają się do encji z tożsamością i mutowalnym stanem (np. encje JPA z wymaganym bezargumentowym konstruktorem i setterami). To narzędzie do przenoszenia niemutowalnych danych, nie do modelowania stanu zmieniającego się w czasie.

Integracja z pattern matching

Od Javy 21 rekordy można dekonstruować we wzorcach (record patterns) w instanceof i switch, wyciągając komponenty bezpośrednio bez wywoływania akcesorów.

Mnemonik

Rekord to dane plus tożsamość wartości (equals po zawartości), klasa to zachowanie plus tożsamość referencyjna.

Dalej: 05 Hierarchie typów: interfejsy, klasy abstrakcyjne, sealed classes i pattern matching

Hierarchie typów: interfejsy, klasy abstrakcyjne, sealed classes i pattern matching

na egzaminie

Interfejsy i klasy abstrakcyjne to dwa narzędzia do modelowania hierarchii typów. Sealed classes/interfaces (Java 17+) dodają kontrolę nad tym, kto może rozszerzać typ. Pattern matching dla switch (Java 21) pozwala wyczerpująco skonsumować taki typ bez branchu default.

Interfejs

  • Wielodziedziczenie: klasa może implementować wiele interfejsów
  • Metody: abstract, default (Java 8+), static, private (Java 9+); brak stanu instancyjnego poza stałymi
  • Kontrakt zdolności: co obiekt POTRAFI zrobić

Klasa abstrakcyjna

  • Jednodziedziczenie: tylko jedna klasa bazowa
  • Może mieć konstruktory, pola instancyjne, metody z dowolną widocznością (private/protected/public)
  • Hierarchia 'jest': wspólna implementacja i stan dla podklas
Domyślna implementacja (Java 8+) i prywatna metoda pomocnicza (Java 9+) w interfejsie java
public interface PaymentProcessor {
    void charge(double amount);

    default void chargeWithLog(double amount) {
        log(amount);
        charge(amount);
    }

    private void log(double amount) {
        System.out.printf("Charging %.2f%n", amount);
    }
}
Termin kluczowy

sealed: Modyfikator (Java 17+) ograniczający zbiór klas/interfejsów mogących bezpośrednio rozszerzać dany typ do jawnie wymienionych w klauzuli permits.

Zamknięta hierarchia: tylko te trzy typy mogą implementować Shape java
public sealed interface Shape permits Circle, Square, Triangle {}

public record Circle(double radius) implements Shape {}
public record Square(double side) implements Shape {}
public record Triangle(double base, double height) implements Shape {}
Wymóg dla podtypów

Każda klasa wymieniona w permits musi być zadeklarowana jako final, sealed (dalej ogranicza) albo non-sealed (jawnie otwiera hierarchię z powrotem). Brak jednego z tych słów to błąd kompilacji.

Switch bez default: kompilator sprawdza wyczerpanie wszystkich permitted typów java
static double area(Shape shape) {
    return switch (shape) {
        case Circle c -> Math.PI * c.radius() * c.radius();
        case Square s -> s.side() * s.side();
        case Triangle t -> t.base() * t.height() / 2;
    };
}
Dekonstrukcja rekordu we wzorcu plus warunek when java
record Point(int x, int y) {}

static String describe(Object obj) {
    return switch (obj) {
        case Point(int x, int y) when x == y -> "Punkt na przekątnej: " + x;
        case Point(int x, int y) -> "Punkt (" + x + ", " + y + ")";
        default -> "Nieznany obiekt";
    };
}
Pułapka

Przed sealed classes jedyną ochroną przed nieobsłużonym podtypem w switch/if-else był ręcznie pisany branch default rzucający wyjątek w runtime. Sealed plus pattern matching przenosi ten błąd z runtime na czas kompilacji.

  • Interfejs: gdy potrzebujesz kontraktu implementowanego przez niepowiązane typy (np. Comparable, Runnable)
  • Klasa abstrakcyjna: gdy podklasy dzielą realną implementację i stan
  • Sealed: gdy znasz z góry pełny, zamknięty zbiór wariantów (np. reprezentacja AST, wynik operacji: Success/Failure)
Mnemonik

sealed mówi 'to są WSZYSTKIE możliwe podtypy', switch z pattern matching mówi 'obsłużyłem je WSZYSTKIE, kompilator to potwierdza'.

Dalej: 06 Generyki, type erasure i var

Generyki, type erasure i var

na egzaminie

Generyki dają bezpieczeństwo typów w czasie kompilacji bez rzutowań. JVM ich jednak nie widzi w runtime: mechanizm type erasure usuwa parametry typu z bytecode'u, zostawiając tylko ich ograniczenia (bounds) albo Object.

Co znika w runtime

List<String> i List<Integer> mają dokładnie tę samą klasę w runtime: List.class. Nie da się zrobić instanceof List<String>, tylko instanceof List<?> (wildcard nieograniczony).

Bounded type parameter: T musi implementować Comparable<T> java
static <T extends Comparable<T>> T max(List<T> list) {
    return list.stream()
        .max(Comparator.naturalOrder())
        .orElseThrow(NoSuchElementException::new);
}
Termin kluczowy

PECS (Producer Extends, Consumer Super): Reguła doboru wildcardów. Użyj ? extends T dla źródła, z którego tylko czytasz (producenta). Użyj ? super T dla celu, do którego tylko zapisujesz (konsumenta).

Producer extends, consumer super java
static void copy(List<? extends Number> source, List<? super Number> destination) {
    for (Number n : source) {
        destination.add(n);
    }
}
Pułapka

new T[10] nie kompiluje się przy generycznym T: erasure nie zna rzeczywistego typu elementu w runtime, więc JVM nie potrafi utworzyć poprawnie otypowanej tablicy. Obejście: Array.newInstance(...) z jawnym Class<T> i rzutowaniem, albo użycie List<T> zamiast tablicy.

Bridge methods

Kompilator generuje niewidoczne metody mostkujące (bridge methods), gdy nadpisanie metody generycznej po erasure miałoby inną sygnaturę niż w typie bazowym. Dzięki temu polimorfizm działa mimo erasure.

Termin kluczowy

var: Lokalne wnioskowanie typu (Java 10+, JEP 286): kompilator wyprowadza konkretny typ statyczny zmiennej lokalnej z wyrażenia inicjalizującego. To nie jest typowanie dynamiczne; typ jest ustalany raz, w czasie kompilacji.

var tam, gdzie typ jest oczywisty z prawej strony java
var users = new ArrayList<String>();  // typ: ArrayList<String>
for (var user : users) {              // typ: String
    System.out.println(user.toUpperCase());
}

try (var conn = dataSource.getConnection()) {
    // typ: Connection
}
Pułapka

var wymaga inicjalizatora (var x; nie kompiluje się). Słowo var nie działa dla pól klasy ani zwykłych parametrów metod (dozwolone od Javy 11 tylko dla parametrów lambdy).

Pułapka

Nie nadużywaj var tam, gdzie ukrywa typ niejasny z kontekstu (np. var result = process();).

Mnemonik

Generyki plus var to dwa różne poziomy: generyki to bezpieczeństwo typu w API, var to wygoda zapisu bez zmiany rzeczywistego typu.

Dalej: 07 Stream API: leniwość, operacje terminalne, kolektory

Stream API: leniwość, operacje terminalne, kolektory

na egzaminie

Stream API opisuje przetwarzanie danych deklaratywnie: źródło, operacje pośrednie (intermediate), operacja terminalna (terminal). Operacje pośrednie są leniwe: nic się nie wykonuje, dopóki nie pojawi się operacja terminalna.

Leniwość

map(), filter(), sorted(), distinct(), peek() budują tylko opis pipeline'u. Faktyczne przejście po elementach następuje dopiero przy wywołaniu operacji terminalnej, i to element po elemencie (nie faza po fazie).

Bez operacji terminalnej pipeline się nie wykonuje java
List<String> names = List.of("Ala", "Bartek", "Celina");

names.stream()
    .filter(n -> {
        System.out.println("filter: " + n);
        return n.length() > 3;
    })
    .map(String::toUpperCase);
// brak wypisania na konsolę - bez operacji terminalnej pipeline się nie wykonuje
Termin kluczowy

Operacja terminalna: Operacja kończąca pipeline i faktycznie konsumująca strumień, zwracająca wynik lub efekt uboczny (collect, forEach, reduce, count, anyMatch, findFirst...). Po jej wywołaniu strumień jest zamknięty.

Pułapka

Ponowne użycie tego samego obiektu Stream po wywołaniu operacji terminalnej rzuca IllegalStateException ('stream has already been operated upon or closed'). Strumień to jednorazowy potok, nie kolekcja wielokrotnego użytku.

Grupowanie po długości nazwy java
Map<Integer, List<String>> byLength = names.stream()
    .collect(Collectors.groupingBy(String::length));
  • toList() / toSet() / toUnmodifiableList(): zbiór wynikowy
  • toMap(keyFn, valueFn): mapa klucz-wartość
  • joining(delimiter): łączenie Stringów
  • groupingBy(classifier): grupowanie po kluczu
  • partitioningBy(predicate): podział na true/false
  • counting(), summarizingInt(): agregacje liczbowe
Short-circuiting

Operacje takie jak limit(), findFirst(), anyMatch() mogą zakończyć przetwarzanie wcześniej, nie odwiedzając całego źródła; dzięki temu da się bezpiecznie operować na nieskończonych strumieniach (Stream.iterate, Stream.generate).

Stream.iterate + limit: bezpieczne cięcie nieskończonego strumienia java
List<Integer> firstFive = Stream.iterate(1, n -> n + 1)
    .limit(5)
    .toList(); // [1, 2, 3, 4, 5], JDK 16+
toList() (Java 16+)

Stream.toList() zwraca niemodyfikowalną listę podobną w duchu do collect(Collectors.toUnmodifiableList()). Obie metody nie są jednak tożsame: toList() dopuszcza elementy null, natomiast toUnmodifiableList() rzuca NullPointerException dla null. JDK nie gwarantuje konkretnego typu implementacji ani identyczności zachowania.

Mnemonik

Operacje pośrednie tylko planują; operacja terminalna naciska 'start'.

Dalej: 08 Wątki wirtualne (Project Loom) vs platformowe

Wątki wirtualne (Project Loom) vs platformowe

na egzaminie

Wątki wirtualne (Java 21, JEP 444) to lekkie wątki zarządzane przez JVM, mapowane wiele-do-kilku na wątki platformowe (wątki nośne, carrier threads). Celem jest tania współbieżność dla kodu blokującego na I/O, bez pisania kodu asynchronicznego.

Wątek platformowy

  • Odwzorowanie 1:1 na wątek systemu operacyjnego
  • Kosztowny: stos rzędu megabajtów, tworzenie i przełączanie kontekstu drogie
  • Praktyczny limit: tysiące wątków na proces
  • Dobry do obliczeń intensywnie korzystających z CPU

Wątek wirtualny

  • Zarządzany przez JVM, tymczasowo montowany na wątku nośnym
  • Tani: lekki stos rosnący na stercie, tworzenie niemal darmowe
  • Praktyczny limit: setki tysięcy lub miliony instancji
  • Dobry do kodu blokującego na I/O (sieć, baza danych, pliki)
Executors.newVirtualThreadPerTaskExecutor(): jeden wątek wirtualny na zadanie java
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10_000; i++) {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return null;
        });
    }
} // executor.close() czeka na zakończenie wszystkich zadań
Odmontowanie na blokadzie

Gdy wątek wirtualny blokuje się na operacji I/O, JVM odczepia go od wątku nośnego, zwalniając ten wątek nośny do obsługi innych wątków wirtualnych. Po zakończeniu operacji wątek wirtualny wraca na dowolny wolny wątek nośny.

Pułapka

Pinning: wątek wirtualny wykonujący blokującą operację wewnątrz bloku synchronized (albo natywnej metody JNI) NIE odczepia się od wątku nośnego, tylko go blokuje (przypina). Przy dużej liczbie wątków wirtualnych to zjada pulę wątków nośnych i niweczy korzyść skalowania.

ReentrantLock zamiast synchronized w kodzie z blokującym I/O na wątkach wirtualnych java
private final ReentrantLock lock = new ReentrantLock();

void transfer() {
    lock.lock();
    try {
        // blokująca operacja I/O nie przypina wątku nośnego
    } finally {
        lock.unlock();
    }
}
Diagnostyka pinningu

Flaga -Djdk.tracePinnedThreads=full (albo short) loguje miejsca w kodzie, gdzie wątek wirtualny zostaje przypięty do wątku nośnego podczas blokowania.

Pułapka

Wątki wirtualne nie przyspieszają obliczeń intensywnie korzystających z CPU (nie ma ich więcej niż rdzeni procesora, które faktycznie mogą coś liczyć). Do równoległych obliczeń nadal właściwy jest ForkJoinPool albo równoległe strumienie, nie wątki wirtualne.

  • Twórz jeden wątek wirtualny na zadanie (task), nie pul ich jak platformowych: są tanie, pooling tylko dodaje złożoność bez korzyści
  • Unikaj synchronized w ścieżkach z blokującym I/O na wątkach wirtualnych, użyj java.util.concurrent.locks
  • Nie trzymaj dużych ThreadLocal na wątkach wirtualnych masowo: koszt pamięci mnoży się przez liczbę instancji
Mnemonik

Platformowy wątek to drogi pracownik na etacie; wirtualny to tani podwykonawca na zlecenie, którego JVM zatrudnia i zwalnia w mikrosekundach.

Sprawdź się

20 z 24 pytań, losowo, z wyjaśnieniem po każdym. Wynik zostaje na tym urządzeniu.

Rozpocznij quiz

Fiszki: Java

Pytanie

O tym demo

Działające demo kursów napisanych przez Tenzan Logic. Wyniki zostają na tym urządzeniu, bez konta.

Każdy kurs, pytanie i fiszkę napisał Tenzan Logic, po polsku i od zera. Jeśli chcesz taki zestaw dla swojego zespołu, z Twoimi procedurami i Twoim słownictwem, napisz.

Napisz do Tenzan Logic

Jak to działa

100% czas (dni) bez powtórek 1 3 7 21 z powtórkami
Schemat idei, nie dane pomiarowe (Ebbinghaus 1885; Cepeda i in. 2006).
  • Odstępy

    1·3·7·21 dni do powtórki

    Fiszka z „Umiem” wraca po 1, 3, 7 i 21 dniach.

    Badanie

    Powtórki z przerwami dają trwalszą pamięć niż jedna po drugiej. Cepeda i in. 2006, Psychological Bulletin 132(3): 354-380

  • Przypominanie

    ukryta odpowiedź fiszki

    Najpierw odpowiedz z pamięci, potem odwróć.

    Badanie

    Próba przypomnienia dała lepszą pamięć po dwóch dniach i po tygodniu niż ponowne czytanie. Roediger i Karpicke 2006, Psychological Science 17(3): 249-255

  • Dwa kody

    4 kolory bloków

    Fakt, termin, mnemonik i pułapka mają swój kolor.

    Badanie

    Teoria: słowo i obraz zapisują się osobno. To teoria, nie gwarancja wyniku. Paivio 1991, Canadian Journal of Psychology 45(3): 255-287

  • Porcje

    167 krótkich sekcji

    Jedna sekcja to jedna porcja do zapamiętania.

    Badanie

    Pamięć robocza mieści około czterech porcji (Miller 1956: siedem, Cowan 2001: cztery). Cowan 2001, Behavioral and Brain Sciences 24(1): 87-114

  • Skróty

    134 zielone bloki

    Mnemonik zbiera kilka elementów w jeden, np. „SUR”.

    Badanie

    Skrót zbiera kilka elementów w jeden; przykład „SUR” jest w kursie o podstawach AI. Opis funkcji aplikacji, bez cytowanego badania

  • Testy

    20 z 24 pytań w quizie

    Po każdej odpowiedzi widzisz wyjaśnienie.

    Badanie

    Ćwiczenie, nie sprawdzian: pytania są w losowej kolejności i uzupełniają fiszki, nie zastępują ich. Efekt testowania: zob. „Przypominanie”

Szukaj

Postęp

Brak wyników. Rozwiąż pierwszy quiz.

Tu zbiera się Twój postęp: rekord i medal każdego quizu, seria dni i pytania do powtórki.

Gdzie jest zapis
Tylko w pamięci tej przeglądarki. Konta nie ma i wyniki nigdzie nie są wysyłane. Inna przeglądarka lub inne urządzenie zaczyna od zera.
Jak wyczyścić
W quizie: Historia, potem Wyczyść historię. Fiszki i serię dni usuniesz razem z danymi witryny w ustawieniach przeglądarki.
Wybierz quiz

Progi medali

Medal liczy się z najlepszego wyniku quizu: Brąz od 60%, Srebro od 75%, Złoto od 90%, Platyna przy 100%.