Pereiti prie turinio

Klausimai apie JAVA


Rekomenduojami pranešimai

Gal kažkas iš JAVA programuotojų karts nuo karto turės laisvo laiko ir galės atsakyti į iškylančius klausimus šioje temoje. Klausimai kol kas pradedančiojo, nes tik du mėnesiai kaip pradėjau mokytis JAVA :)

 

1) kaip priimta tvarkyti JAVA programų struktūrą (packages, classes)? Bandau plius minus tvarkyti pagal ankščiau web puslapiuose matytą struktūrą, bet būtų gerai jei kas pasidalintu kokiu gitlab/github linku pavyzdinės programos. Žemiau mano laisvalaikiu kodinamos programos failai. Pradėjau grupuoti. Bet pvz. kur dėti scannerio klasę, kur įdėti main klasę, skirtą programos paleidimui (ten vienas metodas iškviečiamas):

 

post-23475-0-56196900-1587557836_thumb.png

 

 

2) Taip pat skaičiau, kad naudojami public static metodai, kurie lyg ir talpinami atskiroje helpers klasėje. Nes mano klasėse yra dalis metodu, kurie nesusije su objektais, tarkim printina pasisveikinimo pranešimus, kaip toks:

 

public void showWelcomeMessage() {
       System.out.println("#####################");
       System.out.println("Welcome to MegaShop!");
       System.out.println("#####################");
   }

 

Tai realiai galėčiau tokiu metodus arba atskiras metodų dalis, sudėti atskirai ir išsikviesti. Kodas būtų mažesnis, nes dalis String'ų būtų kiotje klasėje.

Redagavo finansai
Nuoroda į pranešimą
Dalintis kituose puslapiuose

1) Vieno standarto nėra, priklauso nuo organizacijos/individo patirties ir pripratimo. Svarbu, kad būtų patogu, lengvai plečiama ir atitiktų SOLID principus. Dažniausiai pastebėjau vyrauja 2 grupavimo tipai:

* pagal paskirtį (pvz atskiri packages entities, controllers, services, repositories utils, etc);

* pagal esybę (pvz package car, o jo viduje Car.java, CarController.java, CarService.java, CarRepository.java, etc).

Main klasę gali palikti rootiniame package. Beje, Javoje priimtina, kad pradinis package būtų tavo domeno vardas atvirkčiai, pvz lt.manoprojektas.shop

 

2) Dažniausiai tokie statiniai metodai, kurie naudojami keliuose vietose dedami į atskiras utils klases, pvz DateUtils, CurrencyUtils, SessionUtils, etc. Statiniai metodai nėra efektyvus atminties prasme, todėl reikia pagalvoti, ar tikrai tas metodas turi būti statinis. Konstantas (public static final) irgi galima kelti į atskirą Consts failą, jei naudoja kelios klasės.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

1) Vieno standarto nėra, priklauso nuo organizacijos/individo patirties ir pripratimo. Svarbu, kad būtų patogu, lengvai plečiama ir atitiktų SOLID principus. Dažniausiai pastebėjau vyrauja 2 grupavimo tipai:

* pagal paskirtį (pvz atskiri packages entities, controllers, services, repositories utils, etc);

* pagal esybę (pvz package car, o jo viduje Car.java, CarController.java, CarService.java, CarRepository.java, etc).

Main klasę gali palikti rootiniame package. Beje, Javoje priimtina, kad pradinis package būtų tavo domeno vardas atvirkčiai, pvz lt.manoprojektas.shop

 

2) Dažniausiai tokie statiniai metodai, kurie naudojami keliuose vietose dedami į atskiras utils klases, pvz DateUtils, CurrencyUtils, SessionUtils, etc. Statiniai metodai nėra efektyvus atminties prasme, todėl reikia pagalvoti, ar tikrai tas metodas turi būti statinis. Konstantas (public static final) irgi galima kelti į atskirą Consts failą, jei naudoja kelios klasės.

Super, dėkui. Kaip daryti su tokiais metodais, kuriuose nemažai println tekstų. Lyg ir reiktų naudoti StringBuilder, bet nesuprantu panaudojimo esmės ir kitas dalykas, ar normalu tiek teksto laikyti metode, nereikt jo kažkur atskirai laikyti? pvz.:

 

1)

public void showQuestion() {
       System.out.println("\nWhat you wanna do?\n");
       System.out.println("\t[1] - show available products;");
       System.out.println("\t[2] - add product to cart;");
       System.out.println("\t[3] - show cart;");
       System.out.println("\t[4] - remove product from cart;");
       System.out.println("\t[5] - show my profile;");
       System.out.println("\t[6] - finish shopping;");
       System.out.print("\nEnter number: ");
       String temp1 = ScannerInput.scan.next();
       switch (temp1) {
           case "1":
               shopItems.showfullProductsInformation();
               showQuestion();
               break;
           case "2":
               addingToCart();
               showQuestion();
               break;
           case "3":
               showCartWhileShopping();
               showQuestion();
               break;
           case "4":
               removeFromCart();
               showQuestion();
               break;
           case "5":
               //user.showProfile();
               user2.showProfile(); //alternative version
               showQuestion();
           case "6":
               try {
                   checkCartBeforeWritingToRegistry();
               } catch (IOException e) {
                   System.out.println("No bills register found.");
               }
               try {
                   new TurnoverCalculator().rewriteTurnover(calculateCartPriceWithDiscount());
               } catch (IOException e) {
                   System.out.println("Error trying to rewrite total turnover");
               }
               break;
           default:
               System.out.println("\nWrong selection!");
               showQuestion();
               break;
       }
   }

 

 

