Massiiv
Sissejuhatus
Massiiv (array) on järjestatud andmete kogum. Javas massiiv on kindla suurusega ning saab koosneda ainult sama tüüpi elementidest.
Iga element massiivis on nummerdatud. Esimese elemendi indeks on 0, teise elemendi indeks on 1 jne. Viimase elemendi indeks on massiivi pikkus lahutatud ühega. Igale konktreetsele elemendile viitamiseks saab kasutada selle indeksit massiivis.
Järgnev joonis on piltlik näide massiivist, mis koosneb viiest elemendist:
Massiivil on kindel pikkus ehk kindel arv elemente, mis massiivi maksimaalselt mahuvad. Massiivi pikkust ei saa muuta.
Massiivi loomine
Massiivide deklareerimiseks kasutatakse nurksulge ([]), mis lisatakse mingi andmetüübi lõppu.
Näiteks:
int[] numbers;
String[] names;
double[] prices;
Kui me soovime näiteks luua täisarvude massiivi someNumbers, siis saaksime selle deklareerida nii:
int[] someNumbers = new int[10];
Sellisel juhul on massiivi elemendi tüüp int (täisarv).
Lisaks määratakse ka massiivi pikkus, milleks on 10 elementi ehk reserveeritakse massiivile nii palju mälu.
Esimene element on someNumbers[0].
Esimese elemendi saaks väärtustada nii:
someNumbers[0] = 5;
Massiivi on võimalik luua ka algväärtustega:
int[] someNumbers = {10, 20, 33, 47, 99, 101};
String[] someWords = {"Hello", "new", "array"};
Sellisel juhul luuakse uus massiiv, mille pikkus on 6. See on samaväärne sellega:
int[] someNumbers = new int[6];
someNumbers[0] = 10;
someNumbers[1] = 20;
someNumbers[2] = 33;
someNumbers[3] = 47;
someNumbers[4] = 99;
someNumbers[5] = 101;
Viimast viisi saab kokku panna ka new märksõnaga
int[] numbers = new int[]{1, 2, 3, 4, 5};
String[] names = new String[]{"Ago", "Taavi", "Mari"};
See variant on kasulik, kui massiiv edastatakse meetodi argumendina:
printArray(new int[]{1, 2, 3}); // Works
printArray({1, 2, 3}); // Compile error
Elementidele ligipääs
Massiivi elementidele pääseb ligi nurksulgude ja indeksi abil. Java massiivide indekseerimine algab nullist.
int[] numbers = {10, 20, 30, 40, 50};
// Read elements
int first = numbers[0]; // 10
int third = numbers[2]; // 30
int last = numbers[4]; // 50
// Write elements
numbers[1] = 25; // Writes to the second element
numbers[3] = 45; // Writes to the fourth element
System.out.println(numbers[1]); // 25
System.out.println(numbers[3]); // 45
Kui proovida pääseda ligi elemendile, mis jääb väljapoole massiivi piire, tekib ArrayIndexOutOfBoundsException viga:
int[] numbers = {1, 2, 3};
System.out.println(numbers[0]); // OK - 1
System.out.println(numbers[2]); // OK - 3
System.out.println(numbers[3]); // Error - Index out of bounds
System.out.println(numbers[-1]); // Error - Negative indexes not allowed in Java
Vea näide:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
Massiivi pikkus
Massiivi pikkuse leidmiseks saab kasutada: int len = someNumbers.length;
Massiiv on objekt, mille avalik read-only isendimuutuja nimega length sisaldab massiivi pikkust.
int[] numbers = {10, 20, 30, 40, 50};
System.out.println(numbers.length); // 5
String[] names = new String[10];
System.out.println(names.length); // 10
Massiivi pikkust kasutatakse sageli tsüklites, et vältida indeksi piiride ületamist:
int[] numbers = {10, 20, 30, 40, 50};
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
Iteratsioon üle massiivide
Massiivide tsükliga läbimiseks on Javas mitu võimalust.
Klassikaline for-tsükkel
Antud juhul kasutatakse indeksit, et massiivi läbida:
int[] numbers = {10, 20, 30, 40, 50};
for (int i = 0; i < numbers.length; i++) {
System.out.println("Element at index " + i + ": " + numbers[i]);
}
// Element at index 0: 10
// Element at index 1: 20
// Element at index 2: 30
// Element at index 3: 40
// Element at index 4: 50
Antud lähenemine on kasulik, kui:
- Tegevused sõltuvad elemendi indeksist
- Massiivi peab läbima tagurpidi või hüppeliselt
- On vaja muuta massiivi elemente
Näide tagurpidi läbimisest:
for (int i = numbers.length - 1; i >= 0; i--) {
System.out.println(numbers[i]);
}
Täiustatud for-tsükkel (for-each)
Alates Java versioon 5-st on võimalik massiive (ja ka muid kollektsioone) läbida järgnevalt:
int[] numbers = {10, 20, 30, 40, 50};
for (int number : numbers) {
System.out.println(number);
}
Antud lähenemine on kasulik kui on lihtsalt vaja kõik elemendid algusest lõpuni läbi käia ning elementide asukoht ei oma tähtsust.
Levinud operatsioonid massiividega
Massiivi printimine
Massiivi otse ei saa printida, sisu asemel kuvatakse mäluviide:
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(numbers); // [I@1a2b3c4d (for example)
Selle jaoks on olemas meetod Arrays.toString():
import java.util.Arrays; // Has to be imported at the beginning of the java file
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(numbers)); // [1, 2, 3, 4, 5]
Massiivi kopeerimine
Massiivi omistamisel kopeeritakse viide, mitte massiivi sisu:
int[] original = {1, 2, 3};
int[] copy = original; // Copies the reference
copy[0] = 999;
System.out.println(original[0]); // 999 - Both arrays point to same location in memory
Sisu kopeerimiseks on mitu viisi:
Manuaalne kopeerimine
int[] original = {1, 2, 3, 4, 5};
int[] copy = new int[original.length];
for (int i = 0; i < original.length; i++) {
copy[i] = original[i];
}
NB: Antud viisi saab ka adapteerida massiivi ümber pööramiseks. Selleks tuleb tsükkli sees copy massiivi sihtindeksit muuta, näiteks: copy[original.length - 1 - i] = original[i];
Spetsiaalsed meetodid
Lisaks on olemas ka paar meetodit, mis teevad selle töö ära: Arrays.copyOf(), System.arraycopy() ka clone()
int[] original = {1, 2, 3, 4, 5};
int[] copy = Arrays.copyOf(original, original.length);
copy[0] = 999;
System.out.println(original[0]); // 1 - original is unmodified
System.out.println(copy[0]); // 999
int[] original = {1, 2, 3, 4, 5};
int[] copy = new int[original.length];
System.arraycopy(original, 0, copy, 0, original.length);
int[] original = {1, 2, 3, 4, 5};
int[] copy = original.clone();
Massiivi suurendamine/kahandamine
Java massiivid on fikseeritud suurusega – pärast massiivi loomist selle pikkust muuta ei saa. Kui on vaja massiivi suurendada või kahandada, tuleb luua uus soovitud pikkusega massiiv ja kopeerida olemasolevad elemendid sinna ümber.
Massiivi suurendamisel luuakse suurem massiiv ning olemasolevad elemendid kopeeritakse uude massiivi.
Ülejäänud kohad täidetakse vaikimisi väärtustega (nt 0, false, null).
Massiivi kahandamisel kopeeritakse ainult osa elementidest uude, väiksemasse massiivi.
Näiteks:
int[] initialSmall = {1, 2, 3};
int[] larger = Arrays.copyOf(initialSmall, 5);
System.out.println(Arrays.toString(larger)); // [1, 2, 3, 0, 0]
int[] initialLarge = {1, 2, 3, 4, 5};
int[] smaller = Arrays.copyOf(initialLarge, 3);
System.out.println(Arrays.toString(smaller)); // [1, 2, 3]
Selle saavutamiseks on võimalik kasutada ka System.arraycopy meetodit:
int[] initialArray = {1, 2, 3};
int[] newArray = new int[5];
System.arraycopy(initialArray, 0, newArray, 0, initialArray.length);
Mitmemõõtmelised massiivid
Massiivid võivad hoida endas ka mitut tulpa, selliseid massiive nimetatakse mitmemõõtmelisteks. Näiteks võib kahemõõtmelist massiivi ette kujutada kui Exceli tabelit või maatriksit, milles on read ja veerud.
Mitmemõõtmelist massiivi initsialiseerides peab määrama kõikide massiivide suurused.
Kahemõõtmeline massiiv
Kasutame näitena kahemõõtmelist massiivi.
Tegelikuses saab ka näiteks kolme- või neljamõõtmelisi massiive koostada.
Kahemõõtmelisest massiivist saab mõelda kui ridade ja veergude maatriksist:
Sisemiselt mis toimub - kui luua näiteks massiiv A = new int[3][3], siis A viitab massiivile, milles on 3 elementi ning iga element viitab massiivile, milles on 3 täisarvu (int).
Maatriksite loomine
Selliseid maatrikse saab luua järgnevalt:
// Set values directly,
// creates a matrix like in the visualization above
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Initialize with default values
int[][] matrix2 = new int[3][4]; // 3 rows, 4 columns
// Jagged array, each row is is initialized separately,
// allowing each row to have different length
int[][] jagged = new int[3][];
jagged[0] = new int[]{1, 2};
jagged[1] = new int[]{3, 4, 5};
jagged[2] = new int[]{6, 7, 8, 9};
Elementidele ligipääs maatriksis
Kahemõõtmelises massivis kasutatakse kahte indeksit: [rida][veerg]
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println(matrix[0][0]); // 1 - First row, first column
System.out.println(matrix[0][2]); // 3 - first row, third column
System.out.println(matrix[1][1]); // 5 - Second row, second column
System.out.println(matrix[2][0]); // 7 - Third row, first column
// Modifying elements
matrix[1][1] = 50;
System.out.println(matrix[1][1]); // 50
Itereerimine üle maatriksi
Kahemõõtmelise massiivi läbimiseks on vaja kahte tsüklit:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i < matrix.length; i++) { // Iterate rows
for (int j = 0; j < matrix[i].length; j++) { // Iterate columns
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
// output:
// 1 2 3
// 4 5 6
// 7 8 9