Funkcja, ogólnie rzecz biorÄ…c, jest to kawaÅ‚ek kodu przypisany do jakiejÅ› nazwy. Gdziekolwiek w kodzie bÄ™dzie napotkany ciÄ…g znaków a bezpoÅ›rednio po nim para nawiasów okrÄ…gÅ‚ych, kompilator Javy uzna że to jest funkcja i bÄ™dzie próbowaÅ‚ jÄ… wywoÅ‚ać. Funkcje mogÄ… mieć wÅ‚asny zestaw funkcji, niedostÄ™pny z zewnÄ…trz, a wiÄ™c mogÄ… być Å›ciÅ›le wyspecjalizowane do jakiejÅ› czynnoÅ›ci, np. opisywana dalej funkcja suma jako parametr bÄ™dzie dostawaÅ‚a tablicÄ™ liczb caÅ‚kowitych, a zwracać bÄ™dzie już tylko jednÄ… liczbÄ™ caÅ‚kowitÄ… – sumÄ™ wszystkich elementów tablicy podanej jako parametr.
Już w międzyczasie używaliśmy kilku funkcji, ale dotychczas były to funkcje wbudowane w Javę, jak np. funkcja length() stringów, czy funkcja Math.random(). Część z tych funkcji zwracała jakieś wartości, czyli tak jakby w kodzie wywołanie funkcji było zamieniane na wartość, jaką ona zwraca, np. w tym fragmencie:
String str = "test"; int dlugosc = str.length();
funkcja length() stringa str zamieniana jest na wartość jaką zwraca, czyli w
tym przypadku 4, która to jest przypisywana do zmiennej dlugosc. Czyli
ten kod będzie znaczył to samo co:
String str = "test"; int dlugosc = 4;
Ale funkcja nie musi zwracać żadnej wartości. Takie funkcje zazwyczaj wyświetlają coś na ekran lub wykonują jakieś operacje na podanych zmiennych (ale ich nie zwracają, tylko zmieniają te podane), ale to innym razem.
Java jest jÄ™zykiem bardzo obiektowym – w zasadzie wszystko w nim jest obiektem. Polega to na tym, że kod jest podzielony na klasy – w najwiÄ™kszym skrócie klasÄ™ można okreÅ›lić jako zbiór zmiennych i funkcje sÅ‚użące do operacji na nich (w praktyce wychodzi to tak, że albo jednych albo drugich może nie być). Należy rozróżnić pojÄ™cie klasy od pojÄ™cia obiektu. Klasa jest to niejako typ obiektu, a obiekt jest to konkretny egzemplarz, czyli np. Leon jest obiektem klasy czÅ‚owiek (ale to nie zostaÅ‚o jeszcze potwierdzone).
Taki krótki wstęp był potrzebny żeby móc uzasadnić wstawienie definicji funkcji w odpowiednie miejsce w kodzie. Otóż musi ona być umieszczona wewnątrz klasy (w naszym przypadku jest to klasa Program, bo jak na razie zajmujemy się tylko przypadkiem z tylko jednym obiektem), ale nie wewnątrz innej funkcji. Schematycznie wygląda to tak:
package jbPack;
import javax.swing.*;
import java.util.*;
import java.io.*;
public
class Program {
// Gdzieś tu muszą być funkcje
public static void main(String[] args)
{
new Program(args);
// Tutaj nie
}
// Ale tutaj tak
}
Jak już wiadomo (mam nadzieję) co to jest funkcja, to można przystąpić do opisania jak funkcję się definiuje. Definicja określa kilka bardzo ważnych dla funkcji rzeczy:
- typ zwracanej wartości (lub void jeśli nie zwracana jest żadna wartość)
- nazwę funkcji, co by można było ją jakoś wywołać
- ewentualne argumenty (może ich w ogóle nie być, może być konkretna liczba argumentów)
- no i last but not least, ciało funkcji, czyli sam kod który będzie wykonywała funkcja
Wygląda to mniej więcej tak:
zwracany_typ nazwa( parametry ){
// jakiÅ› kod
}
Ale lepiej jest wytłumaczyć to na jakimś przykładzie. Napiszmy powiedzmy funkcję o nazwie dodaj(), która będzie przyjmowała dwa argument całkowite i zwracała też liczbę całkowitą, która będzie sumą tych dwóch argumentów. Będzie to wyglądać mniej więcej tak:
int dodaj( int l1, int l2 ){
int wynik;
wynik = l1 + l2;
return wynik;
}
Jak widać, zwracany jest typ int, funkcja przyjmuje 2 parametry typu int: l1 i l2 – w liÅ›cie parametrów przy definicji funkcji kolejne parametry oddziela siÄ™ przecinkami. WewnÄ…trz funkcji tworzona jest nowa zmienna wynik, której przypisywana jest suma argumentów funkcji. Bardzo ważne jest sÅ‚owo kluczowe return. Oznacza ono zmiennÄ… bÄ…dź wartość, która bÄ™dzie zwrócona przez funkcjÄ™. JeÅ›li funkcja ma coÅ› zwracać, to funkcja musi zawierać takÄ… instrukcjÄ™. Trzeba też pamiÄ™tać, żeby kod mógÅ‚ dojść do tego miejsca – chodzi mi o to, że jeÅ›li instrukcjÄ™ return umieÅ›cimy wewnÄ…trz instrukcji warunkowej, to jeÅ›li warunek nie bÄ™dzie speÅ‚niony, to instrukcja return nie bÄ™dzie wykonana, a tak być nie może. JeÅ›li return jest w instrukcji warunkowej, to musi on być też wewnÄ…trz bloku else, czyli na przykÅ‚ad:
if(liczba == 1) return 10; else return 0;
Ale funkcjÄ™ dodaj() można zapisać proÅ›ciej – wystarczy tak:
int dodaj( int l1, int l2 ){
return l1 + l2;
}
Nie trzeba definiować żadnych zmiennych pomocniczych. No ale jak z tej funkcji skorzystać? Wystarczy napisać takie wywołanie funkcji:
int wynik; wynik = dodaj(10, 20);
Ale wynik dziaÅ‚ania tej funkcji nie musi być zachowywany w zmiennej – można go przenieść od razu do innej funkcji, tak że jedna funkcja staje siÄ™ argumentem innej. Na przykÅ‚ad można od razu wyÅ›wietlić wynik dodawania przez wstawienie funkcji dodaj() do funkcji System.out.println():
System.out.println(dodaj(10, 20));
Jako argument w wywołaniu funcji można podać wszystko co ma wartość odpowiedniego tyou, czyli na przykład wynik funkcji, zmienna lub konkretna wartość, np 10 dla typu int.
Trzeba pamiÄ™tać, że jeÅ›li parametry nie sÄ… tablicami ani żadnymi innymi typami zÅ‚ożonymi, to możemy mieć pewność, że te zmienne które przekazaliÅ›my jako parametry nie sÄ… tymi samymi zmiennymi co wewnÄ…trz funkcji. Fakt, majÄ… one tÄ… samÄ… wartość, ale zmiana jednych nie powoduje zmiany drugich. PrzykÅ‚ad – mamy funkcjÄ™:
void testowa( int arg ){
arg += 1;
}
Jak widać funkcja nic nie zwraca (jako zwracany typ podany jest void) i przyjmuje jeden argument całkowity. Teraz jak gdzieś w kodzie zrobimy coś takiego:
int wartosc = 10; System.out.println( wartosc ); testowa( wartosc ); System.out.println( wartosc );
To dwa razy wyÅ›wietli siÄ™ 10. Dlaczego? Przecież funkcja testowa zmienia swój argument?!? Fakt, zmienia swój argument, akurat o tej samej wartoÅ›ci co zmienna wartosc, a nie zmiennÄ… wartosc. Chodzi o to, że przy wywoÅ‚aniu funkcji z jakimiÅ› argumentami, tworzone sÄ… lokalne kopie tych zmiennych, dostÄ™pne tylko i wyłącznie w tej funkcji, nie majÄ…ce wpÅ‚ywu na to co jest na zewnÄ…trz (można wymusić takie ’sprzężenie’ zmiennych zewnÄ™trznych i wewnÄ™trznych, ale tego przypadku teraz nie rozpatrujemy).
Powyżej sÄ… podstawy teoretyczne. Teraz czas na praktykÄ™. Zadanie jest takie: “stwórz funkcjÄ™ generuj(), która nie przyjmuje żadnych argumentów, a zwraca dwuwymiarowÄ… tablicÄ™ liczb caÅ‚kowitych o wymiarach 10 na 10 elementów, wypeÅ‚nionÄ… losowymi elementami z przedziaÅ‚u 0 – 9″. Jak siÄ™ do tego zabrać? Na tym poziomie stworzenie tablicy z losowymi elementami o podanych wymiarach nie powinno sprawić problemu, ale dla pewnoÅ›ci napiszÄ™.
Najpierw tworzymy tablicÄ™ o wymiarach 10 na 10:
int[][] vec = new int[10][10];
Teraz trzeba jÄ… wypeÅ‚nić. Tablica ma wymiary 10×10, ale elementy od 0 do 9, wiÄ™c trzeba napisać odpowiednio zagnieżdżone 2 pÄ™tle for:
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
I co tu wstawić? Zmienne i i j bÄ™dÄ… kolejno przyjmowaÅ‚y wartoÅ›ci od 0 do 9, a wiÄ™c jeÅ›li w tej pÄ™tli można wykorzystać zmiennÄ… vec[i][j] i można być pewnym, że po wykonaniu tych pÄ™tli, jakakolwiek operacja na tej zmiennej bÄ™dzie dotyczyÅ‚a wszystkich elementów tablicy. Ale co do tej zmiennej przypisać? Trzeba użyć funkcji Math.random(). Ale ona zwraca liczby z przedziaÅ‚u 0 – 1, a do tego liczby rzeczywiste, co już zupeÅ‚nie nam nie pasuje. Najpierw trzeba pomnożyć wynik tej funkcji przez zakres – w naszym przypadku bÄ™dzie to 10. JeÅ›li wynikiem funkcji bÄ™dzie zero, to wynikiem mnożenia też bÄ™dzie zero. JeÅ›li wynikiem bÄ™dzie jeden, to wynikiem mnożenia bÄ™dzie 10. JeÅ›li natomiast wynikiem losowania bÄ™dzie liczba z przedziaÅ‚u 0 – 1, to wynikiem mnożenia bÄ™dzie liczba z przedziaÅ‚u 0 – 10. No ale to bÄ™dzie dalej liczba rzeczywista. Wynik naszego mnożenia Math.random() * 10 trzeba zamienić na liczbÄ™ caÅ‚kowitÄ…. JeÅ›li tego nie zrobimy, to Java bÄ™dzie siÄ™ czepiać, że może nastÄ…pić utrata precyzji (czyli utrata tych wszystkich cyferek po przecinku). Ale jeÅ›li napiszemy to jawnie przez tzw. rzutowanie (podanie nazwy typu, który chcemu uzyskać w nawiasie okrÄ…gÅ‚ym przed wartoÅ›ciÄ…), to Java nie bÄ™dzie miaÅ‚a nic do gadania. A wiÄ™c losowanie naszej liczby z przedziaÅ‚u 1 – 10 i przypisanie jej do elementu tablicy bÄ™dzie wyglÄ…daÅ‚o tak:
vec[i][j] = (int)(Math.random() * 10);
No więc teraz można poskładać w całość tworzenie tablicy i losowanie jej zawartości (to chyba każdy w tym momencie będzie potrafił zrobić sam). Ale jak narazie to jest zwykły kawałek kodu, a trzeba napisać jakąś definicję funkcji. Trzeba tylko poskładać wszystkie fakty:
- Funkcja ma zwracać tablicę dwuwymiarową, czyli typ int[][]
- Funkcja ma się nazywać generuj
- Funkcja ma nie przyjmować żadnych argumentów
Czyli nagłówek będzie wyglądał tak:
int[][] generuj() {
Ale funkcja zwraca jakąś wartość, a więc trzeba poinformować kompilator, że wynikiem działania funkcji generuj() będzie tablica vec. Jak to zrobić? Przy pomocy instrukcji return. A więc cała funkcja będzie wyglądała tak:
int[][] generuj(){
int[][] vec = new int[10][10];
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
vec[i][j] = (int)(Math.random() * 10);
}
}
return vec;
}
Funkcja jest już gotowa, ale jak jej użyć? Proste.
int[][] wylosowanaTablica = null; wylosowanaTablica = generuj();
Zadanie domowe:
- Jak przerobić tą funkcję, żeby pobierała jako parametr wielkość tej tablicy
jaką ma wygenerować? - Jak przerobić tą funkcję, żeby pobierała jako parametr zakres z jakiego
będą wylosowane elementy tablicy?
Teraz czas na coÅ› ambitniejszego, czego jeszcze chyba nie byÅ‚o przed funkcjami. Otóż trzeba znaleźć najwiÄ™kszÄ… wartość w tablicy dwuwymiarowej. Najważniejszy w tym przypadku jest pomysÅ‚ (ale że ten przykÅ‚ad jest strasznie wyeksplowatowany, to wystarczy lektura kilku książek o programowaniu). Trzeba wprowadzić jakÄ…Å› zmiennÄ… pomocniczÄ…, w której bÄ™dzie zachowana tymczasowa najwiÄ™ksza wartość – na poczÄ…tek bÄ™dzie to zero, a później jeśłi, znajdzie siÄ™ jakiÅ› wiÄ™kszy element tablicy, bÄ™dzie odpowiedno zmieniana. Teraz pewne zaÅ‚ożenia co do funkcji. Co o niej wiemy?
- Ma się nazywać max
- Ma przyjmować jako parametr tablicę dwywymiarową
- Ma zwracać pojedyńczą liczbę całkowitą
A więc początek definicji będzie wyglądał tak:
int max( int[][] vec ){
No i teraz trzeba jakoś to sprawdzić. Nie znamy wielkości tablicy vec, nie wiem czy jest prostokątna czy szarpana, więc do pętli for trzeba będzie wykorzystać zmienną vec.length dla ilości wierszy i vec[i].length dla długości każdego wiersza. No więc na początek trzeba zainicjować zmienną temp:
int temp = 0;
(Uwaga: 0 jest tu prawidłowe tylko jeśli tablica zawiera tylko liczby dodatnie). Dalej standardowa pętla przelatująca całą tablicę:
for(int i = 0; i < vec.length; i++){
for(int j = 0; j < vec[i].length; j++){
No i w tym miejscu trzeba wstawić jakiÅ› sprytny warunek – sÅ‚ownie to bÄ™dzie tak: jeÅ›li aktualnie sprawdzany element jest wiÄ™kszy od tego co jest w zmiennej temp, no to wiadomo, że to co jest w temp nie jest najwiÄ™ksze, bo to co jest w tym elemencie jest wiÄ™ksze, a wiÄ™c tymczasowo można przyjąć że to co jest w tym elemencie jest najwiÄ™ksze i przypisać to do temp. A w Javie bÄ™dzie to wyglÄ…daÅ‚o nastÄ™pujÄ…co:
if(vec[i][j] > temp) temp = vec[i][j];
No i po przewianiu całej tablicy mamy pewność, że to co jest w temp jest największą wartością występującą w tablicy. Teraz trzeba tylko zwrócić wynik działania naszej funkcji. A więc cała funkcja będzie wyglądała tak:
int max( int[][] vec ){
int temp = 0;
for(int i = 0; i < vec.length; i++){
for(int j = 0; j < vec[i].length; j++){
if(vec[i][j] > temp)
temp = vec[i][j];
}
}
return temp;
}
Zadanie domowe: jak należałoby zainicjować zmienną temp żeby ta funkcja działała także dla liczb ujemnych?
Funkcja suma(), którą też trzeba napisać, jest prawie identyczna jak poprzednia. Ma ona zwrócić sumę wszystkich elementów w tablicy dwuwymiarowej podanej jako argument funkcji. Czyli co trzeba zrobić? Trzeba poprostu każdy element dodać do jakiejś zmiennej tymczasowej. Czyli w poprzedniej funkcji wystarczy zamiast warunku i zmiany wartości temp napisać:
temp += vec[i][j];
No i oczywiście przydałoby się zmienić nazwę tej funkcji. Reszta pozostaje taka sama, więc nie będę się rozpisywał.
Kolejna funkcja do napisania to ileParzystych(). Także ona ma dostawać tablicÄ™ dwuwymiarowÄ… jako argument i ma zwrócić ilość elementów w tej tabeli, które sÄ… parzyste. No i jak to zrobić? Potrzebny jest nam jakiÅ› licznik, co by notować ile już naliczyliÅ›my tych parzystych elementów – oczywiÅ›cie na poczÄ…tku powinien mieć on wartość 0. No i teraz trzeba sprawdzić każdy element. JeÅ›li jest parzysty – to zwiÄ™kszamy licznik. Na koÅ„cu zwracamy licznik. Tutaj też można wykorzystać jako podstawÄ™ funkcjÄ™ max(), bo ona też ma zwracać int’a, dostawać dwuwymiarowÄ… tablicÄ™ intów, potrzebuje zmiennÄ… tymczasowÄ… i na każdym elemencie tablicy sprawdza jakiÅ› warunek i coÅ› robi w razie speÅ‚nienia tego warunku. Jak ma wyglÄ…dać ten warunek? Mniej wiÄ™cej tak:
if(vec[i][j]%2 == 0) temp++;
Czyli jeśli reszta z dzielenia jest równa 0 (czyli jeśli liczba jest podzielna przez 2, czyli liczba jest parzysta) nasza zmienna tymczasowa temp która w tej chwili jest traktowany jako licznik jest zwiększana o jeden. No i po całej pętli w zmiennej temp będzie się znajdowała liczba parzystych elementów tablicy, którą trzeba zwrócić. I to jest cała filozofia.
OstatniÄ… funkcjÄ… do przerobienia jest funkcja reverse(). Jest ona o tyle inna od poprzednich, że operuje na stringach – pobiera string i zwraca string. Ma ona string podany jako argument zwrócić, ale w postaci ‘od koÅ„ca’. PoczÄ…tek bÄ™dzie wiÄ™c wyglÄ…daÅ‚ tak:
String reverse(String str) {
To chyba nie jest problem. Trzeba sobie stworzyć jakiegoś tymczasowego stringa,
np. out :
String out = "";
I teraz trzeba sobie napisać Å‚adnÄ… pÄ™tlÄ™ for, która bÄ™dzie przerabiaÅ‚a wejÅ›ciowego stringa od koÅ„ca. WartoÅ›ci, jakie bÄ™dzie przyjmowaÅ‚ parametr pÄ™tli for, bÄ™dÄ… musiaÅ‚y być przekazane do funkcji charAt(), wiÄ™c muszÄ… siÄ™ zawierać w przedziale od 0 do (dÅ‚ugość stringa – 1) ponieważ znaki w stringu numerowane sÄ… od zera. Tylko że trzeba bÄ™dzie to zrobić od koÅ„ca, czyli najpierw bÄ™dzie (dÅ‚ugość stringa – 1) a na koÅ„cu 0. PÄ™tla bÄ™dzie wyglÄ…dałą tak:
for(int i = str.length() - 1; i >= 0; i--){
(i musi być >= 0, bo musi też przyjąć wartość 0). No i teraz trzeba kolejno każdy znaczek ze stringa wejściowego str dopisać na koniec stringa wyjściowego out:
out += str.charAt(i);
I po całej pętli trzeba zwrócić stringa wyjściowego. Cała funkcja:
String reverse(String str) {
String out = "";
for(int i = str.length() - 1; i >= 0; i--){
out += str.charAt(i);
}
return out;
}


Tagi:
Te funkcje w Javie nazywaja sie metdowami o ile mnie pamiec nie myli
Funkcje metodowe? Nie sÅ‚yszaÅ‚em o czymÅ› takim… Gógle też nic nie mówi na ten temat.