2)

 public void catchErrorStringInstedOfInt() {
       try {
           int tempValue = ScannerInput.scan.nextInt();
           int index = tempValue - 1;
           if (index <= cart.size() && index >= 0) {
               String tempValuePrint = cart.get(index).toString();
               cart.remove(index);
               cartPriceList.remove(index);
               System.out.println("----------------------------------------------------");
               System.out.println("Successfully removed the product: " + tempValuePrint);
               System.out.println("----------------------------------------------------");
           } else if (index < 0 || index > cart.size()) {
               System.out.println("Wrong number. ");
               removeFromCart();
           } else {
               System.out.println("\n########################################");
               System.out.println("Can't remove product Nr." + index + ".");
               System.out.println("You have only " + cart.size() + " product/-s in your cart");
               System.out.println("########################################");
           }
       } catch (InputMismatchException exception) {
           System.out.println("-------------------------------------------");
           System.out.println("You entered - '" + ScannerInput.scan.next().toUpperCase() + "' - insted of item number.");
           System.out.println("Your cart contains these items:");
           for (int i = 0; i < cart.size(); i++) {
               System.out.println((i + 1) + ". " + cart.get(i) + "€");
           }
           System.out.println("-------------------------------------------");
           removeFromCart();
       }
   }

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Pateikti pavyzdžiai yra konsolinės aplikacijos. Webinėse aplikacijose tokie tekstai nueitų į htmlus. Konsolinėse aplikacijose teksto gali būti daug, bet tik toje klasėje, kuri atsakinga už UI. Jei pvz servise, kuris apskaičiuoja vidurkį išprintinsi vartotojui suskaičiuotą rezultatą, tai nebus gera praktika. Geriau grąžinti rezultatą kvietėjui, o jis tegu sprendžia ką su juo daryti.

SpringBuilder pateiktuose pavyzdžiuose nereikalingas. Jis pravartus tada, kai paprastas String yra dažnai modifikuojamas, pavyzdžiui, sukant ciklą ir vis pridedant po raidę. String objektas Javoje yra immutable tipas, t.y. jį sukūrus (siūlau pasiskaityti apie String pool), modifikuoti nebegalima, visi veiksmai su juo iš tikrųjų grąžina naują String objektą. Tai tam tikrose situacijose kerta per performansą, todėl ir buvo sukurtas StringBuilder, kuris yra mutable String alternatyva.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Pateikti pavyzdžiai yra konsolinės aplikacijos. Webinėse aplikacijose tokie tekstai nueitų į htmlus. Konsolinėse aplikacijose teksto gali būti daug, bet tik toje klasėje, kuri atsakinga už UI. Jei pvz servise, kuris apskaičiuoja vidurkį išprintinsi vartotojui suskaičiuotą rezultatą, tai nebus gera praktika. Geriau grąžinti rezultatą kvietėjui, o jis tegu sprendžia ką su juo daryti.

SpringBuilder pateiktuose pavyzdžiuose nereikalingas. Jis pravartus tada, kai paprastas String yra dažnai modifikuojamas, pavyzdžiui, sukant ciklą ir vis pridedant po raidę. String objektas Javoje yra immutable tipas, t.y. jį sukūrus (siūlau pasiskaityti apie String pool), modifikuoti nebegalima, visi veiksmai su juo iš tikrųjų grąžina naują String objektą. Tai tam tikrose situacijose kerta per performansą, todėl ir buvo sukurtas StringBuilder, kuris yra mutable String alternatyva.

Dėkui.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Turiu klausima del interface klases. Padariau toki dalyka:

 

public interface ProductUpdater {

   static void updateWarehouseData(List<CartProduct> cart) {
       try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src\\shop\\products\\list"))) {
           oos.writeObject(cart);
       } catch (FileNotFoundException e) {
           System.out.println("!!!!!!File to write product list, not found!");
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

   static List<Product> importProducts() {
       ArrayList<Product> listfromfile = null;

       try( ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src\\shop\\products\\list"))) {
           listfromfile = (ArrayList) ois.readObject();
       } catch (IOException | ClassNotFoundException e) {
           System.out.println("!!!!!Nuskaitymo eroras");
           e.printStackTrace();
       }
       return listfromfile;
   }
}

 

Viskas veikia. Tiesa dar objektu ArrayList konstruktoriuje padariau taip:

 

public ProductMenu() {
       this.productList = ProductUpdater.importProducts();
   }

 

Klausimas. Ar teisinga naudoti interface susideti keleta statiniu metodu kurie atlika irasyma arba nuskaityma is failo? Ar konstruktoriuje teisingai padariau?

Redagavo finansai
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Turiu klausima del interface klases. Padariau toki dalyka:

 

public interface ProductUpdater {

