Tippek a kód jobbá tételére

Nagyjából véglegesítettem a nagy programom kódját, még egy problémára várom a választ a mentoromtól. A NetBeans azonban a forráskód számos részéhez fűzött megjegyzést, hogy mivel lehetne jobbá tenni a szoftvert. Olyan megoldásokat javasolt, mint pl. a funkcionális programozás, lambda kifejezések stb., amiről volt szó a StudiCore Java tanfolyamán is. Az oktatószoftver felületén látható a részletes bontás, hol tanultunk róla, például a 42. fejezet a Rekurzió: a programozás magasiskolája.

Ezek a témák azonban sokkal hatalmasabbak annál, hogy egy alap Java képzés részévé váljanak, ezért mi is megtanultuk, miről van szó, és alapvető lambda kifejezéseket írtunk, vagy rekurzív programrészeket készítettünk, illetve még számos hasonlóan fejlett programozói eszközről tanultunk. De egyelőre ennyit tudok róluk, és azért nem írom át a nagy program kódját a NetBeans javaslatai alapján, mert azzal nem én oldanám meg a feladatot, így nem tanulnék belőle semmit. Hamarosan visszatérek ezekre a részekre, és addig gyakorlom, míg magamtól is meg tudom csinálni.

Volt pár olyan javaslat is, amikor pedig a NetBeans tippeket adott a változónevek használatára, erről is mutatok példát.

De nézzük, miről van szó:

Funkcionális programozás

A NetBeans arra figyelmeztet, hogy funkcionális programozást is lehetne használni az általam megírtak helyett. Az én kódom:

private void fillData() throws SQLException {
   vats = vatController.getAllVats();
   for (Vat vat : vats) {
      vatComboBox.addItem(vat);
   }
   customers = customerController.getAllCustomers();
   for (Customer customer : customers) {
      customerNameComboBox.addItem(customer);
   }
   companies = companyController.getAllCompanies();
   for (Company company : companies) {
      companyNameComboBox.addItem(company);
   }
   employees = employeeController.getAllEmployees();
   for (Employee employee : employees) {
      employeeComboBox.addItem(employee);
   }
   double rate = getRateToFill();
   rateField.setText(String.valueOf(rate));
 }

Az általa javasolt kód:

private void fillData() throws SQLException {
        vats = vatController.getAllVats();
        vats.forEach((vat) -> {
            vatComboBox.addItem(vat);
        });
        customers = customerController.getAllCustomers();
        customers.forEach((customer) -> {
            customerNameComboBox.addItem(customer);
        });
        companies = companyController.getAllCompanies();
        companies.forEach((company) -> {
            companyNameComboBox.addItem(company);
        });
        employees = employeeController.getAllEmployees();
        employees.forEach((employee) -> {
            employeeComboBox.addItem(employee);
        });
        double rate = getRateToFill();
        rateField.setText(String.valueOf(rate));
    }

Feltételvizsgálat elkerülése

Ez egy tök jó tipp volt, meg is fogadtam. Egy booleanként visszatérő értéket vizsgálok, hogy igaz-e vagy hamis, és annak megfelelően tér vissza a metódusom igazzal vagy hamissal. A feltételvizsgálat itt tényleg felesleges, hiszen elég visszatérni a boolean értékkel egyből. Ezt meg is jegyeztem a jövőre nézve.

Az én kódom:

if (selected.equals("Igen")) {
   return true;
} else {
   return false;
}

Az átírt kód:

return selected.equals("Igen");

Lambda kifejezéssé alakítás

Ahogy mondtam, erről tanultam már, de ezt még sokat kell gyakorolnom, így nem használtam fel ezt a segítséget. Az én kódom:

notFinishedOrdersTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
   @Override
   public void valueChanged(ListSelectionEvent event) {
      notFinishedEditButton.setEnabled(true);
   }
});

A javasolt változtatás:

notFinishedOrdersTable.getSelectionModel().addListSelectionListener((ListSelectionEvent event) -> {
   notFinishedEditButton.setEnabled(true);
});

