Jakiś czas temu poproszono mnie o pomoc przy kawałku bardzo prostego kodu, bardzo prostego oczywiście z mojej obecnej perspektywy.
Była tam jedna funkcja, która idealnie wpadła w cykl „studium przypadku”. Kod wyglądał mniej więcej tak:
public class Shadowing { private String name; String setname(String Name) { name = name; return name; } }
Oczywiście kod nie działał, jak powinien. Jednak kompilator nie zgłaszał żadnych błędów, bo od strony językowej wszystko gra. Natomiast błędów logicznych było tu kilka, temu kawałek kodu wylądował na blogu.
Nazwy funkcji i zmiennych
Zacznijmy od kwestii nazewnictwa. Plus tego kodu jest taki, że zmienne są po angielsku, nie po polsku. Natomiast po pierwsze pamiętajmy, by używać camelCase przy wieloczłonowych nazwach funkcji i zmiennych.
Kolejna sprawa, mniej oczywista. Java jest czuła, na rozmiar liter. Tzn. Name pisane z wielkiej, to nie to samo co name pisane z małej.
Wprowadzając powyższe poprawki nasz kod settera nieco się poprawia:
public class Shadowing { String name; String setName(String name) { name = name; return name; } public static void main(String[] args) { Shadowing s = new Shadowing(); s.setName("Paweł"); System.out.println(s.name); } }
Natomiast wciąż nie działa.
Przesłanianie zmiennych
W programowaniu, w wielu językach funkcjonuje coś takiego jak przesłanianie zmiennych. Zachodzi ono, gdy mamy zmienną o takiej samej nazwie, jak stan obiektu to operując w zakresie.
W naszym przykładzie mamy ’name’ jako pole klasy, jak i jako parametr metody (czyli zmienną lokalną dla tej metody).
public class Shadowing { String name; String setName(String name) { name = name; return name; } }
W takiej sytuacji używając ’name’ odnosimy się zawsze do lokalnej zmiennej. Jeśli chcemy odnieść się do stanu obiektu, to musimy użyć this.
Powyższy kod nie spełniał swojego zadania, bo efektywnie przypisywaliśmy wartość lokalnej zmiennej name do niej samej. Poprawiony kod:
package pl.clockworkjava.scrapbook; public class Shadowing { String name; String setName(String name) { this.name = name; return name; } public static void main(String[] args) { Shadowing s = new Shadowing(); s.setName("Paweł"); System.out.println(s.name); } }
Konwencja JavaBeans
W ekosystemie Javy istnieje kilka zasad w konwencji JavaBeans. W sumie podstawową jaką trzeba z niej wynieść jest fakt, że pobieramy wartość zmiennej za pomocą metod zwanych „getterami”, a zmieniamy za pomocą „setterów”.
Można się z nią zgadzać, można się z nią nie zgadzać, nie zawsze ma zastosowanie. (np. settery w obiektach niezmiennych zwracające kopie obiektu). Natomiast jest to pewna żelazna podstawa, która musi każdy początkujący adept programowania opanować, zanim zacznie ją łamać.
W naszym przypadku setter zwracał wartość, a nie powinien. Do tego powinniśmy dorobić getter.
package pl.clockworkjava.scrapbook; public class Shadowing { private String name; public void setName(String name) { this.name = name; } public String getName() { return this.name; } public static void main(String[] args) { Shadowing s = new Shadowing(); s.setName("Paweł"); System.out.println(s.getName()); } }
Teraz to już jakoś wygląda.
Przykład ten nie służy napiętnowaniu kogokolwiek. Powinien służyć za przykład, że programowanie to nie taka prosta sprawa, zwłaszcza dla osób początkujących. Cały ten wpis poświęcony był ilości błędów, jakie można zrobić przy napisaniu prostego settera… i ilości różnej wiedzy, jaką trzeba mieć, żeby to porządnie zrobić.
By być na bieżąco i mieć realny wpływ na tematykę tworzonych artykułów zapraszam do dołączenia do mojego newslettera.
W IJIdea skrót alt+ins wygeneruje nam ładne mutatory i akcesory (settery i gettery) a nawet konstruktor z wybranymi parametrami. Warto sobie wygenerować taki kod i przyjrzeć mu się. Pozdrawiam.