   static void updateWarehouseData(List<CartProduct> cart) {
       try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src\\shop\\products\\list"))) {
           oos.writeObject(cart);
       } catch (FileNotFoundException e) {
           System.out.println("!!!!!!File to write product list, not found!");
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

   static List<Product> importProducts() {
       ArrayList<Product> listfromfile = null;

       try( ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src\\shop\\products\\list"))) {
           listfromfile = (ArrayList) ois.readObject();
       } catch (IOException | ClassNotFoundException e) {
           System.out.println("!!!!!Nuskaitymo eroras");
           e.printStackTrace();
       }
       return listfromfile;
   }
}

 

Viskas veikia. Tiesa dar objektu ArrayList konstruktoriuje padariau taip:

 

public ProductMenu() {
       this.productList = ProductUpdater.importProducts();
   }

 

Klausimas. Ar teisinga naudoti interface susideti keleta statiniu metodu kurie atlika irasyma arba nuskaityma is failo? Ar konstruktoriuje teisingai padariau?

 

Statinių metodų naudojimas interfeise nėra gera praktika (beje, anksčiau to ir techniškai negalėjai, statiniai metodai interfeise atsirado nuo Java 8). Įprastai interfeisai naudojami tam, kad apibrėžti kontraktą, kurį konkrečios klasės turi įgyvendinti. Vienas inerfeisas gali turėti keletą realizacijų. Šiuo atveju, geresnis variantas būtų turėti interfeisą ProductUpdater su metodais

void updateWarehouseData(List<CartProduct> cart);

ir

List<Product> importProducts();

Tada susikurti konkrečią implementaciją, pvz

public class ProductUpdaterFromFile implements ProductUpdater

. Ten įgyventinti reikalingus metodus ir tada iškvietimas būtų toks:

ProductUpdater productUpdater = new ProductUpdaterFromFile();
this.productList = productUpdater.importProducts();

Taip mažiau prisirišama prie konkrečios realizacijos, jei pvz vėliau nuspręstum, kad tau reikia krauti duomenis ne iš failo, o iš DB, galėtum apsirašyti naują implementaciją:

public class ProductUpdaterFromDB implements ProductUpdater

ir lengvai pakeisti esamą nesugriaunant viso kodo.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Super, dėkui už atsakymą. Dar klausimas.

 

Pasidariau kaip rekomendavai:

 

public class ProductUpdaterFromFile implements ProductUpdater {
   public static final String PATH = "src\\shop\\products\\list";

   public void updateWarehouseData(ProductMenu shopItems) {
       try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(PATH))) {
           oos.writeObject(shopItems);
       } catch (FileNotFoundException e) {
           System.out.println("!!File to write product list, not found!!");
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

   public ProductMenu importProducts() {
       ProductMenu listfromfile = null;

       try( ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PATH))) {
           listfromfile = (ProductMenu) ois.readObject();
       } catch (IOException | ClassNotFoundException e) {
           System.out.println("!!!!!Nuskaitymo eroras");
           e.printStackTrace();
       }
       return listfromfile;
   }
}

 

Kadangi aš įrašau ir nuskaitau objektą ProductMenu (ArrayList iš objektų), tai aš negaliu jo perduoti į konstruktorių, nes ten yra kitas objektas List<Product> ir man meta errorą. Nes prieš tai kai testavausi, naudojau pabandymui kitą List.

 

Čia pilnas mano konstruktorius ProductMenu klasės.

 

public class ProductMenu implements Serializable {

   private static final long serialVersionUID = 7194248746997618132L;
   public List<Product> productList;

   public ProductMenu() {
   }

   public void showfullProductsInformation() {
       numberOfProductsInShop();
       showNamesAndPricesOfAllProductsInShop();
   }

   public void numberOfProductsInShop() {
       System.out.println("\nShop has " + productList.size() + " products:");
   }

   public void showNamesAndPricesOfAllProductsInShop() {
       productList.sort(Comparator.comparing(Product::getName)); //sortProductsByName();
       int productNumber = 1;
       for (Product item : productList
       ) {
           System.out.println("\t" + productNumber + ". " + item.fullProductInformation());
           productNumber++;
       }
   }
}

 

Man gaunasi padaryti veikiantį kodą, tik jei nenaudoju konstruktoriaus (palieku default), o kitoje klasėje kur vyksta visi metodai susiję su objektų išvedimu, pakeitimu ir t.t., iškviečiu ProductMenu klasę ir padarau tokį inicilizavimą:

 

ProductUpdater updater = new ProductUpdaterFromFile();
   private ProductMenu shopItems = updater.importProducts();  //importuoja ProductMenu objektą

 

Kai pabaigiamas įmituoti apsipirkimas ir pasiekčia likučiai prekių, shopItems įrašomas į failą:

 

public void checkIfProductListUpdateNeeded() {
       if (cart.size() > 0) {
           updater.updateWarehouseData(shopItems); //įrašo ProductMenu objektą
       }
   }

 

Vienintelis dalykas kurį sugalvoju, kad konstruktoriuje panaudoti tavo pasiūlytą variantą:

 

ProductUpdater productUpdater = new ProductUpdaterFromFile();
this.productList = productUpdater.importProducts();  //netinka, nes importuojamas ProductMenu objektas, o ne List<Product>

 

Tai man reikia viską įrašinėti ir nuskaityti kaip List<Product>. Nuskaityti ne problema, bet problema man, kad kitoje klasėje iškviestas ProductMenu jau yra kaip atskiras objektas, nors realiai sudarytas iš to pačio List<Product>. O castinant metode, meta errora. Tai nežinau, kaip pagal taisykles tokį dalyką geriausia padaryti. Ar išvis gal nenaudoti šito varianto, nes kitur rašo, kad reikia vietoj Object Strem, viską daryti su Gson. Gausis, kad nuo paprasto printwriter priejau iki Gson :)

 

Tiesa, mačiau, kad kitur rekomenduojama konstruktoriuje nurodyti, koks tai list:

 

public List<Product> productList;

   public ProductMenu() {
       productList = new ArrayList<>();
   }

Redagavo finansai
Nuoroda į pranešimą
Dalintis kituose puslapiuose

ProductUpdaterFromFile nuskaityti ir įrašyti List<Product>, o ne ProductMenu. Jei tau reikalingas tas ProductMenu, geriau jau daryti taip tada:

ProductUpdater updater = new ProductUpdaterFromFile();
List<Product> shopItems = updater.importProducts();
ProductMenu productMenu = new ProductMenu();
productMenu.setProductList(shopItems);

