Keresés

Új hozzászólás Aktív témák

  • Szmeby

    tag

    válasz axioma #5534 üzenetére

    "Azt hianyolom, ami az abstract fuggveny vgy interface lenyege lenne, hogy ha barki kesobb ujat letrehoz, akkor lassa hogy kotelezo ezt is definialnia."
    Itt most arról beszélsz, hogy egy leszármazott osztálynak kötelező implementálnia az ősben absztraktként jelölt metódust? Vagy valami mást értesz "létrehozás" alatt?

    És ezt akarod static metódusokkal kivitelezni?

    Ez esetben az overriding és hiding közti eltérés a magyarázat a kérdésedre.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz axioma #5538 üzenetére

    Nem nagyon értem, hogy mi lesz ebből, de a statikus metódus helyett nincs jobb megoldás?
    Azt írod, hogy vannak adatok, amelyeknek már a memóriadarabka (?) példányosítása előtt rendelkezésre kell állnia.
    Na de ezeket az adatokat egy egyszerű leíró osztályban is összegyűjtheted, nem? Csinálsz egy immutable POJO-t, benne a méret meg amit akarsz, és teszemazt memóriadarabka konstruktor argumentumaként beküldöd a már adatokkal feltöltött leíró objektumot. Amit aztán a példányok kedvükre használhatnak.
    A konstruktor argumentum miatt kötelezővé válik... már ha nincs másik konstruktor, ami viszont nélküle is elvan :).

    Vagy ha nem akarod "szennyezni" a konstruktort nem oda való argumentummal, esetleg már osztálybetöltéskor szükséged van az infóra, akkor be is injektálhatod ezt a leíró objektumot egy statikus mezőre. Készíthetsz hozzá egy factory-t, ami valami alapján tudja, hogy melyik leírót példányosítsa, hogyan inicializálja, durván el lehet bonyolítani a dolgot. :D
    Bár akkor megint ott vagyunk, hogy hogyan kényszeríthető ki a kötelezőség. Ahh, nem bírom a statikus dolgokat, sok a kötöttség.

    Persze lehet, hogy hülyeséget beszélek, mint mondtam, nem értem a problémát.

  • Szmeby

    tag

    válasz Samifiu #5539 üzenetére

    Ha jól látom, itt az y csak a rendelkezésre álló tér tetejét jelöli. Az alját gondolom fixen behúztad nullára.
    Szerintem a motornak tudnia kellene azt x (és y) függvényében, hogy aktuálisan hol az alja és a teteje.

    Azért írtam y-t is, mert mi van, ha két platform elem is van egymás fölött, az egyik 150-es magasságban, a másik 300-on, és mindkettő ugyanazon az x ponton kezdődik, legyen mondjuk x=40.
    Nem mindegy, hogy a főhős (30;320) koordinátából vetődik az elemek felé, vagy (30;200) pontból. Vagy (30;10)-ből. :)
    Máshol kell kikötnie.
    Amúgy életemben nem csináltam még játékot, csak belekotyogok, bocsi.

  • Szmeby

    tag

    válasz Dave-11 #5773 üzenetére

    Az osztályokat csomagokba rendezzük, arról gondolom már volt szó. Bizonyára valamilyen csomagban lévő osztályról beszél (pl.: com.dave.proba.MyClass), és most az idézeted egy az adott csomagon kívül eső osztályra tér rá (pl.: com.dave.MyOtherClass).

    Egy osztályt futtathatónak nevezhetünk, ha van pl. main metódusa. De a "futtatható" szó akár a Runnable interfészre is vonatkozhat, ami a szálkezelésnél jön elő, és teljesen mást takar.
    Amúgy nem tudom, ennyi információból nem lehet megmondani, max találgatni.
    Szerintem ne várj érdemi választ egy kontextusból kiragadott mondatra, akarom mondani 4 szóra.

    Valószínűleg többre mennél a könyv eredeti (angol nyelvű) változatával. Bár nem olvastam még, de sajnos az a tapasztalat, hogy előszeretettel fordítanak le MINDENT (igen, a keyword-öket is) elcseszett magyar kifejezésekre, így totálisan érthetetlenné téve a szöveget. Persze az is lehet, hogy csak nekem tűnik érthetetlennek, mert én az angol neveken szocializálódtam. Sose hívnám az interfészt pl. felületnek. És ez még a megbocsátható elfordítások közé tartozik. Borzasztó miket ki nem találnak.

  • Szmeby

    tag

    válasz boost #5762 üzenetére

    "Vannak ValamiTask osztályaim, amik mindegyike tartalmaz egy doAction metódust, és az tartalmazza az üzleti logikát, valamint a commander meghívását.
    [..]
    Hogy oldom meg a TaskTest osztály testDoAction metódusában, hogy az ott példányosított Task osztály doAction függvényében meghívott commander osztály mock objektumokat használjon? Tehát két hívásra to"le."

    Hát leküldöd neki. :)
    Bár nem látom, hol van itt a második réteg.

    Ezekszerint nem ilyen a design:

    public class Task {
    private Commander cmd;
    public Task(Commander commander) {
    cmd = commander;
    }
    public doAction() {
    // using cmd
    }
    }

    Tesztelhetőség szempontjából ilyesmi lenne a célravezető. Konstruktor argumentumként adod le neki a mockot, vagy a mockokat használó Commander példányt és azt csinál majd vele, amit csak akar.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz Dave-11 #5784 üzenetére

    Ha biztosra akarsz menni, akkor a default package-be teszed.

    Ami ugye azt jelenti, hogy az osztály a classpath gyökerébe kerül, és elhagyod az osztály első sorában a package sort.
    Habár szerintem is a sereg csomagon kívüliségre gondolt, de furán fogalmaz, az biztos. Ha úgy érzed valami speciális illene ide, akkor csak a default package marad. Ki tudja, lehet, hogy előadáson így nevezte a default package-et. Ha így lenne, de te nem így csináltad, akkor viszont mehetsz reklamálni, mert azt nem úgy hívják és különben is odaírhatta volna, hogy pontosan mire gondol.

  • Szmeby

    tag

    válasz boost #5779 üzenetére

    Ha nem akarod mockolni a Commandert, akkor csinálj egy teljesértékű Commander objektumot, amiben persze továbbra is mockolod a mockolnivalót. :)
    Ezt a Commandert pedig nyugodt szívvel leküldheted a tesztelendő osztálynak.
    Bár a kódot te látod, neked kell eldönteni, hogy mit lehet és érdemes megcsinálni. Kicsit engem is zavar, hogy több rétegen át kell lemenniük a mockoknak, mert nem lehet másként.

  • Szmeby

    tag

    válasz RaPiDsHaRe #5796 üzenetére

    A while cikluson kívül is van élet, ne félj oda is tenni valamit. Persze csak ha szükséges. ;)
    A két azonos szövegből pedig elég csak az egyiket megtartani.

    --- edit:
    A GameLauncher futtatható, mert van neki main metódusa.
    Bármely osztály, ami rendelkezik main metódussal, futtatható:

    public static void main(String[] args) {
    // ...
    }

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz materk #5840 üzenetére

    Hogy mi a jó, az relatív. Neked kell tudnod, hogy mire van szükséged.

    Ha jól értem, akkor azt az információt, ami a versenyzők helyezését reprezentálja, a listában lévő elemek sorrendje határozza meg.
    Amíg egyedül dolgozol a projekten, nem jelenthet problémát, mert mindent tudsz a programról. Amikor többen is bekapcsolódnak a fejlesztésbe, akkor előtérbe kerül az érthetőség, átláthatóság. Ha úgy gondolod, hogy aki ránéz a kódra és egyből leesik neki, hogy a helyezés a listaelemek sorrendje, akkor nem lesz probléma az értelmezéssel. Amennyiben nem egyértelmű, akkor ennek az információnak láthatóbb helyen kell lennie, pl. egy objektum egy mezőjében.

    A jelenlegi helyzetben ezt redundánsnak gondolod, de korábban felvetették, hogy adatbázistól függ, hogy mennyire megbízható a sorrend. A Hibernate alatt pedig semmi perc alatt cserélhető az adatbázis implementáció. De akár olyan galádság is megtörténhet, hogy valaki a jól bejáratott List-et Set-re cseréli, mert nem jut eszébe, hogy a sorrend is fontos. Persze a te esetedben ettől nemigen kell tartani. Viszont az előbbi szituációkban nem jelent redundanciát a helyezés dedikált helyen való eltárolása.

    Egy másik érdekes dolog, hogy a listaelemek sorrendjére való építkezés nem támogatja a holtverseny fogalmát. Valószínűleg a véletlen dönt arról, hogy holtverseny esetén ki sorolódik előrébb. Ez tesztelhetőség szempontjából nem feltétlenül ideális állapot. Tesztelhető ugyan, de a véletlen sorrend miatt nehézkes.

    Persze ha fontos számodra teszemazt a memóriaméret, a redundancia alacsonyan tartása, és biztosan tudod, hogy a fent említett anomáliák (vagy hasonlók) sohasem történhetnek meg, akkor nem kell dedikált mezőt készíteni a helyezésnek. Felesleges.

  • Szmeby

    tag

    válasz Fekete Mária #5847 üzenetére

    Az alkalmazott technológiák, módszertanok, felelősségek megemlítése értékes adalék lett volna, ha már a cég neve titok. Kétlem, hogy pusztán a "kimagasló bérezés" elegendő arra, hogy egy fejlesztő váltásra adja a fejét. Legalábbis a jobbak, akik amúgy is jól meg vannak fizetve.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz Cathfaern #5869 üzenetére

    UAT: User Acceptance Test
    Ha más nem, talán annyi feladata lesz a tesztelőnek, hogy oktatja az ügyfelet. Bár jobb helyeken ez nem a tesztelő dolga.

  • Szmeby

    tag

    válasz Aethelstone #5887 üzenetére

    És mind felesleges, mert tiszta javaban ugyanazt el lehet érni kevesebb erőforrás felhasználásával. :)
    Persze több meló és odafigyelés, de valamit valamiért.

  • Szmeby

    tag

    válasz -v- #5923 üzenetére

    Mennyivel kulturáltabb objektumorientáltan, nemigaz? :DD

    private static final class Number {
    private final int number;

    private Number(int num) {
    this.number = num;
    }

    boolean between(int from, int to) {
    return this.number >= from && this.number <= to;
    }

    static final Number of(int num) {
    return new Number(num);
    }
    }
    // ...
    return Number.of(m).between(m1, m2) && Number.of(d).between(d1, d2);

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz plaschil #6108 üzenetére

    Amikor enumot csinálsz, nyugodtan tekintsd őket konstansnak. Vagyis a legtöbb esetben felesleges mellé static final cuccokat definiálni, azok simán elvannak az enum obejktumon belül is. Pl. a KapacitasTipus-ban.
    Vagy eleve a double értékeket adod be a konstruktornak (0.5 és 1.0), vagy ha ragaszkodsz az egész számokhoz is, akkor a konstruktorban elosztod százzal. Így a getter sokkal egyszerűbb lesz, megszűnik a felesleges komplexitás (if).

    Valami ilyesmi módon:

    public enum KapacitasTipus {
    M0(100), M10(50);
    private final int kapacitasTipus;
    private final double ertek;
    private KapacitasTipus(int tipus) {
    this.kapacitasTipus = tipus;
    this.ertek = tipus / 100.0;
    }
    public int getKapacitasTipus() {
    return this.kapacitasTipus;
    }
    public double getKapacitasTipusErtek() {
    return this.ertek;
    }
    }

    De akár második konstruktor argumentumként is belőhető a másik szám, ha erre tényleg szükség van.

    Ami a komplexitást illeti, amikor gigászi if-else vagy switch-case füzéreket látsz, akkor érdemes elgondolkodni azon, hogy talán nem a legjobb helyen vannak. Gondolok itt a Szerzodes.createList() metódusra, ahol egy stringből enum objektumot készítenél. Szerencsére erre létezik az enumban beépített metódus:

    pkod = PontKod.valueOf(kod);
    ...
    ktipus = KapacitasTipus.valueOf(kapacitastipus);

    Amit tudni érdemes róla, hogy exception-t dob, ha olyan stringet kap, amihez nem talál enum példányt. Ha szükséges, ezt ajánlott lekezelni egy try-catch-ben.
    A PontKod átalakításával még átláthatóbb kódod lesz.

    Az enumnak van még pár hasznos beépített metódusa (name(), ordinal(), values()), érdemes őket megismerni.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz Aethelstone #6213 üzenetére

    És ezen álláspontjukat nagyon arrogánsan képesek védeni is. Borzasztó lekezelően viselkednek a segítséget kérőkkel, cserébe viszont semmi konstruktívval nem tudnak szolgálni. Persze én vagyok a hülye, hogy a Hibernate fórumon kérek segítséget a Hibernate-tel kapcsolatban. :)

  • Szmeby

    tag

    válasz jetarko #6225 üzenetére

    Duplázódás vagy többszöröződés van?

    Most hogy láttam a kódod, előjöttek a régi emlékeim. :O
    Nálam többszöröződés jött elő, az adatszerkezet kicsit más volt, de a lényeg ugyanaz: egy entitásban több (egymástól független) lista eager fetch-csel.

    A problémám az volt, hogy a listák ugyan kis elemszámúak voltak, de többnyire nem 1 elemet tartalmaztak, hanem 2-6 körül. Ami azt eredményezte, hogy a Hibernate a háttérben megcsinálta ezek Descartes-szorzatát, tehát egy 3 elemű lista megtriplázta a másik lista elemeit. (És a Hibernate szerint ez így normális.)

    Esetleg érdemes lehet bekapcsolnod a show_sql kapcsolót, hogy megnézhesd, milyen sql lekérdezést gyárt, és azt külön elpattintva milyen resultsetet kapsz. Ne számíts arra, hogy a Hibernate a háttérben majd megszűri neked a duplikátumokat.

    Már jó rég volt, de ha jól emlékszem, végül az lett a megoldás, hogy a listákat külön-külön select töltötte fel. A design nem engedte meg, hogy Settel bohóckodjak.

  • Szmeby

    tag

    válasz floatr #6226 üzenetére

    OpenSessionInViewFilter: Ez a teljes életciklus alatt nyitva fog tartani egy tranzakciót, nem? Ez nem gáz?

  • Szmeby

    tag

    válasz jetarko #6230 üzenetére

    Asszem készült egy olyan service metódus (getFullInitializedById() vagy valami ilyesmi), ami id alapján lekérte az entitást (szigorúan lazy fetch minden mezőre), majd az id-val egyesével legyűjtögette a listákat is és a setterekkel beállította azokat az entitáson. Mindezt beburkolva 1 tranzakcióba.

    Megjegyzem, tette mindezt azért, mert állandóan nyitott tranzakció / session nem létezett a programban, mindig csak a service metódusban nyílt, elvégezte a szükséges adatbázis műveleteket majd lezárult. Márpedig lazy fetch esetén a listák nem igazi listák csak proxy objektumok, és amint ráhív az ember gyanútlanul egy ilyenre, miközben nincs mögötte aktív session, a cucc borul, mint annak a rendje. :)
    Persze ha neked mindig van nyitott session-öd, akkor talán nem kell vesződnöd a proxyk igazi listára cserélgetésével.

    De ezt ne vedd követendő példának, nagyon keveset Hibernate-eztem, és azóta csak felejtettem. Nem tartom magamat hozzáértőnek.

    select team0_.id as id1_4_0_, team0_.name as name2_4_0_, team0_.points as points3_4_0_, team0_.price as price4_4_0_, races1_.resultOfTeams_id as resultOf2_4_1_, race2_.id as races_id1_3_1_, race2_.id as id1_1_2_, race2_.date as date2_1_2_, race2_.location as location3_1_2_, resultofdr3_.races_id as races_id1_1_3_, driver4_.id as resultOf2_2_3_, resultofdr3_.resultOfDrivers_ORDER as resultOf3_3_, driver4_.id as id1_0_4_, driver4_.name as name2_0_4_, driver4_.points as points3_0_4_, driver4_.price as price4_0_4_, driver4_.team_id as team_id5_0_4_, users5_.team_id as team_id2_4_5_, user6_.id as users_id1_7_5_, user6_.id as id1_5_6_, user6_.money as money2_5_6_, user6_.name as name3_5_6_, user6_.password as password4_5_6_, user6_.points as points5_5_6_, drivers7_.users_id as users_id1_5_7_, driver8_.id as drivers_2_6_7_, driver8_.id as id1_0_8_, driver8_.name as name2_0_8_, driver8_.points as points3_0_8_, driver8_.price as price4_0_8_, driver8_.team_id as team_id5_0_8_
    from TEAM team0_
    left outer join RACE_TEAM races1_ on team0_.id=races1_.resultOfTeams_id
    left outer join RACE race2_ on races1_.races_id=race2_.id
    left outer join RACE_DRIVER resultofdr3_ on race2_.id=resultofdr3_.races_id
    left outer join DRIVER driver4_ on resultofdr3_.resultOfDrivers_id=driver4_.id
    left outer join USER_TEAM users5_ on team0_.id=users5_.team_id
    left outer join USER user6_ on users5_.users_id=user6_.id
    left outer join USER_DRIVER drivers7_ on user6_.id=drivers7_.users_id
    left outer join DRIVER driver8_ on drivers7_.drivers_id=driver8_.id
    where team0_.id=?

    Ha ezt végrehajtod az adatbázison valamilyen id-val a ? helyén, akkor megnézheted a duplikátumokat. Kis elemszámú listák esetén is nagy resultset képződik ebből.

    Az, hogy valami lassú, nem számít. Fontosabb, hogy optimális legyen. Ha teszemazt azonnal szükség van x, y, és z táblákból (összetartozó) adatokra, akkor gyorsabb előállítani azokat egy lekérdezéssel. De ha első körben csak az x-re van szükséged, és fontos a reszponzivitás, akkor y és z ráér később, ajánlott a lazy-re állítani. Az igényektől függ, hogy mi a jó megoldás.

    (#6231) jetarko
    Szerintem nem. Eagerben minden táblát join-ol és egy lekérdezéssel letudja az adatok elővételét. Lazyben csak a fő entitást veszi elő, majd a size() metódushíváskor aktiválja a proxyt, ami előállít egy újabb selectet, ami a listát tölti fel értelmes adattal. Tehát utóbbi esetben több független lekérdezés pattan.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz TheProb #6343 üzenetére

    A boolean egy primitív, értéke sosem lehet null. Inicializálatlan esetben mindig false értéket vesz fel.
    A Boolean wrapper osztály egy objektuma már lehet null, de ettől még írható rá logikai kifejezés, pl.:
    if (chkboxValue != null && chkboxValue.booleanValue()) {
    System.out.println("true");
    } else {
    System.out.println("false");
    }

    ... vagy:
    boolean primitiveValue = chkboxValue == null ? false : chkboxValue.booleanValue();
    if (primitiveValue) {
    System.out.println("true");
    } else {
    System.out.println("false");
    }

    Talán alapérték is beállítható valahol a checkbox számára. A lehetőségek száma végtelen. :)

  • Szmeby

    tag

    válasz TheProb #6397 üzenetére

    Számomra pl. az nem hatékony, amikor fel kell emelnem a kezemet, hogy az egérhez nyúljak. Persze én billentyűzettel fejlesztek. :) Rühellem, amikor egy program elvárja, hogy kattintgassak.
    Egyébént mit értesz fejléc alatt? A (névtelen) osztály példányosítását, vagy esetleg azon belül az implementálandó metódust?
    Én ugyan eclipse-ben tolom, de ez code assist és egyszerű hotkeyek segítségével pár másodperc alatt összedobható. Persze nem árt, ha az ember ismeri a frameworkot.

    Ettől függetlenül persze lehet, hogy van erre valami tool, én nem érteni javafx-hez ennyire.

  • Szmeby

    tag

    válasz TheProb #6399 üzenetére

    Eclipse-ben ez így működik:

    gameScene.setOn // Ctrl+Space, kiválasztom a kívánt metódust, enter

    gameScene.setOnKeyPressed( // Ctrl+Space, megnézem, milyen típusokat adhatok meg, Esc
    );

    gameScene.setOnKeyPressed(new EH // new + az osztály kezdőbetűi, Ctr+Space, enter a kívánt osztályon/interfészen
    );

    gameScene.setOnKeyPressed(new EventHandler<KeyEvent>() { // Ctrl+1 (Quick fix) a pirossal aláhúzott részen, enter (add unimplemented methods)

    });

    gameScene.setOnKeyPressed(new EventHandler<KeyEvent>() {

    @Override
    public void handle(KeyEvent arg0) {
    // TODO Auto-generated method stub

    }

    });

    // kis csinosítgatás, és kész
    gameScene.setOnKeyPressed(new EventHandler<KeyEvent>() {

    @Override
    public void handle(KeyEvent event) {
    engine.handleKeyPressed(event);
    }

    });

    Szerintem ez nem sok gépelés. Ami van, azt meg muszáj, mert honnan is tudná az IDE, hogy a gombnyomást akarom elkapni, vagy azt, hogy az engine-nek akarom továbbítani.

    Persze nem csak interfészen, osztályon is megy a dolog (pl. override methods, generate getters, stb), de asszem ezekhez alapból nincs hotkey rendelve. Egy szabad hotkey hozzárendelése a parancshoz semennyi ideig nem tart.
    Kétlem, hogy a többi IDE (NB, IJI) pont ilyen alap funkciókat ne tudna.
    Vagy félreértettelek.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz glutamin #6802 üzenetére

    Pont ellenkezőleg, ott akad el először. Az a root cause.

    Mikor hiba történik az pl. kivételt (exception) generál, ez megszakítja az adott blokk végrehajtását, a kivétel elkezd visszafelé vándorolni a stack-en. Teszi ezt addig a pontig, amíg azt egy catch ág el nem kapja. Normális esetben a catch blokk csinál is valamit, vagy feloldja a hibát és minden megy tovább onnantól a maga medrében, vagy pl. tovább dobja azt akár egy másik kivételbe csomagolva. Az ilyen elkapom-továbbdobom megoldások eredményezik a "caused by" blokkokat a stacktrace-en. Mire a felhasználó/fejlesztő találkozik a hibával, a kiváltó oka sokszor el is tűnik a felszínen. Ezért érdemes először alul keresni az igazi okot.
    Itt ragadnám meg az alkalmat, hogy megjegyezzem, ne csináljatok üres catch blokkokat, mert ott elveszik a hiba, és később nehéz lesz megtalálni.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz jetarko #6843 üzenetére

    "A másik mód az lenne, hogy db-ben tárolok minden token és értéket..."
    Ismerek olyan rendszert, ahol adatbázisban tárolják az üziket. Megvan az előnye és a hátránya, ahogy a property fájlnak is. Megjegyzem, ott nem a Properties osztályt használják erre, hanem van rá egy egyedi megoldás.

    Én a magam részéről a property fájlt favorizálom, mert nem látom azt az üzleti esetet, hogy ezeknek az üzeneteknek futásidőben változniuk kéne. Van egy programod, támogat 30 különböző nyelvet. Az jó esetben 30 property fájl, csókolom.
    Ha adatbázisban lenne, akkor tuti készítenél hozzá valamit, amivel menet közben szerkeszteni is lehet. Az 30 db textarea. Ilyenkor történik az, hogy "ó, csak a magyar/angol nyelvűt írom át, a többi nem érdekes". És elszabadul a pokol.
    Vagy pl. hogyan tervezed kiírni a "Nincs adatbázis kapcsolat" hibaüzit, ha azt adatbázisban tárolod? :D
    Jó, persze a kivételeket bele lehet tolni a kódba, vagy property-be...

    Természetesen lehet olyan szöveg, ami gyakran változik, annak valóban nem property fájlban a helye, de a labelek, hibaüzik, stb. szerintem nem ilyenek.

  • Szmeby

    tag

    válasz jetarko #6862 üzenetére

    A magam részéről feleslegesnek tartom ennyire túlbonyolítani a dolgot. Ha statikus szövegről van szó, akkor annak a pártján vagyok, hogy tároljuk property fájlban, nyelvenként külön-külön:
    messages_hu_HU.properties
    messages_en_US.properties
    stb...
    Egy új nyelv bevezetése pofonegyszerű... persze ehhez matatni kell a fájlrendszeren.

    Amennyiben vannak olyan szövegek, amelyek gyakran változnak, akkor azok lehetnek adatbázisban (akár in-memory db, akár ennek rendszeres backup-jával). Igazából attól függ, hogy mi a célja, mire használod a szövegeket, mennyire érzékeny adatok ezek, stb.

    Azzal, hogy két helyen tárolod a cuccokat, magadra vetted ezek szinkronban tartásának terhét. Ha ez az igény, akkor nincs mit tenni. Gondoltál a teljesítmény problémákra is, csinálsz hozzá pár komponens tesztet, ezeket akár egy CI rendszerben, akár időnként kézzel megfuttatod, és nincs vele teendő. Legfeljebb majd később átírod, a szoftver úgyis mindig fejlődik. :)
    Sosincs jó megoldás, mindig a körülményektől, a felhasználási módtól függ. Mindig kell kompromisszumokat kötni, de ha már ezt teszem, igyekszem úgy, hogy a lehető legegyszerűbb maradjon a végeredmény. Csak ezt tudom tanácsolni neked is.

  • Szmeby

    tag

    Szoktatok több wart közös jvm-ben futtatni?

    Én most egy embedded jettyvel küzdök. Adott néhány war, egy jettyben, de külön contextHandlerben. Látszik, hogy mindegyik war kap saját classloadert, még jó is lenne, ha ezek nem akadnának össze úton útfélen.

    A probléma gyökere, hogy a resteasy egy uri feloldásakor a javax.ws.rs.core.UriBuilder-t használja (pontosabban annak egy resteasy-féle leszármazottját), az pedig a (szintén resteasy-féle) javax.ws.rs.ext.RuntimeDelegate kvázi-singletonhoz. Itt borul a bili, mivel a webapp1 már létrehozta ezt a singletont a saját classloaderével. Lazy init, hurrá!

    public UriBuilder createUriBuilder() {
    return new ResteasyUriBuilder();
    }

    Érdekes, hogy amikor ráhívunk ennek a példánynak a createUriBuilder() metódusára, akkor az a webapp1 classloaderével betöltött objektumot gyártja le, függetlenül attól, hogy a metódus hívásakor a webapp2 környezetében járunk, a currentThread contextClassLoadere is a webapp2 classloaderére mutat.

    Nem volt még alkalmam megismerkedni a classloaderek világával, valakinek van ebben tapasztalata? Hogyan is kellene - illene - több wart futtatni 1 embedded jetty alól?
    Meg egyáltalán... nem a thread contextclassloaderét kellene használnia egy objektum legyártásakor? Vagy ilyenkor a legyártást végző osztály classloaderét örökli az új objektum? Ezekszerint az utóbbi.

    És persze a problémát az okozza, hogy a visszakapott UriBuilder objektumot ez a szerencsétlen castolná önmagára... vagyis majdnem, hiszen az cast során már képes a webapp2 által betöltött típust használni. :)
    Eredmény: ClassCastException

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz Lortech #6895 üzenetére

    "Amúgy hol vannak a resteasy lib-ek? WEB-INF/lib-ben van mindkét war-ban ugyanaz a verzió?"
    Igen, mindkér war WEB-INF/lib könytárában vannak a jarok. Ugyanaz a verzió, bár szerintem ez már nem sokat számít. :)

    "Én a "-verbose:class" -t is megnézném, hátha valami összefüggés kiolvasható belőle."
    Jaja, tegnap már mentem vele egy kört, de elég nagyok ezek a warok, hogy az eclipse console 2 war esetén is kifusson a maxra húzott pufferből.

    Köszönöm mindenkinek a tippeket, még szenvedek vele egy kicsit.
    Legrosszabb esetben majd futnak külön jettyben.

    Érdekességképpen:
    Thread.currentThread().getContextClassLoader()
    /* WebAppClassLoader=webapp2 */

    org.jboss.resteasy.specimpl.ResteasyUriBuilder.class.getClassLoader()
    /* WebAppClassLoader=webapp2 */
    javax.ws.rs.core.UriBuilder.fromUri(absoluteUri).getClass().getClassLoader()
    /* WebAppClassLoader=webapp1 */

    javax.ws.rs.core.UriBuilder.class.getClassLoader()
    /* sun.misc.Launcher$AppClassLoader@74f2ff9b */
    javax.ws.rs.ext.RuntimeDelegate.class.getClassLoader()
    /* sun.misc.Launcher$AppClassLoader@74f2ff9b */
    javax.ws.rs.ext.RuntimeDelegate.getInstance().getClass().getClassLoader()
    /* WebAppClassLoader=webapp1 */

    org.jboss.resteasy.core.ThreadLocalResteasyProviderFactory (ami egy RuntimeDelegate) rendelkezik egy "org.jboss.resteasy.spi.ResteasyProviderFactory defaultFactory" field-del (ami szintén egy RuntimeDelegate). Bár threadlocal az osztály neve, de azt a funkcióját épp nem használja semmire, hanem a defaultFactory-val dolgozik, amihez a webapp1 anno már készített egy példányt. Ezen a példányon keresztül gyűrűzik be a rossz classloader a másik webapp-ba.

    Az UriBuilder mélyén minden a webapp1 classloaderével készült.
    org.jboss.resteasy.specimpl.ResteasyUriBuilder.class.getClassLoader()
    /* WebAppClassLoader=webapp1 */
    new org.jboss.resteasy.specimpl.ResteasyUriBuilder().getClass().getClassLoader()
    /* WebAppClassLoader=webapp1 */

    Feltételezem, úgy lenne ez szép, ha a közös libek közös classloaderrel töltődnének be (külön webapp-ban?), csak hát erős a gyanúm, hogy a sok war libjei más-más közös részhalmazzal rendelkeznek. :)
    Vaaagy, kicsomagolom a warokat egy helyre, és minden fusson a system classloaderrel. :D
    Ez már nagyon hekkes lenne.

  • Szmeby

    tag

    válasz Lortech #6899 üzenetére

    Hm. Nem rémlik, hogy ezt próbáltam volna. Köszi a tippet, holnap teszek egy próbát.
    Én a másik irányba mozdultam el, hozzáadtam a resteasy cuccait is system classként. Sajnos akkor máshol ütötte fel a fejét a ClassCastException. Végül sikerült elérnem, hogy már el sem indult a cucc. :D
    Vagy azt a custom classloader okozta, már nem emélkszem.

  • Szmeby

    tag

    válasz Szmeby #6910 üzenetére

    Úgy néz ki, sikerül megpatkolni. A jetty által system class-ként alapértelmezetten beállított cuccokat kicsaptam.

    webapp.setSystemClasses(new String[0]);

    Így minden class a webappok saját classloaderével töltődik be, még a RuntimeDelegate singletonból is készül 1-1 példány a webappokban. A PermGen szépen megugrott ennek hatására. :)
    Kicsit pazarló, és talán drasztikus lépés, de úgy tűnik most működik. Még kicsit játszok vele.

    Az kavart meg, hogy a RuntimeDelegate javaxos package-ben volt, míg a resteasy-s leszármazottai org.jboss... package-ben voltak. Kiderült, hogy a RuntimeDelegate IS a resteasy része. Abban a hitben voltam a package alapján, hogy ez valami jdk-s cucc. És mivel a default jetty beállítások miatt ez a system classloaderrel töltődött be, meg sem fordult a fejemben, hogy ez a resteasy libből jön.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz geckowize #6923 üzenetére

    Na igen. Ha kényszeríted, nem adja meg magát. :)

    Bezzeg így:

    byte x = 3;
    byte y = 5;
    byte a = (byte) maxObject.max(x,y);
    System.out.println(a);

    Az oké, hogy a paraméterek mind elférnek a double által lefoglalt területen, viszont így kénytelen vagy double típust visszaadni. A double értéket viszont csak double típusú változóba tudsz beletölteni hiánytalanul.
    Ha lefelé castolod (pl. byte-ra), akkor információ veszhet el.
    Egy nagy vödörből nem tudod az összes vizet áttölteni egy kis vödörbe. Viszont ha a nagy vödörben eleve kevés víz van, és ezt tudod is, akkor az áttöltés veszteség nélkül megoldható. Bocs a hülye metaforáért. :)

    Bár gányolásnak tartom, de ennél a példánál (két szám maximumát adja vissza) nincs túl nagy veszély. A programozó józanságára van bízva, hogy ha byte-okat ad be, akkor byte-ot biztonságosan visszakaphat. Ha az egyik int lenne, de az érték nem változna, még az is oké. Viszont ha az int értéke pl. 300, akkor gáz van, mert az nem fér bele a byte-ba.
    De még 2 byte paraméternél is lehet gond, ha nem maximumot ad vissza a metódus, hanem az összegüket. Bár ez double esetén is gond, ha elegendően nagy számokkal dolgozol.
    Amúgy azért nem szeretem ezt, mert figyelmetlenségből is könnyű rontani, ami egy nagy alkalmazásnál aranyos bugokat szül.

  • Szmeby

    tag

    válasz RexpecT #6966 üzenetére

    Joda-time?

    DateTime now = new DateTime();
    DateTime tomorrow = now.plusDays(1);
    if (tomorrow.isAfter(now)) {
    doIt();
    }

    java.util.Date típusra ide-oda tud konvertálni is, ha szükséged van rá.

    Vagy ha nem bírod a 3rd party librarykat, akkor java8 LocalDateTime?

    LocalDateTime.from(new Date().toInstant()).plusDays(1);

    Rengeteget szívhatsz a másodpercek babrálásával. Az, hogy 1 óra 3600 másodperc, pont annyira igaz, mint hogy egy év 365 nap... vagy mint fentebb, hogy 1 nap 24 óra. Általában igaz, kivéve a kivételek esetén. :)
    A daylight-savig csak egy a sok hülyeség közül. Vannak szökőévek, elcsalt másodpercek, időzónák, saját elcseszett DLS megoldásokkal, borzalom.
    Javaslom a jodát, hasznos kis eszköz.

  • Szmeby

    tag

    válasz szcsaba1994 #7030 üzenetére

    Ilyesmire gondolsz?

    public class Main {

    static abstract class A {
    private final int f1;
    private int f2;
    A() {
    this.f1 = 100;
    }
    A(int f1) {
    this.f1 = f1;
    }
    void setF2(int f2) { this.f2 = f2; }
    int getF1() { return this.f1; }
    int getF2() { return this.f2; }
    }

    static abstract class B extends A {
    private final int f3;
    private int f4;
    B(int f3) {
    super();
    this.f3 = f3;
    }
    B(int f1, int f3) {
    super(f1);
    this.f3 = f3;
    }
    void setF4(int f4) { this.f4 = f4; }
    int getF3() { return this.f3; }
    int getF4() { return this.f4; }
    }

    static final class C extends B {
    C() {
    super(300);
    }
    C(int f1) {
    super(f1, 3000);
    }
    C(int f1, int f3) {
    super(f1, f3);
    }
    C(int f1, int f2, int f3) {
    super(f1, f3);
    setF2(f2);
    }
    }

    public static void main(String[] args) {
    A a = new C(1, 3);
    a.setF2(2);
    System.out.println(a.getF1() + ", " + a.getF2());

    B b = new C(10, 30);
    b.setF2(20);
    b.setF4(40);
    System.out.println(b.getF1() + ", " + b.getF2() + ", " + b.getF3() + ", " + b.getF4());

    C c = new C();
    c.setF2(200);
    c.setF4(400);
    System.out.println(c.getF1() + ", " + c.getF2() + ", " + c.getF3() + ", " + c.getF4());

    c = new C(1000);
    System.out.println(c.getF1() + ", " + c.getF2() + ", " + c.getF3() + ", " + c.getF4());

    c = new C(10000, 30000);
    System.out.println(c.getF1() + ", " + c.getF2() + ", " + c.getF3() + ", " + c.getF4());

    c = new C(100000, 200000, 300000);
    System.out.println(c.getF1() + ", " + c.getF2() + ", " + c.getF3() + ", " + c.getF4());
    }

    }

    A super kulcsszó a barátod. Ezzel hívhatod meg az ős konstruktorát, itt adhatod át a konstruktor argumentumokat is. Ezeket vagy kívülről kapja a konstruktor, vagy akár egy konstanst is átadhatsz, attól függ, mi a cél. A fieldeket beállíthatja konstruktor, vagy ha példányosításkor még nem tudod, akkor setter. Most vegyesen vannak.

    Lehet több konstruktor is egy osztályon belül, természetesen eltérő paraméterezéssel. Lehet default konstruktor. Ha default konstruktort hívsz, a super(); lényegében elhagyható, mivel a compiler mindig belefordítja. Mindig az első sorba... tehát az ős mindig készen fog állni arra, hogy az adattagjait piszkálhasd.
    Ha nem tetszik a konstruktoron belüli setter hívogatás, a fieldeket teheted protecteddé, így közvetlenül is értéket adhatsz nekik. De ilyenkor a csomagon belül minden más osztály is írhatja ezeket az adattagokat.

  • Szmeby

    tag

    válasz Anita330 #7174 üzenetére

    Hát, hajrá, hajrá.
    Én első körben kideríteném, mi az a Newton-módszer. Ilyesmikre a wikipedia jó kiindulópont szokott lenni.
    Aztán átültetném ezt egy olyan nyelvbe, amiben változóknak lehet értéket adni, meg mindenféle vezérlési szerkezetekkel lehet ezeket piszkálni.
    A szemfülesebbek 2 kattintásból is találnak hozzá pszeudokódot.
    Persze megérteni azt is meg kell, de jóval egyszerűbbé válik átültetni az egészet javaba. És végülis erről szól az alkalmazott matek, nem?
    Egy munkahelyen ennél azért jóval húzósabb feladatokat kell majd csinálni, és sokszor nemigen akad olyan, aki megmondja a tutit.

    A gyengébbek persze matlabozhatnak is, de egy java fórumon ilyet csak nem mondok. Én amúgy javaban csinálnám, mert a matlabhoz még annyira sem értek. :)

    Amúgy elég sok az átfedés a feladatok között... szabad csapatban dolgozni?

  • Szmeby

    tag

    válasz Oppenheimer #7186 üzenetére

    Kicsit későn lövöm el a hsz-t, feltartottak. Talán ad ötletet.
    --------
    Szerintem fixen belőtt annotációkkal nem fog menni, mivel nem egyértelmű, hogy melyik fetch módot kell alkalmazni.
    Alap, hogy minden lazy. Mivel csak a REST hívás beérkezésekor tudod eldönteni, hogy adott esetben melyik kapcsolatot kell eager fetchelni, nincs mese, runtime ott helyben kell megmondanod neki.

    Erre sokféle módszer létezik, hogy melyik szép, azt nem tudom.

    1. Ha a user a filmre kíváncsi, előkeresed a filmet, majd ráhívsz a getActors() metódusra (ez úgy tudom meglöki a proxy-t és ha sessionben vagy, akkor feltölti az actorokkal is).

    2. Talán named query használatával (movie és actor joinnal) ez a bohóckodás egyszerűbbé tehető.

    3. Rémlik valami olyasmi, hogy JPA/Hibernate alatt runtime felülbírálható a fetch mód. De itt is áll, hogy minden lazy és szükség esetén adott hívásnál döntöd el, hogy mit nyomatsz eagerrel. Mintha valamiféle fetch profilt kellene ehhez létrehozni (ezzel jól megannotálva az entitást), és az entitás lekérésekor elég csak a profilra hivatkozni.

    4. ...

    Sajnos nagyon régen Hibernate-eztem, nem biztos, hogy ezek a legjobb megoldások, vagy hogy egyáltalán működnek.
    A hibernate doksit nézted már?

  • Szmeby

    tag

    válasz Oppenheimer #7195 üzenetére

    Ha más lehetőség nincs a copy-paste mindig segít. :D
    MovieEntity a JPA-nak, MovieRepresentation a JSON parsernek, és a kettő közé egy finom konverter, ami egyikből másikat csinál. A két eszköz nem fog egymásnak bekavarni, a konverterben meg célzottan meg tudod adni, miből mikor mit csináljon.

  • Szmeby

    tag

    Jobban belegondolva a google is szereti halmozni a rest hívásokat. Jó, persze mögötte ott egy bazinagy elosztott rendszer.

    Pl. gmail:
    Listás nézetben csak az első x db mail látszik (sender, subject és esetleg a body eleje). Nem fogja lehúzni az összes email összes tartalmát. Sőt egy conversationbe belépve sem tölt le mindent, csak az elsőt meg az utolsót. Ha akarod olvasni a többit majd kattintasz és lehúzza azokat is.
    Ez soksok apró hívás, mindig csak a legszükségesebbet letöltve. Így fenn tudja tartani a látszatot, hogy ő milyen gyors. Szóval lehet ezt hatékonyan csinálni, csak meg kell találni az egyensúlyt. :)

    Megjegyzem, a konvertálgatást csak utolsó mentsvárként javasoltam.

  • Szmeby

    tag

    válasz Oppenheimer #7207 üzenetére

    Az alapvető probléma az, hogy két helyen kell ugyanazt karbantartani. Amíg csak néhány entitásról van szó, oké, de amikor elkezd növekedni a számuk, és elkezdenek ezek változni is, akkor születnek újabb bogárkák. :)
    Mert például valaki elfelejtette átvezetni a módosítását a másik osztályba, elfelejtődik, és később jönnek a hibák.
    Röviden: a duplikált kód rossz.

    Ez persze nem jelenti azt, ne lehetnél vele boldog, csak érdemes jobb megoldás után kutatni.

    Láttam olyan helyet, ahol ennek a menedzselésére bevezették a kódgenerálást. Ott aztán már durva állapotok vannak, ha az ember ilyesmire kényszerül. Egy xtend leíróban legózhatod össze a java forráskódot töredékekből, ezzel többféle forrást is generálhatsz, amit majd a compiler fordít, stbstb. Így xtend-ben kell egyszer megírni a cuccot és az akár 20 féle DTO-t is kigenerál neked. Vagy amennyit akarsz. Tiszta káosz. Cserébe viszont az xtend nehezebben olvasható. Vagy lehet, hogy csak szokni kell. Szerencsére nem sokáig kellett gyönyörködnöm benne.

  • Szmeby

    tag

    válasz norbert1998 #7435 üzenetére

    Szia!

    Az ember maximum 7 dolgot tud egyszerre fejben tartani. A program komplexitása messze meghaladja ezt a számot. Vagyis az időd nagy részét arra pazarlod, hogy a fejedből kieső információt folyamatosan töltöd vissza, miközben ettől függetlenül hibát is keresel. Ne csodálkozz, ha nem megy. Senkinek sem menne.

    Az oktatás célja új tudásanyag átadása, és nem a szívatás. Ha tömbök használatát kell gyakorolni, akkor gyakoroljátok, de ezt nem egy átláthatatlan programon kell csinálni, mert az már nem a tömbök használata lesz. Ezzel csak arra akarok célozni, hogy bizonyos komplexitás elérésekor meg KELL tanulni a kód kisebb egységekre bontásának módjait. Különben az energia egyre nagyobb részét fogja felemészteni az, hogy próbálod megérteni, mi történik, és egyre kevesebb figyelem jut a tényleges gyakorlásra.

    A nehezebb mód az, hogy tovább görcsölsz rajta, és majd egyszer sikerül rátalálni az egyik hibára. Sajnos hátra van még a többi hiba is. Mindig van egy újabb hiba. ;)
    Ezen valamelyest javíthatsz, ha elkezded debugolni: teszel egy breakpoint-ot a problémás rész elé, és debug módban indítod a programot. Majd szépen lassan, soronként egyesével lépkedve, a változók értékeit folyamatosan ellenőrizve megnézed, mit is a csinál a gép.

    A könnyebb (és melósabb) mód, ha legalább megtanulsz metódust készíteni.

    Első lépés:
    public class Beadando {
    public static void main(String[] args) {
    new Beadando.doit();
    }

    // ez egy példány szintű metódus, nincs visszatérési értéke, nincs paramétere
    public void doit() {
    // a main helyett ide kerül minden
    }
    }

    A static main metódus a program belépési pontja, ugyan a Beadando osztályban van (mert valahova tenni kell), de nem sok köze van hozzá. Ami a main-ben történik, hogy az osztályból készül egy példány, és azonnal ráhívsz annak egy példány szintű (nem static) metódusára. Én doit-nek neveztem, te úgy nevezed, ahogy akarod. Minden más marad a régiben.

    A következő lépés lehetne mondjuk a Beadando által gyakran használt változókat kiemelni, field-et csinálni belőle. Ha nem lenne egy Beadando példányod, ezt nem tehetnéd meg ilyen szépen. Pl. én kiemelném az adatot tartalmazó tömböket, sőt a színeket tartalmazó konstansokat is:
    public class Beadando {
    private static final String RESET = "\u001B[0m";
    private static final String RED = "\u001B[31m";
    private static final String BLUE = "\u001B[34m";
    private static final String CYAN = "\u001B[36m";
    private int n=500;
    private String [] nev =new String [n];
    private String [] gazdnev =new String [n];
    private String [] tomeg =new String [n];
    private String [] kor =new String [n];

    public static void main(String[] args) {
    new Beadando().doit();
    }

    public void doit() {
    // ide kerül minden
    }
    }

    Értelemszerűen ezeket már nem kell belül létrehoznod, elég hivatkozni rájuk. Javaban a konstans static és final módosítóval is rendelkezik, a példány szintű field-eknek nem kell static-nak lenniük. Nem is ajánlott.

    new Beadando()
    Ez készít egy példányt az osztályból. Mivel az osztálynak még nincs látható(!) konstruktora, az alapértelmezett konstruktor (aminek nincs paramétere) használható a példányosításkor.

    A tömb mérete nem túl szép ott a field-ek között, lehetne akár konstruktor argumentum. A konstruktor tekinthető egy spéci metódusak is, máshogy is néz ki. Ő csak egyszer hajtódik végre, a példány létrehozásakor. A tömböket is elég ilyenkor lefoglalni:
    public class Beadando {
    private static final String RESET = "\u001B[0m";
    private static final String RED = "\u001B[31m";
    private static final String BLUE = "\u001B[34m";
    private static final String CYAN = "\u001B[36m";
    private String [] nev;
    private String [] gazdnev;
    private String [] tomeg;
    private String [] kor;
    private int n;

    public static void main(String[] args) {
    // new Beadando(500).doit();
    // vagy akár így is lehet példányosítani és ráhívni az egyik metódusára:
    Beadando beadando = new Beadando(500);
    beadando.doit();
    }

    // ez a konstruktor, van egy int argumentuma, ebben lesz majd az 500
    public Beadando(int n) {
    this.nev =new String [n];
    this.gazdnev =new String [n];
    this.tomeg =new String [n];
    this.kor =new String [n];
    this.n = n; // ha esetleg még valahol hivatkoznál az n-re, a this.n-nel ezt megteheted
    }

    public void doit() {
    // ide kerül minden
    }
    }

    A field-ekre a this. prefix-szel hivatkozhatsz, de elhagyható, ha a neve nem ütközik más változó nevével.

    Első blikkre egész szépen kiszervezhetők metódusokba a case blokkokban lévő cuccok. Kezdd a belül lévő legkisebbekkel. Kommentekkel még el is nevezted őket, szinte adja magát.
    Pl. ebből:
    // ...

    public void doit() {
    // ... a doit elején lévő cuccok
    case 3 : { //főmenü 1-es menüpont->2-es menüpont
    String kereses=extra.Console.readLine("Milyen korút keressünk?");
    db=0;
    i=0;
    while(kor[i++]!=null){
    }
    for (int g=0;g<i;g++){
    if (kereses.equals(kor [g])){
    torvalogatas[db]=g;
    db++;
    }
    }
    break;
    }
    // ... a doit végén lévő cuccok
    }
    }

    Ez lesz:
    // ...

    public void doit() {
    // ... a doit elején lévő cuccok
    case 3 : { //főmenü 1-es menüpont->2-es menüpont
    db = keresKorra(torvalogatas);
    break;
    }
    // ... a doit végén lévő cuccok
    }

    // ez egy új metódus, az osztályon belül, de a doit metóduson kívül
    private int keresKorra(int[] torvalogatas)
    String kereses=extra.Console.readLine("Milyen korút keressünk?");
    int db=0; // Figyelem! Ez a db, nem a metóduson kívül található db.
    int i=0; // Ahogy ennek az i-nek sincs semmi köze a külső i-hez. Ezek csak itt belül léteznek.
    while(kor[i++]!=null){
    }
    for (int g=0;g<i;g++){
    if (kereses.equals(kor [g])){
    torvalogatas[db]=g;
    db++;
    }
    }
    return db; // Itt a metódus futása megszakad és visszatér a return mögött található változó értékével.
    }
    }

    A metódusokat tetszőleges sorba rendezheted, azokat, amelyek hasonló dolgot csinálnak, egységesítheted. Amelyek pedig ugyanazt csinálják, több helyen újra felhasználhatod, eltérő paramétereket adva neki.

    private int keresKorra(int[] torvalogatas)
    Az első elem egy láthatóságot szabályozó módosító, a private csak az osztályon belül látható, a public bárhol, a többi most nem érdekes, jelen esetben teljesen mindegy, melyiket használod.
    A következő a metódus visszatérési értékének típusa. Sajnos max. csak 1 db visszatérési értéke lehet egy metódusnak, ez most egy int (a metódus törzsében található return utasítással adod majd vissza a tényleges értéket). Ha a metódus nem kell, hogy visszaadjon értéket, akkor a típus a void lesz (a return pedig elhagyható).
    Aztán jön a metódus neve, tetszőleges, bár a szokásos névkonvenciók rá is vonatkoznak, kezdődjön kisbetűvel, és az ékezetes betűket inkább hanyagold.
    A zárójelek között pedig vesszővel elválasztva felsorolod a metódus paramétereit (típusa és a metóduson belül használt neve).
    Ha a metódusban kivételt is dobunk és azt nem kapjuk el, akkor a ) után szerepel a throws kulcsszó és a kivételek vesszővel elválasztva, pl.: void metodusNeve(String param1, int param2) throws IOException { }. A fordító majd úgyis reklamál, ha ilyet kell csinálnod.

    A return a metódusban bárhova tehető, de ha a vezérlés elér hozzá, - akár egy ciklus kellős közepén is vagy - a metódus futása megszakad és visszatér az adott változó aktuális értékével. Ez alól csak a finally blokk kivétel, mert az abban lévő cucc a metódus elhagyása előtt még gyorsan megfut.

    A metódus felhívása így történik:
    db = keresKorra(torvalogatas);
    Metódus neve, és zárójelben vesszővel elválasztva felsorolod az átadni kívánt paramétereket. Ha a metódus valamilyen értékkel is visszatér (nem void), akkor azt az értéket el is tárolhatod egy változóban, most a db változóba tettük egy sima értékadás keretében. Persze ha kint nincs szükséged a visszaadott értékre, nem kell azt mindenáron változóba tenni, az értékadás elhagyható.

    A metódus törzse egy külön világ, itt csak a field-eket és a beadott paramétereket látod, ezekkel dolgozhatsz.
    A paraméterek érték szerint adódnak át. Ez primitív típusoknál (int, char, boolean, stb.) egyértelmű, az érték átadásra kerül, de a metódusban bármit is csinálsz vele, az a metóduson kívül nem fog érvényre jutni. Immutable típusoknál (pl. String) sincs veszély, mert azok úgy lettek megalkotva, hogy bármit is csinálsz vele, magán az objektum állapotán nem változtat, inkább új objektumot hoz létre.
    Viszont van minden más (pl. a fentebb említett Dog osztály, vagy éppen a tömbök), amelyek akár több értéket is képviselhetnek. Ezért aztán csak azok memóriacíme kerül értékként átadásra, így ha ezek tartalmát módosítod a metóduson belül, a módosításod a metóduson kívül is érvényre jut. Hiszen a metóduson kívül létező tömb és a metódusnak átadott tömb címe ugyanaz, ugyanazt a memóriaterületet piszkálod.
    És itt jutottunk el ahhoz a csúnya megoldáshoz, amit alkalmaztam: átadtam a torvalogatas tömböt a metódusnak, pedig az csak ír bele. Nem szép dolog metóduson belül a paramétereket változtatni, normális esetben csak olvasni szabadna, de ez például egy módszer arra, hogy a metódus több dolgot is változtasson (mivel csak egy visszatérési értéke lehet, és azt a db-re elpazaroltuk).
    Persze a több visszatérési értékre van más megoldás is, pl. minden visszaadandó cuccot becsomagolni egy objektumba, de egyelőre szerintem ennyi is elég.

    Kellemes refaktorálást. Miközben bontod szét a kódot, valószínűleg a mostani hiba okát is meg fogod találni. Ha lehet, említsd meg a tanárnak, hogy az ezersoros programod kezd átláthatatlanná válni, meséljen már az osztályokról, példányokról és metódusokról.

    Ami pedig az érettségit illeti: Egy problémát meg lehet oldani jól és hatékonyan, de meg lehet oldani gányolással is. Nem kell ismerni az osztályokat, a metódusokat, de még a for ciklust sem hozzá. Csak éppen évekkel tovább tart a megoldás, és lehet hogy kapsz rá egy kettest. És egy bizonyos méret felett az ember már nem a megoldással foglalkozik, hanem a kapálózással, hogy a víz felszínén tudjon maradni. Kizárt, hogy érettségin ne kelljen ezeket az alap dolgokat használni. De tedd fel magadnak a kérdést: Könnyű érettségit akarsz? Jó munkahelyet magas fizuval? Ha igen, és a tömböket már unalomig gyakoroltad, akkor érdemes továbblépni a List-re. Annyi hasznos dolog van még a nyelvben, sose jutsz a végére.

    Bár lehet, hogy feleslegesen pötyögtem... csapd fel a tankönyvet a metódusnál és hajrá.

    Persze a legjobb az lenne, ha az osztályok és metódusok után egy elegáns mozdulattal telepítené mindenki a junit-ot, és TDD-ben gyakorolnátok tovább. Mennyivel könnyebb lenne az immáron jól struktúrált kódon megtalálni a hibákat. És a refaktorálás is veszélytelenebb lenne. Szép álom.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz norbert1998 #7482 üzenetére

    A j egy nemnegatív szám. A k megy j+1-től j-ig, és növekszik. Csodálkozol, hogy nem csinál semmit? :)

  • Szmeby

    tag

    válasz sutszi #7524 üzenetére

    2. What about this?
    Tudtommal csak az awt tud ikont pakolni a system tray-re. Hogy buborékra képes-e, azt passzolom. Majd meséld el.

    [ Szerkesztve ]

  • Szmeby

    tag

    válasz floatr #7631 üzenetére

    A szmájliból talán sejthető, hogy nem gondoltam komolyan, amit írtam.

    A visibility modifier-es kérdést viszont helyénvalónak érzem. Aki "életvitelszerűen" használja a javat, annak gondolkozás nélkül megy. A csak elméletet ismerőnek pedig csak egy újabb kézzel megfoghatatlan bemagolható valami.

    Szerintem a kérdés inkább a gyakorlottságot akarta felderíteni. Ha az ember írogat magának programokat, és legalább egy értelmes könyvet olvasott már (pl. Effective Java - Bloch, Clean Code - Martin, Refactoring - Fowler, stb), ennek mennie kell, és ehhez nem kell munkatapasztalat.

  • Szmeby

    tag

    válasz alfa20 #7679 üzenetére

    Szia!

    Hehe, Eclipse telepítés után első dolgom lekapcsolgatni a key bindingokat. :)

    Window -> Preferences -> General -> Keys:
    Majd a szűrőbe bepötyögöd, hogy Ctrl+Alt+B
    Kijelölöd a problémás összerendelést, és Unbind gomb. Vagy beállíthatsz valami neked tetsző kombót is.

    Csekkold a többi Ctrl+Alt+ kombót is, valószínűleg nem ez lesz az egyetlen.

  • Szmeby

    tag

    válasz emvy #7683 üzenetére

    Ja, pont akkora őrültség, mint aki a magyar mondataiban nem használ ékezetet. :P

  • Szmeby

    tag

    válasz szcsaba1994 #7845 üzenetére

    Azt értem, hogy nem szabad, de azt nem, hogy miért nem?
    Mi az oka annak, hogy a fejlesztő nem struktúrálhatja a kódját úgy, ahogy az szerinte használható és átlátható?
    Remélem nem az, hogy a prof könnyebben kinyomtathassa az 1 db fájl tartalmát.

    Egy normális világban / OO nyelvben egy kicsit is komplexebb megoldást nem egy osztály valósít meg. És akkor csodálkozunk, hogy az egyetemről érkezők olyan minőségű kódot produkálnak, amilyet. (Én is ilyet produkáltam, és utólag visszanézve nem vagyok rá büszke.)
    Szerencsétlenek nem hogy nem látnak mást, még a kreatívabb kisebbséget is megkötik az idióta szabályaikkal.

    Lortech: A nested class is egy újabb osztály. Bár nem erről szólt a feladat, de ha úgy tartja kedvem, 826 osztályt is tehetek egy fájlba, csak éppen rettentő gusztustalan lesz.
    Persze ebben az esetben én is inner classra szavazok, nagyon ide kívánkozik. Inkább, mint az egymásba ágyazott konténerek végeláthatatlan sora. Vagy akkor szívassuk meg a tanárt, és az olvashatatlanságig bonyolítsuk túl, legyen neki is pár kellemes órája, amíg kitalálja, mit csinál.

    [ Szerkesztve ]

Új hozzászólás Aktív témák