A helyi változó felülírja a mezőnevet

Az osztály elején definiált String errorMessage nevével megegyező változónevet használok a metódusomban is, és a NetBeans figyelmeztet, hogy tudom-e, hogy itt a lokális változóval dolgozok. Javasolja a lokális változó átnevezését, amit végül nem tettem meg, mert egyelőre csak én dolgozok ezen a projekten, és szerintem ez így is marad.

private boolean fieldCheck() {
   boolean back = true;
   String errorMessage = "";
        
   if (nameField.getText().equals("")) {
      back = false;
      errorMessage += "- A cég neve mező nem lehet üres.\n";
   }
        
   if (!back) {
      this.errorMessage = "A következő hibákat találtam a kitöltés közben: \n";
      this.errorMessage += errorMessage;
   } else {
      this.errorMessage = null;
   }
      return back;
 }

Null-safe equals használata

A különféle azonosítókat rejtő ID-ket Integerként használtam int helyett, hogy lehessen nekik null értéket is adni. A NetBeans azonban figyelmeztet, hogy ne a == vagy != operátorokkal hasonlítsak össze, hanem használjak null-safe equals-t. Az én kódom:

if (customerNameComboBox.getItemAt(i).getCustomerId() == customerController.getOneCustomer(order.getCustomer()).getCustomerId()) {
   customerNameComboBox.setSelectedIndex(i);            
}

A null-safe equals megoldás:

if (Objects.equals(customerNameComboBox.getItemAt(i).getCustomerId(), customerController.getOneCustomer(order.getCustomer()).getCustomerId())) {
   customerNameComboBox.setSelectedIndex(i);            
}

Felkeltette a kíváncsiságom, hogy mi ez az Objects.equals metódust, és miért is null-safe. Persze a StackOverflow-n erre is volt válasz:

Since Java 7 you can use the static method java.util.Objects.equals(Object, Object) to perform equals checks on two objects without caring about them being null.

If both objects are null it will return true, if one is null and another isn’t it will return false. Otherwise it will return the result of calling equals on the first object with the second as argument.

Compare two objects in Java with possible null values

Azaz a Java 7 óta felhasználhatjuk a fent említett statikus metódust arra, hogy két objektumot összehasonlítsunk, és ne kelljen amiatt aggódni, hogy bármelyik is null. Ha a két objektum mindegyike null, akkor igaz értékkel tér vissza, ha csak az egyik null, akkor false értékkel. Egyébként meg megegyezik azzal a visszatérési értékkel, amit az equals metódus adna, ha az első objektumra hívnánk meg, a második értéket paraméterként felhasználva.

Már használt metódusnév jelzése

Az űrlapokat megjelenítő osztályaimban készítettem egy ehhez hasonlító getName metódust, ami a nameField JTextField-re írt szöveget adja vissza. A NetBeans jelezte, hogy már van egy ilyen metódus a java.awt.Component osztályban is. Én felülírtam ezt a saját metódusommal, ami jelen esetben nem okozott gondot, de érdemesebb lett volna más metódusnevet használni.

@Override
public String getName() {
   return nameField.getText();
}

Erre is rákerestem, és a StackOverflow megint segített:

The getName() is used in toString() methods, when setting the names of child components inside a Composite/parent Component and in AWT and Swing debug logging code. I suspect strongly that the getName() method is also used by some AWT/Swing testing frameworks.

So if you’re not dependent on any of the above uses of getName(), you might try using it for your help messages, though I would not recommend it.

Maybe you should reconsider your design? Use the name to do some lookup in a hashmap that loads the help text from a resource bundle?

What is java.awt.Component.getName() and setName() used for?

Ha jól értem, a getName() metódust a Composite/Component szülő leszármazottjainál használják, és a Swing debug naplózásánál. A válaszoló még megemlítette, hogy a gyanúja szerint ezt a metódust néhány AWT/Swing teszt framework is használja. Ha ezekre nincs szükségünk, akkor felülírhatjuk a metódust a saját kódunkkal, de ő inkább más név választását javasolja.