Galbūt ne taip supratau problemą, jei taip, tada būtų gerai, kad patikslintum.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

ProductUpdaterFromFile nuskaityti ir įrašyti List<Product>, o ne ProductMenu. Jei tau reikalingas tas ProductMenu, geriau jau daryti taip tada:

ProductUpdater updater = new ProductUpdaterFromFile();
List<Product> shopItems = updater.importProducts();
ProductMenu productMenu = new ProductMenu();
productMenu.setProductList(shopItems);

Galbūt ne taip supratau problemą, jei taip, tada būtų gerai, kad patikslintum.

 

Bandysiu aiškiau parašyti. Pas mane yra klasė, kurioje sukuriu produktų sarašą iš failo. Ir toje klasėje vyksta visos operacijos su šiuo sąrašu - ProductMenu shopItems (nuskaitymas, produktu kiekio mažinimas ir t.t.).

 

public class ShoppingOperations {

   ProductUpdater updater = new ProductUpdaterFromFile();
   private ProductMenu shopItems = updater.importProducts();

   //...toliau eina įvairūs metodai, kurių pabaigoje įrašau pasikeitusi shopItems...


//iskvieciu metoda, kuris iraso mano produktu sarasa, bet jis irasomas kaip ProductMenu objektas
public void checkIfProductListUpdateNeeded() {      
       if (cart.size() > 0) {
           updater.updateWarehouseData(shopItems);
       }
   }

 

 

Gaunasi, kad aš įrašau į failą objektą ProductMenu shopItems. Todėl jei nori jį iškviesti vėl, turiu importuoti irgi kaip ProductMenu objektą. Ką dabar ir darau. Bet kiek matau rekomendacijų, tai geriau produktų sąrašą inicializuoti pačiame konstruktoriuje. Jei tai darau, rodo, kad netinkamas formatas:

 

post-23475-0-27911100-1588602225_thumb.png

 

 

Jei bandau castinti, vėl rodo rekomendacijas:

 

post-23475-0-57527700-1588602300_thumb.png

 

Klausimas ar verta daryti inicializavimą tokiu atveju konstruktoriuje, ar palikti inicializavimą produktų sąrašo kaip dabar esu pasidaręs.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Bandysiu aiškiau parašyti. Pas mane yra klasė, kurioje sukuriu produktų sarašą iš failo. Ir toje klasėje vyksta visos operacijos su šiuo sąrašu - ProductMenu shopItems (nuskaitymas, produktu kiekio mažinimas ir t.t.).

 

public class ShoppingOperations {

   ProductUpdater updater = new ProductUpdaterFromFile();
   private ProductMenu shopItems = updater.importProducts();

   //...toliau eina įvairūs metodai, kurių pabaigoje įrašau pasikeitusi shopItems...


//iskvieciu metoda, kuris iraso mano produktu sarasa, bet jis irasomas kaip ProductMenu objektas
public void checkIfProductListUpdateNeeded() {      
       if (cart.size() > 0) {
           updater.updateWarehouseData(shopItems);
       }
   }

 

 

Gaunasi, kad aš įrašau į failą objektą ProductMenu shopItems. Todėl jei nori jį iškviesti vėl, turiu importuoti irgi kaip ProductMenu objektą. Ką dabar ir darau. Bet kiek matau rekomendacijų, tai geriau produktų sąrašą inicializuoti pačiame konstruktoriuje. Jei tai darau, rodo, kad netinkamas formatas:

 

post-23475-0-27911100-1588602225_thumb.png

 

 

Jei bandau castinti, vėl rodo rekomendacijas:

 

post-23475-0-57527700-1588602300_thumb.png

 

Klausimas ar verta daryti inicializavimą tokiu atveju konstruktoriuje, ar palikti inicializavimą produktų sąrašo kaip dabar esu pasidaręs.

 

Kažkaip keistai pas tave čia su tais objektų tipais. Nuskaitymas ir įrašymas turėtų naudoti tą pačią klasę, o ne taip, kad įrašo ProductMenu, o krauna List<Product>. Konstruktorius yra tinkama vieta inicializuoti ir užkrauti reikalingus duomenis, tik to castinimo nereikėtų naudoti, o tiesiog susitvarkyti tipus, kad atitiktų.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Kažkaip keistai pas tave čia su tais objektų tipais. Nuskaitymas ir įrašymas turėtų naudoti tą pačią klasę, o ne taip, kad įrašo ProductMenu, o krauna List<Product>. Konstruktorius yra tinkama vieta inicializuoti ir užkrauti reikalingus duomenis, tik to castinimo nereikėtų naudoti, o tiesiog susitvarkyti tipus, kad atitiktų.

Dėkui, to ir norėjau išsiaiškinti. Aš dabar įrašinėjau ir iniciacilizavau kaip ProductMenu, tik paskui buvo mintis viską įrašinėti kaip List<Product>, tam kad galėčiau jau konstuktoriuje inicializuoti.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Ar toks metodas (jis veikia), turi buti skaidomas i smulkesnius metodus. Ar pati kodo logika atrodo normali? Tikrinu ar emailas atitinka regexa, jei atitinka, dar tikrinu ar tokio emailo nera duombazeje (paprastas .csv failas) ir jei abu atvejai "praeina", ivestas emailas grazinamas.

 

