Java:Programowanie funkcyjne

Udało ci się, pierdoło, dojść aż do tego etapu? Przecież wiem, że nawet nie zrozumiałeś do końca poprzedniego rozdziału. Boże, człowieku, przecież to jest wszystko zapisane, abyś wracał do woli i czytał, analizował i próbował rozumieć. Jeżeli nadal nie wiesz co tu robisz i pomimo tego idziesz do przodu, to tak jakbyś znalazł się na studiach z poziomem wiedzy z gimnazjum. Albo, może poprawnie powinienem powiedzieć, z *podstawówki*.

Już, a kysz! Wracaj do poprzednich rozdziałów i nie chcę cię widzieć, póki nie napiszesz mi z pamięci programu rysującego połowę choinki!

## Definicja funkcji

### Trochę matematyki

Jak pewnie wiesz, w matematyce funkcje istnieją. Z tego mamy taki profit, że nie powinieneś próbować sobie tłumaczyć funkcje informatyczne inaczej niż właśnie tymi matematycznymi.

Na początku rozpiszmy może dowolną funkcję matematyczną. Niech będzie to funkcja kwadratowa. Dla dowolnego ***x*** przyjmuje ona pewną wartość wyliczaną wzorem:

f
(
x
# )

x
2

{\displaystyle f(x)=x^2}

Czyli praktycznie jedyne, co robi ta funkcja, to podnoszenie do kwadratu.

Przypomnij sobie (choć powinieneś to po prostu wiedzieć!), czy w Javie możemy podnosić do potęgi? Oczywiście że tak! Taką funkcję więc równie dobrze będziemy mogli zapisać w programie!

Dodatkowo funkcje są niezwykle przydatne, bo mogą zastąpić te elementy kodu, które wielokrotnie powtarzamy, na przykład wzór, silnię, czy cokolwiek innego.

### Ciekawsze funkcje

Teraz jednak weźmy pod uwagę przypadek, gdy funkcja w różnych przedziałach przyjmuje inne wartości. Na przykład dla *x* mniejszego od lub równego 0 niech ma wartość 1.

f
(
x
# )

{

1

dla
x
∈
(
−
∞
,
0
>

x
2

dla
x
∈
(
0
,
∞
)

{\displaystyle
f(x) =
 \begin{cases}
 1 & \quad \text{dla } x \in (-\infty , 0>\\
 x^2 & \quad \text{dla } x \in (0, +\infty )\\
 \end{cases}
}

Jak rozwiązać ten problem? No coż, jeżeli czytałeś uważnie (wiem, że nie), to powstaje tutaj warunek. J e ż e l i x jest mniejsze lub równe 0, to wtedy wartość funkcji wynosi 1. W innym przypadku jest to x do kwadratu.

Widzisz to? Hę? J e ż e l i to widzisz, powinieneś wiedzieć o co chodzi. J e ż e l i. Rozumiesz? Ech...

Jeżeli po angielsku to **if**. To magiczne słówko potrafi zapewnić nam właśnie, że dla warunku if(x <= 0) funkcja przyjmie wartość 1, a w każdym innym przypadku (else) będzie to wartość funkcji kwadratowej.

## Funkcja w kodzie

### Jak to, cholera, zapisać?

Nie wiem czy wiesz, ale funkcja jest tak jakby zmienną. Znaczy jest i nie jest. Dlaczego?

Zobacz, matematyczne mogłeś do dowolnej niewiadomej przypisać wartość funkcji, na przykład

# q
f
(
p
)

{\displaystyle q = f(p)}

W informatyce możesz zrobić to samo! Jednak znów ci przypomnę - Java cię nienawidzi. Nie zrobisz nic, jeśli nie określisz, jakiego typu jest funkcja.

### Nie odpowiedziałeś mi na pytanie.

A więc funkcją, która nie ma potrzeby przyjmować wartości jest **void**. Zapamiętaj dobrze tę nazwę. Pewnie ją gdzieś widziałeś już... A no tak!

```
public static void main(String[] args) {

```

main nie przyjmuje wartości, dlatego main jest funkcją typu void.

Dodatkowym słowem, które przed nazwą musi mieć każda funkcja będzie **static**. Static określa, że funkcja jest statyczna, czyli istnieje gdy włączasz program. Na swój poziom, adepcie Zakonu Klawiatury, wystarczy ci to wytłumaczenie.

Pamiętaj także o nawiasach! W nawiasach podaje się **argumenty**. To słowo znaczy dokładnie to samo co w matematyce - to jest ten "x" z funkcji. Jeżeli argumenty są niepotrzebne, zostawiasz pusty nawias.

UWAGA! O ile główny program zapisujesz w klamrach funkcji main, swoje funkcje zapisuj poza nimi. To znaczy nie zaczynaj nowej funkcji, póki nie zamkniesz klamry poprzedniej.

Oznacza to, że masz pisać pod funkcją main, ale jeszcze w klasie. Jeżeli uważałeś, to zrozumiesz.

### Rodzaje funkcji

Funkcja jednak bardziej by nam się przydała, gdyby przyjmowała jakąś konkretną wartość.

Taką wartością może być **dowolny typ Javy.** To nawet trochę praktyczne, móc stworzyć dowolną zmienną i "wrzucić" do niej wynik z funkcji...

Dlatego np. możemy stworzyć zmienną typu int, double, String, czy jakiegokolwiek innego. Wystarczy ten typ wpisać po static.

```
static double funkcja() {

```

Chyba nie muszę tłumaczyć, że nazwa funkcji jest już dowolna?

### No i co z tymi typami?

Jeżeli zdecydujesz się na jakiś typ, funkcja w końcu musi przybrać jakąś wartość. Robi się to magicznym słówkiem **return**, po którym wpisujesz wartość. Przed tym słówkiem może dziać się cokolwiek wpiszesz, nawet niezwiązanego z wynikiem. Pamiętaj jednak, że funkcja musi zwracać coś dla każdego argumentu!

```
static int cztery() {
  return 4;
}

```

Tak zmyślnie napisana funkcja jest oczywiście funkcją stałą odpowiadającą wyrażeniu matematycznemu:

f
(
x
# )
4

{\displaystyle f(x) = 4}

Taką funkcję możemy np. wykorzystać w takich niecnych celach, jak dawanie zmiennym wartości... **4**!

```
int jakaś_zmienna = cztery();

```

Widoczna wyżej zmienna od tego momentu ma wartość zwróconą przez funkcję (to, co wyrzuciła po return).

### Funkcja kwadratowa w Javie

Jak pewnie widziałeś, wyżej czepiłem się tej funkcji kwadratowej. Zapisanie jej w kodzie jest proste jak zapisanie x\*x. Jednak skoro to jest funkcja, powinniśmy zapisać jej odpowiednik w Javie.

```
static double funkcja(double x) {
  return x*x;
}

```

Zauważ, że w nawiasie wpisałem zarówno x, jak i *double*. Jest to spowodowane wielokrotnie wspominaną nienawiścią Javy do ciebie, młody adepcie, dlatego argumenty też muszą mieć ustalony typ.

Użycie tej funkcji wygląda analogicznie jak wyższe hybrydy matematyczno-programistyczne:

```
double wartosc = funkcja(5);

```

wartosc przyjęło wartość 25.

### Zabawa z przedziałami

Używając ifa ulepszymy teraz naszą funkcję. Dodajemy do niej warunek - jeżeli x <= 0, to zwróć 1.

```
if(x <= 0) return 1;

```

Jednak to nie jest jedyne, co musimy zrobić w naszej funkcji. Zostają jeszcze liczby dodatnie, których nie uwzględniliśmy. Dla nich funkcja powinna przyjąć wartość funkcji kwadratowej. Dlatego używając else dodajemy drugie return.

```
static double funkcja(double x) {
  if(x <= 0) return 1;
  else return x*x;
}

```

Da się? Da się! Możesz spróbować u siebie jeżeli nie wierzysz.

## Funkcja używająca funkcji

### Zabawa dopiero się zaczyna

Wyobraź sobie kolejną nudną lekcję matematyki. Przestałeś już uważać i oczy już ci się zamykają. Nagle wpadasz w swój trans myślowy i zastanawiasz się nad różnymi pierdołami, jak na przykład studnią. Taka studnia jest głęboka, a jak zrobisz jej zdjęcie, to wtedy otwór tak jakby się staje mniejszy. Znaczy tak jakby, bo dno jest coraz dalej. Czyli wyciągając kciuka przed siebie mozesz je zasłonić. "Ciekawe", zastanawiasz się, "a jakby tak narysować coś takiego?"

Zabierasz się do roboty. Jesteś ograniczony plastycznie, ale to żaden problem - wykombinowałeś ciekawy sposób narysowania studni. Zaczniesz od narysowania dużego okręgu, a w nim będziesz rysował coraz mniejsze i mniejsze... aż w końcu zostawisz taki jeden mały w środku. Jak doda się do tego cieni, to będzie prawie jak studnia!

Zobacz jak łatwo zbudować taki rysunek studni - okręg w okręgu. Jednak zobacz też, że cały czas robiłeś to samo - rysowałeś okręgi. Bez narysowania największego nie mogłeś dobrze ocenić wielkości mniejszego i go narysować - w rezultacie musiałeś (i tak robiłeś) rysować po kolei. Tyle, że nie rysowałeś okręgów. Rysowałeś studnię.

Co się z tym wiąże to to, że każdy dowolny okrąg oprócz najmniejszego też jest studnią. Czyli narysowałeś studnie w studni. Teoretycznie użyłeś studni do narysowania studni, czyli bez studni nie mogłeś narysować studni. **A czym jest studnia? Cóż... jest okręgiem ze studnią w środku**.

Czyli studnia jest studnią... To się wydaje głupie, ale ma wiele sensu, ponieważ każda studnia ma własny okrąg i studnię! Czyli rysujesz studnię w okręgu do pewnego momentu, czyli aż nie będziesz miał miejsca na kartce. Podobny efekt masz na obrazku po lewej - tutaj studnia składa się z ramki i studni. Czyli z ramki i w studni: ramki ze studnią. Czyli składa się (jescze raz): z ramki i studni: w niej jest ramka i studnia: w niej jest ramka i studnia. Czekaj... Mam już trzy ramki i tak naprawdę jedną studnię... Czyli studnia jest nieskończona, a zobaczyć jej efekt możemy dzięki ramce!

### Co to ma do Javy?

W Javie coś takiego **też jest możliwe**. Można użyć funkcji w funkcji. Nazywa się to **rekurencją** (rekursją). Chodzi o to, że gdy wzór funkcji może się rozwijać w nieskończoność (to znaczy dla jednego argumentu jest inny niż dla drugiego, ale schemat ten sam), to możemy użyć tej samej funkcji. Przedstawię matematycznie wzór na silnię:

s
i
l
n
i
a
(
x
# )

{

1

dla
x
≤
1

x
⋅
s
i
l
n
i
a
(
x
−
1
)

dla
x
>
1

{\displaystyle
silnia(x) =
 \begin{cases}
 1 & \quad \text{dla } x \leq 1\\
 x \cdot silnia(x-1) & \quad \text{dla } x > 1\\
 \end{cases}
}

Możemy spróbować rozpisać ten wzór dla 5!:

s
i
l
n
i
a
(
5
# )
5
⋅
s
i
l
n
i
a
(
4
# )
5
⋅
4
⋅
s
i
l
n
i
a
(
3
# )
5
⋅
4
⋅
3
⋅
s
i
l
n
i
a
(
2
# )
5
⋅
4
⋅
3
⋅
2
⋅
s
i
l
n
i
a
(
1
# )
5
⋅
4
⋅
3
⋅
2
⋅
1

{\displaystyle silnia(5) = 5 \cdot silnia(4) = 5 \cdot 4 \cdot silnia(3) = 5 \cdot 4 \cdot 3 \cdot silnia(2) = 5 \cdot 4 \cdot 3 \cdot 2 \cdot silnia (1) = 5 \cdot 4 \cdot 3 \cdot 2 \cdot 1}

Jak pewnie zauważyłeś, nie mogliśmy policzyć silni póki nie rozpisaliśmy jej do końca, czyli uzyskaliśmy wartość tej "najgłębszej" silni. Tak samo będzie działał nasz program.

### Javowa silnia rekurencyjna

A więc bazując na powyższej funkcji matematycznej, zapisujemy funkcję

```
static int silnia(int x) {
  if(x <= 1) return 1;
  else return x * silnia(x-1);
}

```

Zobacz, to dokładnie to samo! Działa też tak samo, dlatego poniższa zmienna będzie miała wartość 120.

```
int wynik = silnia(5);

```

Rozwinięcie tej funkcji jest takie samo jak powyżej, czyli takie jak matematyczne. Możesz sobie porozpisywać, jeśli mi nie wierzysz.