Rozdział 6 - Tablice - Definiowanie i używanie tablic

Tablice definiujemy w następujący sposób:

typ[] nazwaZmiennej;

Przykładowo, tablica, która może przechowywać liczby typu int, to:

int[] mojaTablica;

Różnica względem tego, jak do tej pory definiowaliśmy zmienne, jest taka, że po nazwie typu umieściliśmy nawiasy kwadratowe – wskazuje to kompilatorowi, że zmienna mojaTablica jest tablicą. Zauważmy, że zmienna mojaTablica nie jest typu int, lecz jest tablicą, która może przechowywać wiele elementów typu int.

Zanim będziemy mogli używać tablicy, musimy ją utworzyć. Aby to zrobić, możemy:

  • utworzyć tablicę za pomocą nowego słowa kluczowego new, podając ile maksymalnie elementów będzie ona mogła przechowywać,
  • zainicjalizować tablicę w momencie jej definiowania wartościami zawartymi w nawiasach klamrowych,
  • skorzystać z rozwiązania będącego połączeniem dwóch powyższych – utworzenia nowej tablicy z pomocą słowa kluczowego new wraz z podaniem początkowych elementów, z których tablica ma się składać.

Spójrzmy na przykład każdego z powyższych sposobów:

Nazwa pliku: TworzenieIUzywanieTablic.java
public class TworzenieIUzywanieTablic {
  public static void main(String[] args) {
    // tablica, ktora moze przechowywac maksymalnie 5 wartosci calkowitych
    int[] calkowite = new int[5];

    // tablica, ktora moze przechowywac maksymalnie 3 wartosci rzeczywiste
    //  wstepnie zainicjalizowane wartosciami 3.14, 5, -20.5
    double[] rzeczywiste = { 3.14, 5, -20.5 };

    // tablica, ktora bedzie mogla przechowywac ciagi znakow
    // na razie nie podalismy, ile wartosci typu String
    // ta tablica bedzie mogla przechowywac
    String[] slowa;

    // tworzymy tablice, ktora bedzie mogla miec maksymalnie
    // trzy elementy, i inicjalizujemy ja trzema elementami,
    // kolejno: Ala, ma, kota
    slowa = new String[] { "Ala", "ma", "kota" };
  }
}

W powyższym programie utworzyliśmy trzy tablice – spójrzmy, w jaki sposób to osiągnęliśmy:

  1. Pierwsza tablica, calkowite, może przechowywać maksymalnie 5 wartości o typie int. Należy tutaj zwrócić uwagę, że użyliśmy nowego słowa kluczowego new, aby utworzyć tablicę – po nim następuje nazwa typu, jaki ma przechowywać tablica, a w nawiasach kwadratowych – z ilu elementów podanego typu tablica będzie mogła się składać.
  2. Druga tablica, o nazwie rzeczywiste, może przechowywać maksymalnie 3 wartości o typie double. Ta druga tablica została zainicjalizowana trzema wartościami typu double, które zostały zawarte w nawiasach klamrowych { }: 3.14, 5, -20.5 – w tej właśnie kolejności.
  3. Ostatnia tablica, o nazwie slowa, to tablica wartości typu String. Zauważmy, że nie zainicjalizowaliśmy tej tablicy żadną wartością – dopiero w linii poniżej korzystamy ze słowa kluczowego new, jak w przypadku tablicy calkowite, z tym, że nie podaliśmy rozmiaru tablicy – zamiast tego, po nawiasach kwadratowych [ ], podaliśmy w nawiasach klamrowych { } wartości, jakimi elementy tablicy mają zostać zainicjalizowane.

Przykładowa reprezentacja tablicy rzeczywiste mogłaby być następująca:

Indeks 0 1 2
Wartość 3.14 5 -20.5

Co ważne, rozmiar każdej z powyższych tablic został ustalony w momencie ich tworzenia – tablica calkowite ma ustalony rozmiar pięciu elementów, a tablice rzeczywiste i slowa – trzy elementy.

Drugi z powyższych sposobów można użyć tylko w momencie inicjalizacji tablicy. W poniższym kodzie, druga linia spowodowałaby błąd kompilacji:

double[] rzeczywiste = { 3.14, 5, -20.5 };
reczywiste = { 1, 2, 3 }; // blad kompilacji!

Kiedy stosować każdy z tych sposobów?

  1. Jeżeli nie mamy konkretnych wartości początkowych, którymi chcemy zainicjalizować tablicę, korzystamy z pierwszego sposobu – podajemy liczbę elementów, które tablica będzie mogła przechowywać. Wartości konkretnych elementów przypiszemy w dalszej części programu.
  2. Jeżeli znamy konkretne wartości, które tablica ma przechowywać, możemy użyć drugiego sposobu (podania wartości w nawiasach klamrowych) podczas definiowania tablicy.
  3. Trzeciego sposobu możemy użyć, jeżeli chcemy w jednym kroku utworzyć tablicę i zainicjalizować ją pewnymi wartościami, ale nie w momencie definiowania zmiennej.