  public String validateEmailAddress() {
       String validEmail = "";
       boolean valid;
       do {
           System.out.print("\nEnter email: ");
           String emailInput = ScannerInput.scan.nextLine().trim();
           final Pattern VALID_EMAIL_ADDRESS_REGEX =
                   Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
           Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailInput);
           valid = matcher.find();
           if (!valid) {
               System.out.println("Wrong email format. Try again!");
           } else {
               if (userData.checkEmailWhenNewUsrRegisters(emailInput)) { //sitas metodas grazina true, jei randamas emailas duombazeje
                   System.out.println("User with this email exist.\nEnter another email to register!");
                   valid = false;
               } else {
                   validEmail = emailInput;
               }
           }
       } while (!valid);
       return validEmail;
   }

Redagavo finansai
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Ar toks metodas (jis veikia), turi buti skaidomas i smulkesnius metodus. Ar pati kodo logika atrodo normali? Tikrinu ar emailas atitinka regexa, jei atitinka, dar tikrinu ar tokio emailo nera duombazeje (paprastas .csv failas) ir jei abu atvejai "praeina", ivestas emailas grazinamas.

 

  public String validateEmailAddress() {
       String validEmail = "";
       boolean valid;
       do {
           System.out.print("\nEnter email: ");
           String emailInput = ScannerInput.scan.nextLine().trim();
           final Pattern VALID_EMAIL_ADDRESS_REGEX =
                   Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
           Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailInput);
           valid = matcher.find();
           if (!valid) {
               System.out.println("Wrong email format. Try again!");
           } else {
               if (userData.checkEmailWhenNewUsrRegisters(emailInput)) { //sitas metodas grazina true, jei randamas emailas duombazeje
                   System.out.println("User with this email exist.\nEnter another email to register!");
                   valid = false;
               } else {
                   validEmail = emailInput;
               }
           }
       } while (!valid);
       return validEmail;
   }

 

Toks metodas neatitinka single responsibility principo, nes šis metodas ir skaito iš inputo, ir rašo į konsolę, ir validuoja emailą, ir tikrina jį DB. Matau bent kelis taškus, kuriuose kodą būtų galima išskaidyti:

1) Susikurk atskirą metodą (tiktų private) pavadinimu pvz validEmailAddress, kuris priima String ir grąžina boolean ir ten iškelk visą šią logiką:

final Pattern VALID_EMAIL_ADDRESS_REGEX =
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailInput);
return matcher.find();

2) Analogiškai dar vieną metodą pvz checkEmailExists, kuris patikrintų ar email egzistuoja DB ir grąžintų true/false.

3) Tada pagrindinis metodas validateEmailAddress() tiesiog skaitys user inputą, kvies tuos kitus metodus nesigilindamas ką jie daro ir printins informaciją.

Dar vienas pastebėjimas: validateEmailAddress() grąžina String. Jei aš pvz kviesčiau tavo funkciją nežinodamas apie jos vidų, nežinau, ko tikėčiaus, kad jį gąžina, nes pagal pavadinimą atrodo, kad ji turėtų validuoti, tai gal būtų galima sugalvoti labiau tikrąjį funkcionalumą atitinkantį pavadinimą pvz readValidEmailAddress() ar pan.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Toks metodas neatitinka single responsibility principo, nes šis metodas ir skaito iš inputo, ir rašo į konsolę, ir validuoja emailą, ir tikrina jį DB. Matau bent kelis taškus, kuriuose kodą būtų galima išskaidyti:

1) Susikurk atskirą metodą (tiktų private) pavadinimu pvz validEmailAddress, kuris priima String ir grąžina boolean ir ten iškelk visą šią logiką:

final Pattern VALID_EMAIL_ADDRESS_REGEX =
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailInput);
return matcher.find();

2) Analogiškai dar vieną metodą pvz checkEmailExists, kuris patikrintų ar email egzistuoja DB ir grąžintų true/false.

3) Tada pagrindinis metodas validateEmailAddress() tiesiog skaitys user inputą, kvies tuos kitus metodus nesigilindamas ką jie daro ir printins informaciją.

Dar vienas pastebėjimas: validateEmailAddress() grąžina String. Jei aš pvz kviesčiau tavo funkciją nežinodamas apie jos vidų, nežinau, ko tikėčiaus, kad jį gąžina, nes pagal pavadinimą atrodo, kad ji turėtų validuoti, tai gal būtų galima sugalvoti labiau tikrąjį funkcionalumą atitinkantį pavadinimą pvz readValidEmailAddress() ar pan.

 

Dėkui, bandau ištaisyti ir skaidyti į smulkesnius metodus. Dar klausimas, ar galiu naudoti tokį konstruktorių? Taip galiu setinti reikšmes kai ištraukiu User iš "duombazės" arba sukuriu naują userį.

 

    public class User {
   private String email;
   private String password;
   private String username;
   private int discountLevel;


   public User() {
       this.email = "";
       this.password = "";
       this.username = "";
       this.discountLevel = 1;
  }

   public String getEmail() {
       return email;
   }

   public void setEmail(String email) {
       this.email = email;
   }

   public String getPassword() {
       return password;
   }

   public void setPassword(String password) {
       this.password = password;
   }

   public String getUsername() {
       return username;
   }

   public void setUsername(String username) {
       this.username = username;
   }

   public int getDiscountLevel() {
       return discountLevel;
   }

   public void setDiscountLevel(int discountLevel) {
       this.discountLevel = discountLevel;
   }

   @Override
   public String toString() {
       return "Your username: " + getUsername() + "\nYour email: " + getEmail() +
               "\nYour password: ******" + "\nYour discount level: " + getDiscountLevel();
   }
}

 

Tokiu principu:

 

