Operacje na tablicach w Javie
We wcześniejszych częściach szkolenia poznaliśmy już zarówno tradycyjne tablice, jak i ich dynamiczne odpowiedniki w postaci klasy ArrayList. Do tej pory mamy opanowane umiejętności, takie jak deklarowanie i inicjowanie nowej tablicy oraz dostęp do elementów poprzez operator []. W tej lekcji przyjrzymy się bliżej klasie Arrays, która dostarcza szeregu przydatnych metod do pracy z tablicami.
Klasa Arrays
W jej zestawie znajduje się cały szereg metod statycznych do wykonywania przeróżnych operacji na tablicach. Pierwsze spojrzenie w dokumentację może przytłaczać mnogością dostarczonych algorytmów. Jednakże gdy się dokładniej przyjrzymy, to zauważymy, że jest to spowodowane typami danych, które przechowują tablice. Z tego względu skupimy się na konkretnych czynnościach, a nie typach zmiennych przechowywanych w tablicach.
Zamiana tablicy String na listę
Operacja ta wymaga jedynie tablicy z obiektami typu String oraz wczytanie odpowiednich bibliotek.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.Arrays; import java.util.List; public class TestArrayToList { public static void main(String[] args) { String [] tabS = {"A", "B", "C"}; List<String> listS = Arrays.asList(tabS); System.out.print("Zawartość listy: " + listS); } } |
Rezultatem wykonania powyższego kodu będzie.
1 |
Zawartość listy: [A, B, C] |
Jak widać wystarczy użyć metody asList() dostępnej w klasie Arrays.
Zamiana tablicy zawierającej typy proste na listę
Analogiczna próba konwersji z dowolnego typu prostego na listę zakończy się niepowodzeniem. Jak nauczyliśmy się w rozdziale o klasach osłonowych do list można zapisywać jedynie obiekty. Dlatego typy proste należy najpierw opakować do odpowiednich im klas. Poniżej pokażemy przykład jak przekonwertować tablicę typu int na listę zawierającą obiekty Integer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.util.Arrays; import java.util.List; public class Test { public static void main(String[] args) { int [] tab = {1,2,3}; //rozmiar nowej tablicy musi być identyczny jak konwertowanej Integer [] tabI = new Integer[tab.length]; //każdy element tablicy musimy ręcznie opakować do nowej tablicy int i = 0; for(int item: tab) { tabI[i++] = Integer.valueOf(item); } List<Integer> listA = Arrays.asList(tabI); System.out.print("Zawartość listy: " + listA.toString()); } } |
Jak widać w tym przypadku potrzebujemy tablicy pośredniej, która będzie przechowywała obiekty. Dopiero ją możemy przekonwertować na listę.
Java 8
W Javie od wersji 8 możemy zrobić to nieco prościej wykorzystując strumienie.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Test { public static void main(String[] args) { int [] tab = {1,2,3}; List<Integer> listA = Arrays.stream(tab).boxed().collect(Collectors.toList()); System.out.print("Zawartość listy: " + listA.toString()); } } |
W obu przypadkach wynik wykonania kodu będzie następujący.
1 |
Zawartość listy: [1, 2, 3] |
Kopiowanie tablic
Jak pamiętamy przypisanie zmiennej tablicowej nie powoduje utworzenie kopii tablicy, a jedynie dodatkową referencję od niej. Inaczej mówiąc modyfikując tablicę przy użyciu pierwszej referencji zmienia także tablicę, na którą wskazuje druga. Nie ma w tym nic dziwnego – w końcu to ten sam obiekt w pamięci komputera.
W klasie Arrays dostępna jest metoda copyOf() dostępna w kilku wariantach – dla każdego typu w tym sparametryzowana. Tym razem użyjemy tablicy znakowej char.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import java.util.Arrays; public class Test { public static void main(String[] args) { char [] tab = {'o', 'l', 'd'}; char [] copy = Arrays.copyOf(tab, tab.length); System.out.println("Wynik zwrócony przez metodę equals: " + tab.equals(copy)); copy[0] = 'n'; copy[1] = 'e'; copy[2] = 'w'; System.out.println("Tablica tab: " + Arrays.toString(tab) + ", a tablica copy: " + Arrays.toString(copy)); } } |
Metoda equals() zwróciła false, co jest dowodem, że tym razem są to dwie tablice. Jak pamiętamy nie zwraca ona tylko czy zawartość jest identyczna, ale porównuje też kod mieszający (ang. hash code) obiektu. Ostatecznie jeśli zmodyfikujemy zawartość tablicy copy, to tablica tab pozostaje nienaruszona.
Sortowanie tablic
Stosując metodę sort() tablice są sortowane algorytmem quick sort. Implementacja zastosowana przez twórców zapewnia wysoką wydajność operacji O(n log(n)).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import java.util.Arrays; import java.util.Collections; public class Test { public static void main(String[] args) { char [] tab = {'c', 'd', 'e', 'a', 'b', 'f'}; //sortowanie w porządku rosnącym Arrays.sort(tab); System.out.println("Sortowanie w porządku rosnącym: " + Arrays.toString(tab)); //sortowanie w porządku malejącym Character [] tab2 = {'c', 'd', 'e', 'a', 'b', 'f'}; Arrays.sort(tab2, Collections.reverseOrder()); System.out.println("Sortowanie w porządku malejącym: " + Arrays.toString(tab2)); } } |
Sortowanie w porządku rosnącym (ang. ascending)
Ten porządek sortowanie jest domyślnym dla metody sort(). Jak widać na powyższym listingu wystarczy w argumencie przekazać tablicę do posortowania.
Sortowanie tablicy w porządku malejącym (ang. descending)
Java nie posiada domyślnie przygotowanej metody, która sortowałaby tablicę w porządku malejącym. Zamiast tego musimy dostarczy obiekt klasy Comparator, który wykona odpowiednie porównania. Z pomocą przychodzą klasy opakowujące gdyż jak pamiętamy nie można zaimplementować metody compareTo() dla typów prostych. Jest to możliwe jedynie dla typów obiektowych. Klasa Collection w metodzie reverseOrder() dostarcza komparator, który pozwala nam w prosty sposób odwrócić kolejność tablicy.
1 |
Arrays.sort(tab2, Collections.reverseOrder()); |
Jak widać wystarczy go dopisać jako argument do metody sort().
Wynik uruchomienia powyższego listingu jest następujący.
1 2 |
Sortowanie w porządku rosnącym: [a, b, c, d, e, f] Sortowanie w porządku malejącym: [f, e, d, c, b, a] |
Wypełnianie tablicy jedną wartością
Klasa Arrays dostarcza metodę fill(), która pozwala na wypełnienie całej tablicy lub jej fragmentu podaną wartością.
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; public class Test { public static void main(String[] args) { char [] tab = new char[10]; Arrays.fill(tab, 'a'); System.out.print("Zawartość tablicy: " + Arrays.toString(tab)); } } |
W powyższym przypadku pusta tablica zostaje zapełniona zmiennymi typu char o wartości 'a’. Metoda działa identycznie dla każdego typu danych. Należy tylko uważać na automatyczne konwersje
Wynik uruchomienia programu jest następujący.
1 |
Zawartość tablicy: [a, a, a, a, a, a, a, a, a, a] |