0Pricing
Java Academy · Lekcja

Własne interfejsy funkcyjne

Definiowanie własnego interfejsu za pomocą @FunctionalInterface

Własne interfejsy funkcyjne to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Co sprawia, że interfejs jest funkcyjny

Interfejs funkcyjny ma dokładnie jedną metodę abstrakcyjną (SAM). To właśnie tę pojedynczą metodę implementuje lambda.

  • Metody domyślne i statyczne nie są uwzględniane w tym limicie.
interface Greeter {
    String greet(String name);
}

public class Main {
    public static void main(String[] args) {
        Greeter g = name -> "Hello, " + name;
        System.out.println(g.greet("Ada"));
    }
}

Adnotacja @FunctionalInterface

@FunctionalInterface nakazuje kompilatorowi egzekwować regułę jednej metody abstrakcyjnej. Jeśli przypadkowo zostanie dodana druga metoda abstrakcyjna, kompilacja zakończy się niepowodzeniem.

@FunctionalInterface
interface Calculator {
    int compute(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        Calculator add = (a, b) -> a + b;
        System.out.println(add.compute(3, 4));
    }
}

Dlaczego adnotacja jest pomocna

Adnotacja dokumentuje zamiar i chroni kontrakt. Bez niej interfejs nadal działa jako funkcyjny, ale inny programista mógłby go zepsuć, dodając kolejną metodę abstrakcyjną.

@FunctionalInterface
interface Transformer {
    String apply(String input);
}

public class Main {
    public static void main(String[] args) {
        Transformer reverse = s -> new StringBuilder(s).reverse().toString();
        System.out.println(reverse.apply("abc"));
    }
}

Własny interfejs z typami generycznymi

Interfejs może być generyczny, podobnie jak interfejsy wbudowane.

@FunctionalInterface
interface Converter<S, T> {
    T convert(S source);
}

public class Main {
    public static void main(String[] args) {
        Converter<String, Integer> toInt = Integer::parseInt;
        System.out.println(toInt.convert("123") + 1);
    }
}

Metody domyślne są dozwolone

Interfejs funkcyjny może zawierać metody default. Dodają one zachowanie bez naruszania reguły jednej metody abstrakcyjnej.

@FunctionalInterface
interface Operation {
    int apply(int x);

    default Operation then(Operation next) {
        return x -> next.apply(this.apply(x));
    }
}

public class Main {
    public static void main(String[] args) {
        Operation inc = x -> x + 1;
        Operation dbl = x -> x * 2;
        System.out.println(inc.then(dbl).apply(5));
    }
}

Metody statyczne również są dozwolone

Metody statyczne mogą pełnić funkcję fabryk, podobnie jak Function.identity().

@FunctionalInterface
interface Mapper {
    int map(int x);

    static Mapper identity() {
        return x -> x;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Mapper.identity().map(99));
    }
}

Zgłaszanie wyjątków kontrolowanych

Jeśli metoda abstrakcyjna deklaruje wyjątek kontrolowany, lambda może go zgłaszać. Wbudowany Function nie pozwala na to, co stanowi jeden z powodów definiowania własnego interfejsu.

@FunctionalInterface
interface RiskyParser {
    int parse(String s) throws NumberFormatException;
}

public class Main {
    public static void main(String[] args) {
        RiskyParser p = Integer::parseInt;
        System.out.println(p.parse("77"));
    }
}

Przekazywanie własnych interfejsów do metod

Interfejs staje się typem parametru, dzięki czemu wywołujący mogą dostarczać zachowanie za pomocą lambd.

@FunctionalInterface
interface IntCombiner {
    int combine(int a, int b);
}

public class Main {
    static int reduce(int[] arr, IntCombiner c) {
        int acc = arr[0];
        for (int i = 1; i < arr.length; i++) acc = c.combine(acc, arr[i]);
        return acc;
    }

    public static void main(String[] args) {
        int[] data = {1, 2, 3, 4};
        System.out.println(reduce(data, (a, b) -> a + b));
    }
}

Interfejs przyjmujący trzy argumenty

JDK udostępnia interfejsy przyjmujące tylko jeden lub dwa argumenty. W przypadku trzech lub większej liczby argumentów należy zdefiniować własny interfejs.

@FunctionalInterface
interface TriFunction<A, B, C, R> {
    R apply(A a, B b, C c);
}

public class Main {
    public static void main(String[] args) {
        TriFunction<Integer, Integer, Integer, Integer> sum3 = (a, b, c) -> a + b + c;
        System.out.println(sum3.apply(1, 2, 3));
    }
}

Referencje do metod pasują do własnych interfejsów

Każda metoda, której sygnatura odpowiada SAM, może zostać przekazana jako referencja do metody.

@FunctionalInterface
interface StringTest {
    boolean check(String s);
}

public class Main {
    public static void main(String[] args) {
        StringTest blank = String::isBlank;
        System.out.println(blank.check("   "));
    }
}

Klasa anonimowa a lambda

Lambda jest zwięzłym zamiennikiem klasy anonimowej implementującej interfejs funkcyjny. Oba rozwiązania zapewniają takie samo zachowanie.

@FunctionalInterface
interface Action {
    void run();
}

public class Main {
    public static void main(String[] args) {
        Action old = new Action() {
            public void run() { System.out.println("anonymous"); }
        };
        Action neo = () -> System.out.println("lambda");
        old.run();
        neo.run();
    }
}

Szybkie sprawdzenie

Co gwarantuje @FunctionalInterface?

Podsumowanie

Zdefiniowano własne interfejsy funkcyjne:

  • Interfejs funkcyjny ma dokładnie jedną metodę abstrakcyjną (SAM).
  • @FunctionalInterface egzekwuje tę regułę podczas kompilacji.
  • Metody domyślne i statyczne, typy generyczne oraz wyjątki kontrolowane są dozwolone.
  • Własne interfejsy uzupełniają luki, których nie pokrywa JDK, na przykład obsługują funkcje z trzema argumentami lub lambdy zgłaszające wyjątki kontrolowane.

Często zadawane pytania

Czy lekcja „Własne interfejsy funkcyjne” jest bezpłatna?

Tak — pełny tekst „Własne interfejsy funkcyjne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Własne interfejsy funkcyjne”?

Definiowanie własnego interfejsu za pomocą @FunctionalInterface Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Własne interfejsy funkcyjne”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Function i BiFunction
  2. Supplier i Consumer
  3. Predicate i kompozycja
  4. Własne interfejsy funkcyjne
← Powrót do Java Academy