Mając już zmienne tablicowe, spójrzmy teraz, jak odnieść się do ich poszczególnych elementów.

Tablice można też definiować z nawiasami kwadratowymi zapisanymi po nazwie zmiennej, zamiast po typie:
int mojaTablica[];
My będziemy jednak stosować sposób definiowania tablic, w którym nawiasy kwadratowe stawiamy po nazwie typu.

Odnoszenie się do elementów tablicy

Aby odnieść się do poszczególnych elementów tablicy, używamy operatora [ ] (nawiasy kwadratowe), któremu podajemy indeks elementu, do którego chcemy się odnieść.

Elementy tablicy w języku Java, a także w wielu innych językach programowania, zaczynają się od indeksu 0, a nie 1!

Przykład użycia tablic z programu o definiowaniu i tworzeniu tablic:

Nazwa pliku: TworzenieIUzywanieTablic.java
// ustawiamy wartosc pierwszego, drugiego, i piatego elementu tablicy
calkowite[0] = 10;  // pierwszy element ma indeks 0 (a nie 1)!
calkowite[1] = 15;
calkowite[4] = 200; // piaty element ma indeks 4 (a nie 5)!

System.out.println(
    "Suma dwoch pierwszych elementow to " + (calkowite[0] + calkowite[1])
);

// zmieniamy wartosc pierwszego elementu
rzeczywiste[0] = 100;
System.out.println(
    "Pierwszy element tablicy rzeczywiste = " + rzeczywiste[0]
);

// zmieniamy pierwszy i trzeci (czyli ostatni) element
slowa[0] = "Ania";
slowa[2] = "psa";
System.out.println(slowa[0] + " " + slowa[1] + " " + slowa[2]);

Wynik działania:

Suma dwoch pierwszych elementow to 25 Pierwszy element tablicy rzeczywiste = 100.0 Ania ma psa

Z pomocą użycia operatora [ ] możemy zarówno wskazać element, który chcemy zmienić, jak i element, który chcemy pobrać z tablicy. Zwróćmy jeszcze raz uwagę, że pierwszy element w każdej tablicy ma indeks 0, a nie 1, oraz ostatni element ma indeks o jeden mniejszy, niż liczba wszystkich elementów w tablicy.

Jeżeli spróbowalibyśmy odnieść się do elementu tablicy, podając indeks, który wykracza poza zakres tablicy, to wykonanie naszego programu zakończy się błędem:

Nazwa pliku: WyjsciePozaZakresTablicy.java
public class WyjsciePozaZakresTablicy {
  public static void main(String[] args) {
    int[] tablica = { 1, 2, 3 };

    // element o indeksie 3 nie istnieje!
    // ostatni (trzeci) element tablicy ma indeks 2
    // kod sie skompiluje,
    // ale w trakcie dzialania programu pojawi sie blad
    System.out.println(tablica[3]);
  }
}

Po uruchomieniu programu zobaczymy następujący błąd:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 at WyjsciePozaZakresTablicy.main(WyjsciePozaZakresTablicy.java:8)

Java poinformowała nas, że wyszliśmy poza zakres tablicy (a także wskazała numer problematycznej linii kodu). W wyniku wystąpienia tego błędu, nasz program zakończył działanie.

Nazwa tego konkretnego błędu, to ArrayIndexOutOfBoundsException – jest to dość często widywany błąd – jeszcze nie raz go zobaczymy!

Zwróćmy jeszcze uwagę, że kompilator nie miał obiekcji odnośnie powyższego programu. Z punktu widzenia kompilatora, nasz program jest poprawny – nie ma w nim żadnych błędów składniowych. Błąd wydarzył się dopiero w momencie działania programu – tego typu błędu są zdecydowanie gorsze, niż błędy wskazywane przez kompilator, ponieważ ujawniają się dopiero w momencie działania programu, często wtedy, gdy korzystają z niego nasi użytkownicy.

Domyślne wartości w tablicach

Pytanie: jeżeli utworzymy tablicę 5 elementów, nie podając, jakie wartości mają być w niej na wstępie przechowywane, to jakie wartości będą pod kolejnymi indeksami 0, 1, 2, 3, 4?

Wartości tablic inicjalizowane są domyślną wartością danego typu. W przypadku typów liczbowych jest to 0, dla typu boolean jest to false, a dla typów złożonych (takich jak String) jest to wartość null, o której dokładnie opowiemy sobie w rozdziale o klasach. Spójrzmy na poniższy przykład:

Nazwa pliku: DomyslneWartosciWTablicach.java
public class DomyslneWartosciWTablicach {
  public static void main(String[] args) {
    int[] calkowite = new int[5];

    calkowite[0] = 10;
    calkowite[1] = 15;

    // trzeci element nie byl ustawiony - bedzie mial
    //  domyslna wartosc typu int, czyli 0
    System.out.println("Trzeci element: " + calkowite[2]);
  }
}

W wyniku uruchomienia tego programu, na ekranie zobaczymy:

Trzeci element: 0

Jak widzimy, trzeci element ma wartość 0 – nie ustawiliśmy nigdzie tej wartości – została domyślnie nadana wszystkim elementom tablicy calkowite w momencie jej tworzenia za pomocą słowa kluczowego new. Potem zmieniliśmy dwa pierwsze elementy, nadając im wartości 10 i 15. Pozostałe trzy elementy nadal mają wartość 0.

Zmienne, które definiowaliśmy do tej pory, nigdy nie miały wartości domyślnych – zawsze trzeba było przypisać zmiennej pewną wartość, zanim tej zmiennej mogliśmy zacząć używać. Jak widzimy powyżej, elementy tablic zachowują się inaczej i mają nadawane wartości domyślne.

Sprawdzanie liczby elementów tablicy

Zmienną tablicową można "odpytać" o liczbę elementów, które przechowuje, korzystając z atrybutu tablicy o nazwie length:

Nazwa pliku: SprawdzRozmiarTablicy.java
public class SprawdzRozmiarTablicy {
  public static void main(String[] args) {
    int[] calkowite = new int[5];
    double[] rzeczywiste = { 3.14, 5, -20.5 };

    System.out.println(
      "Liczba elementow w tablicy calkowite: " + calkowite.length
    );

    System.out.println(
      "Liczba elementow w tablicy rzeczywiste: " + rzeczywiste.length
    );
  }
}

Wynik działania tego programu:

Liczba elementow w tablicy calkowite: 5 Liczba elementow w tablicy rzeczywiste: 3

Aby sprawdzić rozmiar tablicy, korzystamy z atrybutu o nazwie length, do którego odnosimy się poprzez napisanie kropki po nazwie tablicy.

W jednym z poprzednich rozdziałów zobaczyliśmy, że zmienną typu String także możemy odpytać o liczbę znaków, z których się składa, i także stosujemy w tym celu length – jest jednak znacząca różnica pomiędzy sprawdzaniem liczby znaków w stringach a liczbą elementów w tablicy.

W przypadku stringów, korzystamy z metody length, więc po jej nazwie musimy zawsze podać nawiasy ( ). W przypadku tablic, korzystamy z atrybutu length, więc z nawiasów nie korzystamy. O różnicach pomiędzy metodami a atrybutami porozmawiamy w rozdziale o klasach.

Spójrzmy na przykład użycia length na tablicy i na zmiennych typu String:

Nazwa pliku: RozmiarStringITablicy.java
public class RozmiarStringITablicy {
  public static void main(String[] args) {
    String tekst = "Witajcie!";

    String[] slowa = { "Ania", "ma", "kota" };

    System.out.println("Liczba slow w zmiennej tekst: " + tekst.length());

    System.out.println("Liczba elementow w tablicy: " + slowa.length);

    System.out.println(
      "Liczba znakow w pierwszym slowie z tablicy: " + slowa[0].length()
    );
  }
}

Wynik działania tego przykładu jest następujący:

Liczba slow w zmiennej tekst: 9 Liczba elementow w tablicy: 3 Liczba znakow w pierwszym slowie z tablicy: 4

Zwróćmy uwagę, że w pierwszej instrukcji System.out.println wypisujemy na ekran liczbę znaków w łańcuchu tekstowym – korzystamy więc z length() z nawiasami.

W kolejnej instrukcji System.out.println, wypisujemy liczbę elementów tablicy – korzystamy więc z length bez nawiasów.

W ostatniej instrukcji System.out.println odnosimy się do pierwszej wartości zawartej w tablicy – wartość ta jest typu String, bo tak została zdefiniowana tablica slowa – przechowuje ona wartości typu String. Sprawdzamy, ile znaków ma pierwszy element (pierwszy string w tej tablicy) za pomocą length() – z nawiasami, bo działamy na wartości typu String.

Komentarze (2):

  1. Wspaniały jest ten kurs - bardzo za niego dziękuję!
    W ostatnim przykładzie pierwszy sout powinien być chyba: "Liczba ZNAKOW w zmiennej tekst: "

    Pozdrawiam
    Michał

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Nie musisz podawać swojego imienia, e-mailu, ani strony www, aby opublikować komentarz. Komentarze muszą zostać zatwierdzone, aby były widoczne na stronie.