public User importUserAfterPswCheck(String emailIn) {
       User tempUser = new User();
       try (Scanner read = new Scanner(new File("src\\shop\\users\\userdata.csv"))){
           read.nextLine();
           while (read.hasNext()) {
               String dataFromFile = read.nextLine();
               String[] valuesFromLine = dataFromFile.split(",");
               String email = valuesFromLine[0];
               String password = valuesFromLine[1];
               String userName = valuesFromLine[2];
               int discount = Integer.parseInt(valuesFromLine[3]);
               if(emailIn.equals(email)) {
                   tempUser.setEmail(email);
                   tempUser.setUsername(userName);
                   tempUser.setPassword(password);
                   tempUser.setDiscountLevel(discount);
               }
           }
           return tempUser;
       } catch (Exception e) {
           System.out.println("No users database file found!");
       }
       return null;
   }

 

Nezinau ar butu logiska dar konstruktoriuje ideti if kuris parinktu ar kraunama is duombazes ar vykdoma nauja registracija.

 

Ar visgi daryti User klase, kuria extendintu RegisteredUser, tada iskart konstruktoriuje nurodau, kad uzkrauti duomenis is duombazes, ir dar viena klase kuri extendintu User, butu NewUser, tuomet konstruoti jau is ivedamu duomenu.

Redagavo finansai
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Jei gerai supratau problemą, tai siūlau User esybės nepildyti NewUser ir RegisteredUser, o geriau atskirai susikurti kokį AuthManager, kuris atliktų registracijos ir login veiksmus, atitinkamai sukurdamas naują userį arba pakraudamas iš esamų.

Kadangi aš dar tik trečias mėnuo kaip mokausi, ne visus niuansus iškart perprantu :) Ar turi omenyje, kad man pasidaryti atskirą klasę, kur susikrauti visus metodus kurie ir nuskaito failą ir iš jo ištraukia reikiamą userį pagal prisijungimus, bei tikrina naujo varototojo registracijos inputus ir jį sukuria? Nes realiai gautusi didelė klasė, nebent jai papildomai dar sukurti klasių, padedančių kažką chekinti. Bet esminis klausimas, ar ta klasė, ištraukus arba sukurus userį, turi man gražinti userį, ar kažkur jį užsetinti. Ar User klasėje aš konstruktoriuje jau turiu paduoti, kad užkrautų iš AuthManager klasės userį? Svo kreivais metodais prikuriu aš veikiantį variantį, bet jis savaime aišku neatitinka teisingo kodo praktikų. Todėl norisi kuo išsamiau sužinoti teisingas praktikas.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Kadangi aš dar tik trečias mėnuo kaip mokausi, ne visus niuansus iškart perprantu :) Ar turi omenyje, kad man pasidaryti atskirą klasę, kur susikrauti visus metodus kurie ir nuskaito failą ir iš jo ištraukia reikiamą userį pagal prisijungimus, bei tikrina naujo varototojo registracijos inputus ir jį sukuria? Nes realiai gautusi didelė klasė, nebent jai papildomai dar sukurti klasių, padedančių kažką chekinti. Bet esminis klausimas, ar ta klasė, ištraukus arba sukurus userį, turi man gražinti userį, ar kažkur jį užsetinti. Ar User klasėje aš konstruktoriuje jau turiu paduoti, kad užkrautų iš AuthManager klasės userį? Svo kreivais metodais prikuriu aš veikiantį variantį, bet jis savaime aišku neatitinka teisingo kodo praktikų. Todėl norisi kuo išsamiau sužinoti teisingas praktikas.

 

Nebūtinai viską sutempti į AuthManager, jis gali deleguoti darbus, tarkim registravimą ar prisijungimą. Loginis išskaidymas praverstų, tačiau neperkraunant vienos klasės. Idealiu atveju, klasė turi daryti vieną darbą, bet daryti jį gerai. Userio inputų skaitymas ir rašymas į konsolę, kaip jau kažkada minėjau, turėtų priklausyti UI klasei. Dėl userio, tai priklauso, kur tau paskui jį reikės naudoti, šiaip tokiose consolinėse aplikacijose aš pats mažai susidūręs su autentifikacija, webinėse platformose įprastai naudojamas Spring security arba dedama į sesiją.

Nuoroda į pranešimą
Dalintis kituose puslapiuose
  • po 3 savaičių...

Nebūtinai viską sutempti į AuthManager, jis gali deleguoti darbus, tarkim registravimą ar prisijungimą. Loginis išskaidymas praverstų, tačiau neperkraunant vienos klasės. Idealiu atveju, klasė turi daryti vieną darbą, bet daryti jį gerai. Userio inputų skaitymas ir rašymas į konsolę, kaip jau kažkada minėjau, turėtų priklausyti UI klasei. Dėl userio, tai priklauso, kur tau paskui jį reikės naudoti, šiaip tokiose consolinėse aplikacijose aš pats mažai susidūręs su autentifikacija, webinėse platformose įprastai naudojamas Spring security arba dedama į sesiją.

Ką reikia žinoti, norint tapti Junior Java developer? Kiek bandžiau skaityti, tai Java Core geri pagrindai, Collection API, SQL, Hibernate, Spring(Boot, MVC).

Redagavo finansai
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Ką reikia žinoti, norint tapti Junior Java developer? Kiek bandžiau skaityti, tai Java Core geri pagrindai, Collection API, SQL, Hibernate, Spring(Boot, MVC).

 

Aš pats dar Junior ir daug ko nežinau, bet aprašysiu įgūdžius/žinias, kurios, mano nuomone, praverstų juniorui. Keli pastebėjimai:

kalba eina tik apie techninius įgūdžius ir labiau orientuota į WEB developer karjerą. Skliaustuose surašysiu konkrečius pavyzdžius, kuriuos rekomenduočiau pasinagrinėti.

 

