Uczę się javy na tle javascript i zastanawiam się, czy można napisać podobną funkcję w Javie. Oto przykład w javascript:

function getBalance(side, date) {
    let balance;
    let getPrice = (f) => {
        while ((result = f(date)) == 0) {
            date++;
        }
        return result;
    }
    if (side) {
        let price = getPrice(getPrice1);
        // Some calculations
        return balance;
    } else {
        let price = getPrice(getPrice2);
        // Some calculations
        return balance;
    }
}

Gdzie getPrice1 i getPrice2 są poprzednio zdefiniowanymi funkcjami. Użycie tutaj calbacków pomaga skrócić kod. Nie jestem pewien, czy w Javie można przekazać funkcję jako argument bez deklarowania dodatkowych interfejsów.

Zadałem to pytanie, ponieważ jest to uproszczony przykład prawdziwego zadania, które napotkałem. Jak myślisz, które będzie najbardziej eleganckim rozwiązaniem?

P.S. Wygląda na to, że sposób na interfejsy funkcjonalne jest tutaj.

4
sweetshot 6 marzec 2020, 13:12

2 odpowiedzi

Najlepsza odpowiedź

Tak, to możliwe.

Oto przykładowa prezentacja, aby zilustrować, jak można to połączyć.

class Showcase {

    public static void main(String[] args) {
        Function<Function<LocalDate, Double>, Double> getPrice = f -> {
            // an example how to call it - replace it with your logic
            f.apply(LocalDate.now());

            return 0.;
        };

        getPrice.apply(Showcase::getPrice1);
        getPrice.apply(Showcase::getPrice2);
    }

    public static Double getPrice1(LocalDate date) {
        return 0.;
    }

    public static Double getPrice2(LocalDate date) {
        return 1.;
    }

}

Byłoby to bardziej szczegółowe ze względu na dyscyplinę pisania. Jednak idea jest zasadniczo taka sama.

3
Andrew Tobilko 6 marzec 2020, 10:36

Oto rozwiązanie, które wygląda dość blisko kodu javascript:

import java.time.LocalDate;

public class Showcase {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now();

        double result1 = getPrice(priceFunction1, date);
        double result2 = getPrice(priceFunction2, date);
    }

    private static double getPrice(PriceFunction priceFunction, LocalDate date) {
        return priceFunction.getPrice(date);
    }

    private static final PriceFunction priceFunction1 = date -> date.getYear() * 0.5;
    private static final PriceFunction priceFunction2 = date -> date.getYear() * 1.5;

    @FunctionalInterface
    private interface PriceFunction {
        double getPrice(LocalDate date);
    }
}

Zamiast używać standardowych interfejsów funkcjonalnych z języka java, takich jak Function, po prostu zdefiniuj nowy interfejs funkcjonalny, który dokładnie spełnia wymagania Twojej funkcji: pobiera datę i zwraca podwójną wartość.

Funkcja getPrice przyjmuje taką „funkcję” jako pierwszy argument, wtedy musimy podać datę (zakresy javascript tu trochę ułatwiają ...). Same „funkcje” są wyrażeniami lambda i możemy je przechowywać jako pola lub stałe statyczne.

Purysta może krzyczeć, że nie wybrałem krzyczącej wielkości liter dla nazw, ale celowo odstąpiłbym od powszechnych konwencji nazewnictwa ze względu na czytelność.

4
Naman 6 marzec 2020, 14:04