Java - metoda nie dodaje poprawnie liczb, pomoc potrzebna
Zostałem poproszony o rozwiąznie problemu. Jak najłatiwej wyjaśnić ten problem? Problem opisze poniżej.
Potrzebuje pomocy przy sumowaniu tablicy intów, mam kod:
public class SumowanieTablicy {
public static void main(String[] args) {
int suma = 0;
int[] stanKonta = {10, 20, 30};
System.out.println(suma); // 0
sumownie(suma, stanKonta);
System.out.println(suma); // 0
}
static void sumownie(int suma, int[] stanKonta) {
for (int i = 0; i < stanKonta.length; i++) {
suma += stanKonta[i];
}
}
}
Wynik:
0
0
Naprawa tego problemu polega na tym, że mając sumę typu int, nie powinniśmy jej przekazywać do metody jako parametr, tylko sumę definować w metodzie i zwracać z return.
public class SumowanieTablicyFix {
public static void main(String[] args) {
int[] stanKonta = {10, 20, 30};
int suma = sumownie(stanKonta);
System.out.println(suma); // 60
}
static int sumownie(int[] stanKonta) {
int suma = 0;
for (int i = 0; i < stanKonta.length; i++) {
suma += stanKonta[i];
}
return suma;
}
}
Wynik:
60
Wyjaśnienie - wartość vs referencja
Cały błąd w kodzie wynika z tego, że w javie typy proste przekazywane są poprzez wartości a obiekty i tablice przez referencje. Bardzo często na początku jest z tym dość dużo problemów, tzn ze zrozumieniem tego, jak to do końca działa. Polecam bawić się przykładami i zrozumieć to na przykładach. Teorie tylko poczytać, aby wspomagać przykłady.
Tutaj znalazłem ciekawy gif obrazujący różnicę pomiędzy przekazywaniem argumentów do metody przez wartość a przekazywaniem przez referencje.
https://twitter.com/codingninja4/status/1300942494637723648
Na tym gifie widzimy kubek kawy i co się z nim dzieje kiedy przekazujemy go do metody. Kiedy kubek kawy przekazwywany jest przez 'value' - wartość, to działamy na kopi. Czyli przekazujemy naszej metodzie zmienną suma z wartością 0, w metodzie zmieniamy tą wartość na 5 i z metody nie zwracamy nic (metoda nie ma return, ma void-a). Wtedy po wyjściu z metody, spowrotem do funkcji main, nasza zamienna będzie wynosiła 0. Tutaj właśnie trzeba używać return i przypisać w main naszą zmienną do int-a.
Przykład:
public class PrzekazywanieInta {
public static void main(String[] args) {
int liczba = 2;
System.out.println("Krok A: " + liczba); // 2
tenIntSieNieZmieni(liczba);
// i tutaj nasza zmienna się nie zmieniała na 5, tylko wynosi nadal 2
// ponieważ typy proste int, double, boolean tak działają w javie
System.out.println("Krok D: " + liczba); // 2
}
static void tenIntSieNieZmieni(int liczba) {
System.out.println("Krok B: " + liczba); // 2
liczba = 5;
// tylko przez chwile w tej metodzie nasza liczba wynosi 5
// obiecuje, że nabierze to sensu z czasem
System.out.println("Krok C: " + liczba); // 5
}
}
Wynik:
Krok A: 2
Krok B: 2
Krok C: 5
Krok D: 2
W komentarzach postarałem się to wyjaśnić maksylanie prosto dla początkującego programisty.
A teraz przykład, który ma metodę z return i nasza zmienna się zmieni.
public class PrzekazywanieIntaNaprawione {
public static void main(String[] args) {
int liczba = 2;
System.out.println("Krok A: " + liczba); // 2
liczba = tenIntSieNieZmieni(liczba);
System.out.println("Krok D: " + liczba); // 5
}
static int tenIntSieNieZmieni(int liczba) {
System.out.println("Krok B: " + liczba); // 2
liczba = 5;
System.out.println("Krok C: " + liczba); // 5
return liczba;
}
}
Wynik:
Krok A: 2
Krok B: 2
Krok C: 5
Krok D: 5
Ten przykład może mieć zastosowanie, gdy np przekazujemy do metody int-a i mamy jakieś warunki np jeśli liczba jest równa 2 to zmień ją na 5, a jeśli nie to nic nie rób. I jeśli nie użyjemy return i nie przypiszemy tej liczy w main, to nasza liczba niestety się nie zmieni.
Warto poćwiczyć to na przykładach bardzo małych z 1 zmienną. I zrobić ich z 20 sztuk. Plus dać sobie czas na oswojenie z tym. Czasem programiści z rocznym doświadczeniem popełniają takie błędy.
Jeśli będą jakie kolwiek problemy ze zrozumieniem, dodaj pytanie z przykładowym kodem, bardzo chętnie pomogę 👍.