Kadangi mano nuomone, svarbiausia yra pagrindai, o specifinę technologiją galima lengvai išmokti, tai aprašysiu ir bendrai Junior dev (nepriklausomai nuo technologijos) reikalingus įgūdžius:

  • Bendri programavimo pagrindai (ciklai, sąlyginiai sąkiniai, etc);
  • Versijų kontrolės sistema (Git) bei kodo repositorijų saugyklos (GitHub, GitLab);
  • Darbo su komandine eilute pagrindai;
  • Duomenų bazių pagrindai. Tikėtina dažniau teks susidurti su reliacinėmis DB, pvz.: PostgreSQL, Oracle, MS SQL. Iš NoSQL rekomenduočiau susipažinti su MongoDB;
  • Interneto technologijos (HTML5, CSS3, JS);
  • WEB services (REST, SOAP);
  • Duomenų serializavimo, perdavimo formatai (XML, JSON);

 

 

Kalbant specifiškai apie Java Juniorą, tai išskirčiau šiuos įgūdžius:

  • Žinoti pačią Java kalbą ir joje sutinkamas struktūras, pavyzdžiui, interfaces, enums, static, exceptions, etc.
  • OOP principai (inheritance, encapsulation, polymorphism, etc);
  • Collections API (List, Set, Map);
  • Pasirinkti patinkantį code editorių (ar IDE) ir išmokti juo efektyviai naudotis (mano nuomone, geriausias pasirinkimas - IntelliJ, tačiau Eclipse ir NetBeans taip pat iš bėdos galima naudoti. Kai kuriems darbams naudoju VSCode editorių. Dažnai pasirinkimas priklauso nuo komandos, kurioje dirbi pasirinkimų, nors teoriškai taip neturėtų būti).
  • Būti bent kažkiek pačiupinėjus ir susipažinus su kokiu nors Java WEB aplikacijų karkasu (rekomenduoju Spring Boot). Prie to pačio - components ir jų scopes (Bean, RequestScope, SessionScope, ViewScope);
  • Build tools (Maven, Gradle);
  • JPA/Hibernate manau didelis privalumas (suprasti kaip sumapinti ryšius OneToOne, OneToMany, ManyToMany, etc bei kaip rašyti Hibernate užklausas);
  • Bent kažkiek gaudytis design patternuose ir žinoti, kas yra DI (dependency injection);
  • Bent kažkiek susipažinti su aplikacijų serveriais (Tomcat);
  • Šiais laikais turbūt frontend dažniau renkamasi client side framework (React, Angular, Vue), tačiau anksčiau dominavo JSF, JSP, todėl JSF pagrindai manau irgi duotų naudos.

 

Gal kažką ir pamiršau paminėti, bet manau vis tiek rasi pakankamai naudingos informacijos.

Redagavo IDK
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Aš pats dar Junior ir daug ko nežinau, bet aprašysiu įgūdžius/žinias, kurios, mano nuomone, praverstų juniorui. Keli pastebėjimai:

kalba eina tik apie techninius įgūdžius ir labiau orientuota į WEB developer karjerą. Skliaustuose surašysiu konkrečius pavyzdžius, kuriuos rekomenduočiau pasinagrinėti.

 

Kadangi mano nuomone, svarbiausia yra pagrindai, o specifinę technologiją galima lengvai išmokti, tai aprašysiu ir bendrai Junior dev (nepriklausomai nuo technologijos) reikalingus įgūdžius:

  • Bendri programavimo pagrindai (ciklai, sąlyginiai sąkiniai, etc);
  • Versijų kontrolės sistema (Git) bei kodo repositorijų saugyklos (GitHub, GitLab);
  • Darbo su komandine eilute pagrindai;
  • Duomenų bazių pagrindai. Tikėtina dažniau teks susidurti su reliacinėmis DB, pvz.: PostgreSQL, Oracle, MS SQL. Iš NoSQL rekomenduočiau susipažinti su MongoDB;
  • Interneto technologijos (HTML5, CSS3, JS);
  • WEB services (REST, SOAP);
  • Duomenų serializavimo, perdavimo formatai (XML, JSON);

 

 

Kalbant specifiškai apie Java Juniorą, tai išskirčiau šiuos įgūdžius:

  • Žinoti pačią Java kalbą ir joje sutinkamas struktūras, pavyzdžiui, interfaces, enums, static, exceptions, etc.
  • OOP principai (inheritance, encapsulation, polymorphism, etc);
  • Collections API (List, Set, Map);
  • Pasirinkti patinkantį code editorių (ar IDE) ir išmokti juo efektyviai naudotis (mano nuomone, geriausias pasirinkimas - IntelliJ, tačiau Eclipse ir NetBeans taip pat iš bėdos galima naudoti. Kai kuriems darbams naudoju VSCode editorių. Dažnai pasirinkimas priklauso nuo komandos, kurioje dirbi pasirinkimų, nors teoriškai taip neturėtų būti).
  • Būti bent kažkiek pačiupinėjus ir susipažinus su kokiu nors Java WEB aplikacijų karkasu (rekomenduoju Spring Boot). Prie to pačio - components ir jų scopes (Bean, RequestScope, SessionScope, ViewScope);
  • Build tools (Maven, Gradle);
  • JPA/Hibernate manau didelis privalumas (suprasti kaip sumapinti ryšius OneToOne, OneToMany, ManyToMany, etc bei kaip rašyti Hibernate užklausas);
  • Bent kažkiek gaudytis design patternuose ir žinoti, kas yra DI (dependency injection);
  • Bent kažkiek susipažinti su aplikacijų serveriais (Tomcat);
  • Šiais laikais turbūt frontend dažniau renkamasi client side framework (React, Angular, Vue), tačiau anksčiau dominavo JSF, JSP, todėl JSF pagrindai manau irgi duotų naudos.

 

