Function în Java

O funcție care primește o valoare de tip T și returnează una de tip R; o apelezi cu apply.

Sintaxă
import java.util.function.Function;

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

Ce face Function

Function<T, R> este tipul unei funcții cu un parametru: primește un T și returnează un R. Este o interfață funcțională (are o singură metodă abstractă, apply), deci o poți crea dintr-o expresie lambda: Function<String, Integer> lungime = s -> s.length(); sau dintr-o referință de metodă: String::length.

apply(valoare) rulează funcția și returnează rezultatul. Așa poți păstra o funcție într-o variabilă, o poți da ca parametru unei metode sau o poți pune într-un map.

Stream.map primește exact o Function. Pentru tipuri primitive există variante fără împachetare: IntFunction, ToIntFunction, IntUnaryOperator etc.

Parametri

Parametru Descriere
t Pentru apply: valoarea de intrare.

Ce returnează

apply returnează rezultatul funcției, de tip R.

Exemple

Exemplul 1: Funcții în variabile

import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        Function<String, Integer> lungime = String::length;
        Function<Double, Double> cuTva = pret -> pret * 1.21;

        System.out.println(lungime.apply("Timișoara"));
        System.out.println(cuTva.apply(100.0));
    }
}

Rezultat

9
121.0

Exemplul 2: O metodă care primește o funcție

Metoda transforma nu știe ce face funcția; primește regula ca parametru.

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class Main {
    static <T, R> List<R> transforma(List<T> lista, Function<T, R> f) {
        List<R> rezultat = new ArrayList<>();
        for (T element : lista) {
            rezultat.add(f.apply(element));
        }
        return rezultat;
    }

    public static void main(String[] args) {
        List<String> orase = List.of("Iași", "Cluj", "Brăila");
        System.out.println(transforma(orase, String::toUpperCase));
        System.out.println(transforma(orase, o -> o + " (" + o.length() + ")"));
    }
}

Rezultat

[IAȘI, CLUJ, BRĂILA]
[Iași (4), Cluj (4), Brăila (6)]

Exemplul 3: Un map de operații

import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        Map<String, Function<Integer, Integer>> operatii = new TreeMap<>();
        operatii.put("dublu", x -> x * 2);
        operatii.put("pătrat", x -> x * x);
        operatii.put("minus", x -> -x);

        operatii.forEach((nume, f) -> System.out.println(nume + "(7) = " + f.apply(7)));
    }
}

Rezultat

dublu(7) = 14
minus(7) = -7
pătrat(7) = 49

Greșeli frecvente

  • Folosești Function<Integer, Integer> pentru calcule multe cu numere. Fiecare apel împachetează valori; IntUnaryOperator evită asta.
  • Încerci să apelezi funcția ca f(5). În Java scrii f.apply(5).
  • Ai nevoie de doi parametri. Function are unul; folosește BiFunction.

Comenzi înrudite

  • Function.andThen: Leagă două funcții una după alta: f.andThen(g) rulează întâi f, apoi g; f.compose(g) rulează întâi g, apoi f.
  • Function.identity: Funcția care returnează exact valoarea primită; utilă în toMap și groupingBy când elementul însuși e cheia sau valoarea.
  • BiFunction: O funcție cu doi parametri (de tipuri T și U) care returnează un R; o apelezi cu apply(a, b).
  • UnaryOperator: O Function în care intrarea și ieșirea au același tip (T → T); folosită de List.replaceAll și Stream.iterate.
  • Stream.map: Transformă fiecare element al stream-ului în altă valoare, eventual de alt tip.