Gal kažką ir pamiršau paminėti, bet manau vis tiek rasi pakankamai naudingos informacijos.

Dėkui už išsamų atsakymą. Smagu, kad daugelį tavo išvardintų punktų bent jau daugiau arba mažiau moku/arba esu susipažinęs. Tiesa dėl duombazių, mums akademijoje kursas apie duombazes bus tik po keletos mėnesių, bet aš pradėjau savarankiškai mokytis. Kadangi mums bus paskaitos apie SQL ir bus naudojama MySQL, tai aš apie ją pradėjau mokytis. Bet matau, kad dažnai rekomenduojama ir PostgreSQL. Ar verta papildomai dar mokytis ir PostgreSQL ar geriau labiau gilintis į vieną MySQL?

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Dėkui už išsamų atsakymą. Smagu, kad daugelį tavo išvardintų punktų bent jau daugiau arba mažiau moku/arba esu susipažinęs. Tiesa dėl duombazių, mums akademijoje kursas apie duombazes bus tik po keletos mėnesių, bet aš pradėjau savarankiškai mokytis. Kadangi mums bus paskaitos apie SQL ir bus naudojama MySQL, tai aš apie ją pradėjau mokytis. Bet matau, kad dažnai rekomenduojama ir PostgreSQL. Ar verta papildomai dar mokytis ir PostgreSQL ar geriau labiau gilintis į vieną MySQL?

 

Man pačiam su MySQL neteko susidurti, todėl ir nepaminėjau, manau tai populiarus pasirinkimas tarp PHP developerių. StackOverflow 2019 m. apklausoje MySQL lyderiavo tarp DB pasirinkimų, todėl tai nėra nueinanti technologija. Iš esmės, išmokus dirbti su viena reliacine DBVS, nesunku pereiti prie kitos, todėl didelio skirtumo ar pradėsi nuo MySQL ar nuo PostgreSQL nėra.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Dėkui už išsamų atsakymą. Smagu, kad daugelį tavo išvardintų punktų bent jau daugiau arba mažiau moku/arba esu susipažinęs. Tiesa dėl duombazių, mums akademijoje kursas apie duombazes bus tik po keletos mėnesių, bet aš pradėjau savarankiškai mokytis. Kadangi mums bus paskaitos apie SQL ir bus naudojama MySQL, tai aš apie ją pradėjau mokytis. Bet matau, kad dažnai rekomenduojama ir PostgreSQL. Ar verta papildomai dar mokytis ir PostgreSQL ar geriau labiau gilintis į vieną MySQL?

klausimas off topic:

 

Visą laiką JAVA mokeisi akademijoje ar savarankiškai?

Nuoroda į pranešimą
Dalintis kituose puslapiuose

klausimas off topic:

 

Visą laiką JAVA mokeisi akademijoje ar savarankiškai?

Pradejau mokytis akademijoje sausio pabaigoje, bet dėl karantino paskaitos sulėtėjo ir persikėlė laikinai online. O kadangi dėl karantino atsirado daug laisvo laiko pas mane, tai aš nemažai bandau ir savarankiškai mokytis. Nes šiuo metu akademijoje dar tik baigėme Collections API, Exceptions ir pan. O pati akademija baigsis tik lapkričio mėn. Tai iki to laiko norisi pakankamai ir savarankiškai gerai pasiruošti, kad po akademijos turėčiau pakankamai žinių tapti junior developer. Ir geras dalykas pramokti daugiau, tuomet dėstytojui gali užduoti aktualesnius klausimus, kurie atsiranda savarankiško mokymosi metu. Šiaip nebrangių online kursų labai daug, ypač Udemy. Be to daug gerų video Youtube ir anglų ir rusų kalbomis. Tad net ir savarankiskai mokantis, galima pramokti visko ką išvardino IDK. Bet auditorijoje gyvai su dėstytoju visai produktyvus mokymasis, iškart gauni pagalba visais klausimais dėl kodo. Galima ir ne paskaitų metu parašyti dėstytojams, dėl kažkokių klausimų per Slack. Yra pliusų mokytis akademijoje, bet jei esi gabesnis, tai ir online kursai po 10 Eur gali duoti daug naudos.

Nuoroda į pranešimą
Dalintis kituose puslapiuose
  • po 2 mėnesių...

Klausimas del loginimo. Kol kas vis dar naudojame standartinius exception printinimus. O ka reiktu isbandyti loginimui, kad logintu faile ir realiai butu naudojama kazkokiuose siuolaikiniuose projektuose. Lyg maciau keleta rekomenduojamu biblioteku internetuose, bet butu idomu isgirsti rekomendaciju is tu kas dirba su Java.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Prisijunkite prie diskusijos

Jūs galite rašyti dabar, o registruotis vėliau. Jeigu turite paskyrą, prisijunkite dabar, kad rašytumėte iš savo paskyros.

Svečias
Parašykite atsakymą...

×   Įdėta kaip raiškusis tekstas.   Atkurti formatavimą

  Only 75 emoji are allowed.

×   Nuorodos turinys įdėtas automatiškai.   Rodyti kaip įprastą nuorodą

×   Jūsų anksčiau įrašytas turinys buvo atkurtas.   Išvalyti redaktorių

×   You cannot paste images directly. Upload or insert images from URL.

Įkraunama...
  • Dabar naršo   0 narių

    Nei vienas registruotas narys šiuo metu nežiūri šio puslapio.

×
×
  • Pasirinkite naujai kuriamo turinio tipą...