"A Kotlin az Java, csak jobb!"

Címkék

Július 26-án 30 órás online képzést indítunk Modern Android fejlesztés Koltin alapokon címmel. A képzés hiánypótló, hiszen Kotlin nyelv rövid úton kiváltja a Javát az Android ökoszisztémában - a Google támogatásával. A tananyag tartalmazza már az ősszel érkező Android Jetpack újdonságait is. A képzés online követhető és bármikor visszanézhető, így nyaralás-kompatibilis. Sőt, az órák időpontjainál figyelembe vettük a focivébé menetrendjét is, különös tekintettel a kieséses szakaszra. További részletek »

Hozzászólások

Én azért nem tartanám vissza addig a levegőt, amíg le nem váltja a java t :)

Nem elengedte, csak van egy Java 2.0 végre :)

Eléggé nehéz Python-on, C#-on, JavaScript-en és hasonló nyelveken felnőtt embereket rávenni Java-ra, annyira el van maradva a többitől. A Kotlin megváltás...

Cserébe a temérdek Java-ban írt lib még mindig használható.

pl:

  • nincs property (a getXX setXX metódus nem az!)
  • checked exception eredetileg jó ötlet volt, én is nagyon szerettem, de sajnos az évek tapasztalatai után egyetértek az ellenzőkkel
  • egyszerű típusok API-ja teljesen más, mint az objektumoké (azaz nem teljesen objektum-orientált a nyelv...)
  • tömb - ennek is egy vicc az API-ja, ld. egyszerű típusok, ráadásul nem collection
  • nincs operator overload, még korlátozottan sem - kivéve a String.concat-ra a + ! Arra bezzeg csináltak.
  • az API-ban évek óta benn levő bugok nincsenek kijavítva, pl. a java.util.Map.put metódusa
  • stream api eléggé körülményes
  • objektum initializerek
  • korutinok szerintem a bödös életben nem lesznek
  • NullPointerException (ez már csak azért is vicc, mert a Java-ban nem pointerek vannak, hanem referenciák, de mindegy)
  • type inference - ez verzióról verzióra javul, de van még hova fejlődni

És még lehetne gyűjteni sok mindent, amit a későbbi verziókban már javítottak (pl var kulcsszó). Tessék megnézni, hogy pl. a 8-as Java (stream API, végre használható date-time API, és a legfontosabb: lambdák!) milyen későn jelent meg,

C# fejlesztés után mindig fáj visszatérni Java-ra, egyszerűen a nyelv annyival kényelmetlenebb. Az IDE-k sokat segítenek, hogy spóroljunk a gépeléssel, de olvasni akkor is gáz. A stream API pedig egy vicc a LINQ-hoz képest (mondjuk semelyik másik nyelvben nincs ekkora állatság, a LINQ nagyon egyedülálló).

A Java előnye az, hogy viszonylag egyszerű a nyelv, irtózatosan nagy az ökoszisztémája, szinte mindenre van valami opensource vagy vásárolható lib (csak soros portot ne akarj kezelni...). A másik előnye lenne a platformfüggetlenség, habár ez manapság már a .NET-tel szemben sem lesz előny (.NET core).

Én szerettem a Java-t, C++ után tetszett, hogy egyszerűbb, illetve a garbage collector ott van mögöttünk, van sztenderd API-ja XML kezelésre, GUI-ra, adatbázis-ra, ésatöbbi. A collection framework-je nagyon jó volt a maga idejében, a java.util.concurrent is eléggé fejlett volt. A kód static analysis-e könnyen megoldható, és eléggé jó is volt.

Sajnos azonban sok mindenben lemaradtak, és tizenpár év Java fejlesztés után már nem tudom elnézni ezeket a hátrányokat - egyszerűen idegesítenek.

Azt remeltem leirod, hogy miben elmaradott a nyelv, vagy, hogy az emlitett nyelvek mit csinalnak sokkal jobban, de igazabol joreszt koncepcios dolgokat emlitettel, amik raadasul szemelyes izlest is tartalmaznak. Felre ne ertsd nem hiszem, hogy a Java a tokeletes nyelv, de azt sem hiszem, hogy letezik ilyen. Regenyt lehetne irni a Python hibairol, vagy a Javascriptrol. Nem vagyok jartas a C#-ban, de mondjuk a Go-ban igen. A Go egy rohadt modern nyelv, es vannak benne olyan hajmereszto koncepciok, amitol a legtobb newbie sarkonfordul es elmegy :)

"nincs property" lehet nem ertem pontosan, de sajat kododban nem kotelezo getter/setter-t irni (a legtobbet ugyis sajat kodbazissal interaktalsz). Barmihez barhonnan hozza lehet ferni, csak nem szokas. De nem veletlen, pl sokkal konnyebb immutable osztalyokat csinalni, mint pl Groovy-ban, ahol meg minden public, aztan kulon annotalgatni kell, ha valamit megsem szeretnel a vilagnak kiajanlani.

"checked exception" keves utalatosabb dolog van a vilagon mint a runtimeexception es a leszarmazottjai. Mibol ajt volna a NumberFormatExceptiont kezelt kivetelle tenni. igyis-ugyis minden parsolashoz oda kell irni a try-catch-et, mert Javaban a kivetel egyfajta "visszateresi ertek". Keves dolgot utalok jobban mint forrast/doksit turni, hogy milyen hibak johetnek, neha 5 level melyen (vagy catch (Exception e)-t irni)

"egyszerű típusok API-ja teljesen más, mint az objektumoké" es nem is kotelez senki arra, hogy hasznald. Az autoboxingnak hala, ha te mindehol objektumokat hasznalsz, akkor eszre sem veszed, hogy a hatterben neha ide-oda konvertal. Projekten beluli megegyezes kerdese kb

"tömb - ennek is egy vicc az API-ja" konkretan nincs neki ;) azert vannak a collectionok. Ertelmes kodban alig talalkozol tombokkel, kiveve a String.split() meg a main(String[] args). A tomb a leghatekonyabb modja osszetartozo adatok tarolasanak a memoriaban. Low level adatstruktura

"nincs operator overload, még korlátozottan sem" es meg milyen szerencse

"kivéve a String.concat-ra a + ! Arra bezzeg csináltak" szerintem az nem operator overload, hanem build time optimization. meg a 9es Javaban is finomitottak rajta

"az API-ban évek óta benn levő bugok nincsenek kijavítva" valoszinuleg azert mert az egesz nyelv vezerelve a visszafele kompatibilitas, es tul sokan epitettek mar a hibas mukodesre. Masik Map-et kell hasznalni, mert a java.util.Map egy interface es nem implementacio. A Python sem jobb, ahol a 2-es es 3-as verziok kozott gyakorlatilag nincs atjaras, sok esetben az az erzesem, mintha masik platform lenne. Az meg a masik veglet

"stream api eléggé körülményes" izles dolga, van a nyelvben, nativan, csomo fancy dolgot tud, nem lett a legszebb, de ettol meg nem elmaradott a nyelv

"korutinok szerintem a bödös életben nem lesznek" az tuti, bar sose mondd, hogy soha. A Java by design 1-1 mappingot hasznal os thread es runtime thread kozott. Az osszes core lib erre epul. Nem hiszzem, hogy ezt a koncepciot naivan be fogjak vezetni, ez teny. De ha majd igazan nagy lesz ra az igeny akkor lesz 3rd party megoldas. De ennek megintcsak nincs koze az elmaradottsaghoz. Megint a Go a jo pelda, ami egy modern nyelv, es nem tudsz benne egy treadet letrehozni, epp ezert parhuzamos vegrehajtsra alkalmatlan a nyelv. Viszont eros a konkurrens vegrehajtasban, a Java meg parhuzamos vegrehajtasban.

"pl var kulcsszó" istenem mekkora egy oltari baromsag.

// DANGEROUS: infers as List<Object>
var list = List.of();


// ORIGINAL
byte flags = 0;
short mask = 0x7fff;
long base = 17;

// DANGEROUS: all infer as int
var flags = 0;
var mask = 0x7fff;
var base = 17;

Tenyleg erre van szuksegunk???

"végre használható date-time API" tehat nem elmaradott a nyelv van benne szep, fancy, sokak altal kedvelt date-timae API :)

"a java.util.concurrent is eléggé fejlett volt" Javaban mindenre van tobb implementacio, ilyen kereso algoritmus meg olyan, lockfree meg nem lockfree, a feladathoz lehet valasztani collectiont. Az emlitett elorehaladott nyelvekben, Python/Javascript ez hogy van? Hany fele concurrent collection tipusbol valaszthatok JS-ben mondjuk?

"Sajnos azonban sok mindenben lemaradtak" vegul a koritunin kivul egyet sem emlitettel, ami hianyzo nyelvi feature, es nem nyelvi koncepcio. Raadasul epp az elmult evekben latszik felporogni a dolog, felevente release. Vannak lambdak, modularizacio, hatekonyabb GC algoritmusok (az is pl a Go-ban van 1 azaz 1 db).

"egyszerűen idegesítenek" de azt tudod, hjogy ez nem a nyelv hibaja :D :D :D

En szeretem a java-t, igy tizenpár év fejlesztes utan. Keves nyelvben valogathatok ennyi eszkoz kozul, vagy valaszthatom meg a kulso libeket a felaadthoz (last 1000 fele collection implementacio). Az altalam ismert nyelvek kozul a legkevesebb hulyeseggel/inkonzisztenciaval kell megbirkozni pedig a hello worldnel lenyegesen tobb tapasztalatom van bash, basic, php, python, go, actionscript, java, groovy, javascript, objective-c-ben.

-
Advanced testing of Golang applications

Ekkora regényre nem számítottam, persze hogy csak koncepció szintjén írtam le a gondolataimat, minden egyes témáról sokat lehetne írogatni, gugli segít a bővebben kifejtett válaszok megtalálásában :).

A property hasznos dolog, egyrészt reflection-nél is jól tud jönni hogy egyben van a get/set, másrészt szerintem sokkal olvashatóbb egy értékadás az erre szolgáló operátorral (=), mint set/get függvényhívásokkal. Ez egy plusz absztrakció, pl. egy értékadásnál bármikor kitalálhatod, hogy mégiscsak kell valami ellenőrzést végezni, és ilyenkor az objektum interfésze nem változik, nem kell refactorálni mindent =-ről set()-re. Arról nem is beszélve, hogy külső libekkel sokszor beanekkel tudsz nomrálisan interaktálni, field-ekkel nem annyira (főleg ha van SecutityManager). A láthatóság szintén nem mindegy, a globálisan írható mezők kissé veszélyesek tudnak lenni, még saját kódbázison belül is. Ha valamit lehet írni kívülről, akkor előbb-utóbb az egyik fejlesztő írni is fogja, aztán majd lehet hibát nyomozni.

A checked exception kapcsán pedig egyetértek veled teljesen, csakhogy az évek alatt sokszor tapasztaltam azt, hogy a kikényszerített exception kezelés eredménye nem a kezelés lesz, hanem az exception lenyelése. A legrosszabb dolog, amit egy exception-el tehetsz az, hogy elkapod de nem kezeled le. Ha a drága egységsugarú fejlesztőnek implementálnia kell egy metódust, aminek a során ő találkozik egy checked exception-el, de az interfész, amit implementálnia kell nem definiálja, akkor három eset áll fenn: vagy szól a tervezőnek, hogy ide kellene még egy exception, vagy csomagol, RuntimeException-be vagy valami másba. A harmadik eset az, hogy elkapja, majd lehetőleg ki sem loggozva visszaad valami hülyeséget. Na ilyen kódban próbáld megtalálni a hibát, sok sikert. Ennél jobb koncepció az, hogy a legkülső ponton (pl. uncaughtexceptionhandler, threadpool thread-jei, stb) mindenképpen naplózzuk az exception-öket, és megpróbálunk valami helyreállítást csinálni. Ezt a lépést mellesleg mindenképpen meg kell csinálni, és így legalább a kevesebb tapasztalattal rendelkező fejlesztő sem fogja megszívatni az egész csapatot.
Sokat dolgoztam C#-ban, és ott nincsenek checked exception-ök. Eleinte hiányoztak nekem is, de aztán rájöttem, hogy nem nyersz vele annyit, mint amennyit bukni tudsz. Persze a .NET-ben a dokumentációban részletesen és konzekvensen le vannak írva a dobható exception-ök, ez sokat segít. A RuntimeExcepotion-be csomagolt alkalmazás hibák viszont nem segítenek.

Egyszerű típusok a teljesítmény és a natív libek interakciója miatt léteznek. Mivel nem voltam ott a nyelv tervezésekor, és nem olvastam utána, ezért nem tudom, mi vezetett ahhoz a döntéshez, hogy ezek kezelése a Java-ban teljesen más, mint az objektumoké. Pl. a C#-ban ez meg van oldva, azaz egységes az API és mégis van jó teljesítmény. Az autoboxing (java 5-től van) az inkább csak a probléma elfedése, gyakorlatilag az egyszerű típusok által nyújtott teljesítményt bukjuk el vele, hogy ne fájjon collection-ökbe pakolni őket. A List<Integer> és az int[] között jelentős a különbség, sajnos API szempontjából is. Tiszta szerencse, hogy legalább a foreach működik tömbökkel.

Az operator overloading nagyon veszélyes is tud lenni (lásd Scala), és tényleg nem egy akkora durranás, viszont milyen jól jönne pl. a BigDecimal használatánál ugyebár. Vagy a Matrix-nál. Ahol sok az aritmetika, na azt kimondottan fáj Java-ban csinálni az operátorok hiánya, a property-k hiánya és az automatikus típuskonverzió miatt. A string + az nem build optimization (oké, annyira azért mégis, hogy StringBuilder lesz belőle), hanem a + operátor felül van bírálva string-ekre. Ha már nincs overload, akkor miért van mégis overload-olva a + ? Jó, én örülök neki, hogy van ilyen, de még jobban örülnék, ha BigDecimal-ra is lenne. Ami viszont nagyon hiányzik, az asszociatív tömb-szerű indexelés. Nagyon jó lenne, ha lenne, de hát nincs overload, csak a String-re (kivéve a gyevi bíró, ja)

A var-os példádban nem a var kulcsszóval van baj, hanem a type inference fos, amit speciel említettem is korábban, hogy nem elég jó :) Az első példádnak ott fordítási hibát kellene dobnia (nem tudom, nem próbáltam a 10-es Java-t). Kotlinban, C#-ban pl. az ilyen kód nem fordul. A számokkal pedig szintén nem lenne gond, ha a java nem konvertálna automatikusan, number literalok pedig igenis vannak a nyelvben (pl. 0.1d = double és nem float). A dadogós "EzEgyNagyonHosszúClassNév változó = new EzEgyNagyonHosszúClassNév(dsjhdks)" viszont kimondottan gáz, na erre való a var kulcsszó.

A nyelvvel van bajom elsősorban, a runtime többnyire rendben van, legalábbis nem rosszabb a többieknél. Persze pl. a datetime api-nál miért kellett várni a 8-as verzióig, és ha már a jodatime-ot vették át, akkor miért maradt ki egy-két metódus, illetve ennyi erővel maradhatott volna a package, az már jó kérdés.

Az ökoszisztéma miatt pedig kifejezettem kedvelem a JVM világot, csak minél többet használok jobban kézreálló nyelveket, annál jobban fájnak a Java hibái. Ezért örülök különösen a Kotlin-nak, mert habár itt is vannak hülyeségek (pl. Unit visszatérési érték, stb), de olvashatóbb a kód és hamarabb meg tudom benne írni, amit kell. És persze 100% kompatibilis a Java libekkel/classokkal, enélkül nem lenne jó :)

Ja, az API bugok: na erre még nem találtam magyarázatot, hogy a Map<K, V> esetén a put(Object, V) kijavítása put(K, V)-re mégis mily módon okozhatna visszamenőleges kompatibilitási problémákat? Ha emiatt nem fordulna a kód, ott az eleve hibás volt! (valójában de, tudok ilyen hibás kódot írni, ami mégsem fog exception-t dobi, de bakker, ez a type erasure miatt csakis compile-time érdekes, runtime nem. áááá)

Scalaban technikailag nem operator overloading van, egyszerűen csak megengedő a nyelv a metódusnevekkel szemben. Teszem hozzá, ugyanezt tudja pl. a Ruby is. Nyilván ésszel kell használni, de vannak előnyei, pl. lehet custom DSL-t építeni.

Ha szigorúbb szabályokat szeretnél de mégis szeretnéd megőrizni az operator overloadingot, akkor a Lua megoldását érdemes megismerni. Pl. nem tudod egymástól függetlenül definiálni a <, >, <=, >= operátorokat, azt majd a runtime megoldja, hogy melyik metametódusba kell behívni. Talán nem túl meglepő, de ilyesmi Scalaban is van: https://ideone.com/wq9pgb :)

"itt is vannak hülyeségek (pl. Unit visszatérési érték, stb)"

A Unit visszatérési érték értelmes. Az nem is függvény, aminek nincs visszatérési értéke. Ezt a problémát oldja fel a Unit, így tudsz olyan függvényt definiálni, aminek valójában nincs visszatérési értéke. Ennek akkor van jelentősége, amikor egy ilyen függvényt pl. szeretnél függvényreferenciaként átadni.

Még egy gondolat a típusokkal kapcsolatban: pl. Scalaban nincsenek primitív típusok annak ellenére, hogy JVM-re fordul. Azt majd a fordító eldönti, hogy hol tud primitív típust használni és hol referencia típust. Így teljes a típushierarchia, az Any típus magában foglalja az AnyVal értéktípusokat (pl. Boolean, Int) és az AnyRef referenciatípusokat (pl. java.lang.Object) is.

"szerintem sokkal olvashatóbb egy értékadás az erre szolgáló operátorral (=), mint set/get függvényhívásokkal" eldontheted melyiket valasztod. Persze a kulso lib fejlesztoje is eldonti.

"globálisan írható mezők kissé veszélyesek tudnak lenni" immutable a kulcsszo. nem fogja irni :D

"hogy elkapod de nem kezeled le" de ez egyaltalan nem a nyelv hibaja, hanem a kodere meg a reviewere

"és megpróbálunk valami helyreállítást csinálni" hat ott altalaban lovesed sincs mi ment felre, es azt hogyan kell javitani (szerintem)

"Az autoboxing (java 5-től van)" aminek 10 eve, szoval van mar egy ideje ;)

"gyakorlatilag az egyszerű típusok által nyújtott teljesítményt bukjuk el vele, hogy ne fájjon collection-ökbe pakolni őket" ezt nem tudom ertelmezni mi koze az autoboxingnak collectionnonknek. Amugy a boxing majdnem 0 overhead

"A List és az int[]" itt valoszinuleg egy vegtelen ciklusba kerulunk, de most rajtam a sor ;) :D nem kotelezo hasznalni a tomboket, sot nem is ajanlott. Ha neked a List apija tetszik hasznald azt. Ha nagyritkan belefutsz valami tomb hasznalatba es a foreach-en kivul tobbre van szukseged alakitsd at collectionne

"oké, annyira azért mégis, hogy StringBuilder lesz belőle" mar re nem ;)

"hanem a + operátor felül van bírálva string-ekre" ezt sajna nem tudom ertelmezni, te + jelet irsz a compiler meg lecsereli valamire a hatterben, de ebbe neked semmi beleszolasod nincs (9-es Javaig). overloadolasrol akkor beszelhetunk, ha te a kodban tudod overloadolni. Az, hogy a compiler hogyan oldja meg bytekod szinten az nem szamit annak, az en olvasatomban. A compiler ertelmezi, amit leirsz, es hatekony gepi kodot csinal belole.

"nem tudom, nem próbáltam a 10-es Java-t" A specifikaciobol szedtem a peldakat. Az a para, hogy a generikusok csak compile time vannak ertelmezve, es ezert Java-ban megengedett a raw tipusok hasznalata. Tehat tok valid a var l = List.of(), ahogyan a List l = List.of() is, meg a List&ls;Object> vagy a List<?>. Ezt nem torhettek el, mert akkor 5os Javaig vissza mindent eltornek. Azt gondolom a visszafele kompatibilitast nem lehet a szemukre hanyni.

"java nem konvertálna automatikusan" semmit nem konvertal, megprobalja kitalalni a tipusat, es mivel az osszes valid int, ezert annak veszi. pont ezert nyelvidegen a var kulcsszo.

"mégis mily módon okozhatna visszamenőleges kompatibilitási problémákat?" hat pl mert eddig barmint bele lehetett tolni, ki lehettt szedni, vagy lehetett torolni. A fix utan pedig eltorik a program. "ott az eleve hibás volt!" hat egyfelol igen, masfelol meg nem, hiszen nem kellett vizsgalnod semmit, map.remove(akarmi) es ha kitorli kitorli ha nem nem, az api megengedte. Namost ha ezt megvaltoztatjak, akkor szomoru leszel, amikor a dependenciad dependenciajanak a dependenciaja miatt nem tudod forditani az alkalmazasodat.

-
Advanced testing of Golang applications

Nagyon másképp látjuk a dolgokat :)

Azonban hadd hívjam fel a figyelmed arra, hogy igenis van automatikus típuskonverzió Java-ban, számoknál, amennyiben az nem jár információvesztéssel (widening). Pl. egy long változónak tudsz közvetlenül int értéket adni, sőt, a "long timeout = 3000" az pont egy ilyen szerkezet, mert a "3000" literál az int. Aritmetikai műveleteknél is konverzió van, méghozzá pl. osztásnál ha az egyik operandus egész, a másik float, akkor float-á lesz konvertálva az egész operandus, és az eredmény is float lesz, pl. "float f = 1.5f / 2".

Az autoboxing-al kapcsolatban is szeretném felhívni a figyelmedet, hogy a "majdnem 0" kijelentésed kissé felelőtlen. Ha véletlenül ciklusban csinálod (esetleg nem 1-2 tucat hanem sok-sok ezer elemmel), akkor bizony már fájdalmasan sok tud lenni az összeadódott "majdnem 0" overhead. Ráadásul a box-olt értékek objektumok lesznek (na nem mind, mert bizonyos mértékű cache-elést végez a jvm), amiket majd a garbage collectornak fel kell szabadítania használat után. Ha még aritmetikai műveleteket is végzel egy box-olt collection-ön, na az külön mókás.

A többire itt most nem reagálok, már így is túl hosszúra nyújtottuk az egészet, nem fogjuk egykönnyen meggyőzni egymást.

Elég sok hülyeséget összehordtál már a Jáváról, nem is értem, miért beszélsz róla, úgyhogy csak röviden:

"A property hasznos dolog"
getter/setter metódusoknak helyből van method handle-je, method referenceként be tudod dobni valahova consumernek pl. Egy property-s (gondolom a C# -os get/set struktúrára gondolsz) nekifutáshoz patkolni kéne szartig.

"a kikényszerített exception kezelés eredménye nem a kezelés lesz, hanem az exception lenyelése."
rossz programozó rosszul programozik. fish seen in water.

"A List<Integer> és az int[] között jelentős a különbség"
hogyapicsábane. Egyik egy generikus lista interfész (ami mögött n darab implementáció lehet), másik meg egy konkrét tömb. az ArrayList """szimulálja""" az int[]-et, de még így is sokkal többet tud nála.

"Az operator overloading"
az operator overloading szerintem nem OO Way :D azért vannak a metódusok, hogy ne meglevő aritmetikai műveleteket értelmezz újra, hanem csinálhass sajátokat.

"A dadogós "EzEgyNagyonHosszúClassNév változó = new EzEgyNagyonHosszúClassNév(dsjhdks)" viszont kimondottan gáz, na erre való a var kulcsszó."
erre nyekegi kb mindenki, hogy 1) NE adj hosszú osztálynevet, 2) rövid nevű interfész elég előre az esetek 95%-ában (pl. Map vs ConcurrentHashMap)

"A nyelvvel van bajom elsősorban, a runtime többnyire rendben van,"
ami fura, mert szinte minden jávához értő a runtime-ot fikázza.

"ha már a jodatime-ot vették át, akkor miért maradt ki egy-két metódus, illetve ennyi erővel maradhatott volna a package"
mert pl nem kell?

" method referenceként be tudod dobni valahova consumernek"

Ja, csak C#-ban, ott az event meg a TPL DataFlow erre a célra. Meg, hogy őszinte legyek, nem hiszem, hogy egy setter/getter-nek kellene egy consumer bemenetének lenni.

"hogyapicsábane"

Ez mind remek, de szerintem nem értetted meg a probléma lényegét.

"1) NE adj hosszú osztálynevet"

Jó vicc.

"2) rövid nevű interfész elég előre az esetek 95%-ában (pl. Map vs ConcurrentHashMap)"

Leszámítva, hogy nem csak Map-okat meg írunk interface-ba, hanem mondjuk üzleti logikai fogalmakat, amikből vagy TLA-FLA hegyek lesznek vagy kiírjuk rendesen és akkor még az is fogja érteni, aki megörökli. Mindenesetre még nem beszéltünk arról, amikor valami generikus visszatérési érték van vagy arról, hogy mennyivel egyszerűbb egy refactoring, hogy nem kell a kódban ezer helyen átírni valamit, csak mert a típuson reszeltünk ezt-azt).

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

> hogy nem kell a kódban ezer helyen átírni valamit

Legtöbb Java projektben a típusok fordítási időben vannak generálva, általában xsd-ből, kézzel ritkán írunk POJO-t. Tapasztalatom szerint ezerszer több időt spórol, hogy ha hozzá kell nyúlni egy funkció miatt a kódhoz 1000 helyen, akkor az a kód olvasható és nem kell tippelnem mi micsoda, mert a kolléga lusta alapos munkát végezni és inkább return var. Arról nem is beszélve hogy a szállítási folyamatot mennyire lelassítaná, ha triviális típus hibák egy nagy refaktor után csak futás időben jönnek ki, persze egyesével, mert az üzleti folyamat 94 lépéséből 25-ben hiba keletkezik, és mindenki nagyon örül a javít-fordít-deploy-újranekiálla94lépésnek munkafolyamatnak.

wow.

az megvan, hogy:
- csak local variablere lesz? (a return var-t és a pojo ebben a témakörben nem is tudom értelmezni)
- ettől még compile time lesz minden type check a Javaban

de kíváncsi vagyok, milyen refactort tudsz elképzelni, ahol a típus kiírása eddig nem okozott gondot, de a

var

használata fog.

> "a kikényszerített exception kezelés eredménye nem a kezelés lesz, hanem az exception lenyelése."
> rossz programozó rosszul programozik. fish seen in water.

azért ez tényleg nem jött be, hosszútávon. Egy Stream API-s hívásnál mit kezdesz, ha a filter/map/etc. metódusod exception dobna? pl.:


Files.walk(Files.createTempDirectory("foobar"))
        .filter(path -> Files.isRegularFile(path))
        .map(Files::readAllBytes) // na, ezzel mi lesz?
        .collect(Collectors.toList());

És ez nem Java8-as probléma, már előtte megvolt, hogy pl. a

Callable

nagyon kitágítja a dobható exceptionök típusát, míg a

Runnable

meg nagyon szűk. Valami generikus-exceptionös móka lehetne erre jó irány, ami ilyenkor megengedi kichainelni egy interfészből az exceptiönt - de... szóval valszeg nem véletlenül nem történt még ez meg.

De érdekelne, szerinted ezekre mi a szép megoldás?

> "A nyelvvel van bajom elsősorban, a runtime többnyire rendben van,"
> ami fura, mert szinte minden jávához értő a runtime-ot fikázza.

Szerintem a runtime kurva jó, és kíváncsian várom a hozzáértők runtime fikázását. Amivel eddig találkoztam, az a lassú, sok RAMot eszik, fujj, de ezek ~15 éves beidegződések az appletes időkből, olyanoktól, akik sosem foglalkoztak Javaval. Igen, ott tényleg szar volt, de ma nem is ez a célterülete a Javanak, s sokat fejlődött még ott is.

Ellenben a nyelven érezni, hogy néhol ~20 év tervezési vakvágányait is cipeli magával. Mostanság az Oracle mer erős dolgokat mondani (kidobnak metódusokat! deprecated finalizers!!! múltkor Reinhold egy újragondolt szerializációt is emlegetett!!!!), de rengeteg helyen kicsit félresikerültnek érződik az API, amit hoz magával a nyelv.

Itt mind a két oldalnak igaza van szerintem. Egyrészt az exception kezelés (különösen a checked), az valami nagyon rossz megoldás, volt is egy tanulmány, ami ezt támasztja alá, itt írtam róla.

Másrészről pedig valóban, nagyon sokan rosszul programoznak és sokszor észre sem veszik vagy nem érdekli őket.

De érdekelne, szerinted ezekre mi a szép megoldás?

Az exception-ök mellőzése :-) Mi most egy kis projektben mellőztük az exception-öket. Egyrészről mi sehol sem dobtunk, másrészről a külső kódokban dobott exception-öket elkaptuk. Ahol hibát akartunk visszaadni ott mindenhol Either<Failure, T>-t adtunk vissza.

Itt is szépen megmutatkozott, hogy:
1.) van jobb megoldás, mint az exception,
2.) ezt is lehet rosszul használni, és fogják is rosszul használni (a javasolt map, flatMap, orElse metódusok helyett a nem javasolt forEach, get átgondolatlan használata).
--
Ickenham template engine

> Az exception-ök mellőzése :-)
na igen, de ha már a JDK-ban ottvan... Én díjaznám, ha a egyszercsak minden kivételt úgy kezelne majd a Java, mint a runtimeexceptionöket most.

> a nem javasolt

forEach

funkcprogrban mi szokás

forEach

helyett? Valahol lesz a programomnak mellékhatása, s ott kell valami ilyesmi, nem?

Jézus, és akkor "ifeztek" minden visszatérési értékre? Az exceptionben az a jó, hogy nem feltétlen kell lekezelni a közvetlen hívónál. Például egy webserviceben ha 5 hívás mélyről jön egy exception, akkor legfelül (akár egy külön osztályban, pl spring controlleradvice) lekezeled, hogy melyikre milyen hibakódot adj, csak azzal törődsz helyben, amivel tudsz értelmes dolgot kezdeni.

Jézus, és akkor "ifeztek" minden visszatérési értékre?

Nem, map, flatMap, orElse metódusokat használunk.

Az exceptionben az a jó, hogy nem feltétlen kell lekezelni a közvetlen hívónál.

Az Either-nél is, plusz kikényszeríti valamelyest a hibakezelést (nem feltétlen a hívónál), mint a checked exception, csak ezt még fel tudod olyan helyeken használni, ahol a checked exceptiont nem.
--
Ickenham template engine

Idézőjeles ifezésbe ezeket is beleértem, szerintem túlzottan összekeveritek a buisness kódot a hibakezeléssel. De leginkább azért nem tetszik, mert ti akik kitaláltátok és most dolgoztok vele azok értik, és nyilván tetszik is nektek, elvégre ti csináltátok, csak ha új ember jön rá jó eséllyel a haját fogja tépni. Annyival meg biztos nem jobb mint checked exceptiont használni, hogy megérje az extra betanulást/próbaidő alatt lelépő emebereket.

szerintem túlzottan összekeveritek a buisness kódot a hibakezeléssel.

A business kódban vastagon benne kell legyen a hibakezelés is, csak erről sokan megfeledkeznek.

csak ha új ember jön rá jó eséllyel a haját fogja tépni.

Gondolod olyan bonyolult 4-5 metódus működését megérteni?
Szerintem ilyen ember, akinek ez gondot okoz, nem fog ezen dolgozni, sőt valószínűleg nálunk sem. ;-)
--
Ickenham template engine

Pl. ez a program indulása:


Either<Failure, DatabaseConfig> databaseConfigOpt =
    DatabaseConfig.load("conf/" + configFileName);

Either<Failure, Repository> repositoryOpt =
    databaseConfigOpt.flatMap(
        databaseConfig -> Repository.load(
            databaseConfig.driver,
            databaseConfig.connectionUrl));

repositoryOpt.flatMap(repository ->
    CommunicationConfig.loadFromDB(repository).map(
        communicationConfig ->
            Main.run(repository, communicationConfig))
).forEachLeft(failure -> logger.error("Hiba: {}", failure));

1. Betölti az adatbázis configot.
2. Az adatbázis config alapján betölti (létrehozza) a repositoryt. (Kapcsolódik adatbázishoz, példa lekérdezést végez, hogy minden rendben)
3. A repository alapján betölti adatbázisból a kommunikációs config-ot.
4. A repository és a kommunikációs config alapján futtatja a programot.
5. Ha a fenti pontok bármelyikénél hiba volt, akkor kiírja a hibát és leáll a program.
--
Ickenham template engine

Bele lehetne rakni, de nem rakjuk, ugyanis nem nagyon van értelme.
A hibára vonatkozó adatokat tesszük be, ha fontosnak látjuk. Pl., "A NÉV mezőnél megadott szöveg túl hosszú, 52 karakter, maximum 30 lehet." => TooLong("NÉV", 52, 30).

A stacktrace egyedül a programhibáknál nyújthat egy kis segítséget, amire sokkal jobbak az automatizált tesztek, illetve a korábban általam írt technikák a hibák megelőzésére.
Az egyéb hibák (nem megy a szerver, az adatbázis nem elérhető, hiányzik egy fájl, nincs megadva konfig adat, ...) esetén meg eleve zavaró is, ha ott van.
--
Ickenham template engine

Nekem már csak egy kérdésem van, ha FP-zni akartok, miért nem valami rendes FP nyelv?

Nálunk is pedzegetik a C# kapcsán, de azért érezhető a levegőben egy "látszik, hogy nem egészen erre van kitalálva a nyelv" vélemény.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Jó volna egy rendes nyelven FP-zni, de nem én döntök egyedül. Az biztos, hogy pl. Scala alatt ugyanez sokkal kevesebb boilerplate-et tartalmaz, így olvashatóbb.

Alapvetően a Java-ról egyelőre nem akarnak elmozdulni, ha meg már így van, akkor is jobb az ilyen eszközöket használni (Either, lambda, immutable, value objects, pure függvények, make illegal states unrepresentable, ...). Bár van sok nyelv, ahol egyszerűbb és kényelmesebb ezeket használni, de a Javahoz is rengeteg értéket adnak.

A semmi FP és a full, pure FP között azért elég sok minden elfér.
--
Ickenham template engine

Akartam válaszolni mindenkinek fentebb, de rájöttem, hogy megint a C#-osok verekednek a Jávásokkal fennforgás van.
Mindenki azt fikázza a másikban, amit az ő választott, egy igaz nyelve "okosabban" csinál (én is), úgyhogy lehet nincs értelme.

(ez a thread vége, azért ide írtam)

én Javas vagyok, s nagyon érdekelne, hogy az itt felvetett problémára, miszerint a checked exception sokszor nem fér bele a definiált interfészekbe (vagy ha az interfész definiál exceptiont, akkor meg sokszor nagyon tágra bővíti ezt) mi szerinted a kultúrált megoldás.

köszönöm.

Kulturált megoldás az, ha kezeled az Exceptiont, miközben streamelsz:

try (Stream<String> linez = Files.lines(Files.createTempFile("foo", "bar"))) {
linez.forEach(System.out::println);
} catch (final IOException e) {
Log.fatal("yolo", e);
}

PB

(A Files.lines megold neked mindent. Kivéve az exception-t, mert az üres stream == üres file, ami != nem létező file.)

nem vagyok javas, itt hogy oldhato meg szepen, hogy kulon kezeled a createTempFile altal dobott IOException-t (=if an I/O error occurs or the parent directory does not exist) a lines altal dobott IOException-tol (=if an I/O error occurs opening the file)? (a trivialis kulon try/catch-ek kivul)

--
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!

látom átjött a lényeg. a példa bugyuta (3 sorban nem is lesz jobb), de fentebb leírtam mi a gond.

de tessék, itt egy komplexebb. Adott Foo lib, benne a következő interfész:


interface Foo {
    ParsedFoo parse(InputStream is);
}

szeretném egy könyvtár alól az összes

.foo

fájlt felolvasni, majd felparsolni mindet.

Most:


Files.walk(path)
    .map(Files::newInputStream) // itt biztosan elhal
    .map(fooInstance::parse) // ha az interfész checked exceptiont dobna, itt is...
    .collect(Collectors.toList());

Na, rakjam ezt is egy try-catch-be? Ha utána esetleg dolgozni akarok a parseolt dolgokon? Akkor? Meddig? 6 soros stream belefér? 8?

Tudom, a Files.lines megold nekem mindent.

Rakjad.
Mindig lesz valaki, akinek nem fog tetszeni.

Nekem tökmindegy, én csináltam már hosszabbat is.
És olyat is, ahol egy helper levágta a picsába az IOException-t, mert nem kellett.

El kell fogadni, hogy ami checked exceptiont dob, azt nem tudod streamben közvetlenül használni.
Ezt a példádat, itt, ki kell írnod több sorban, nem úszod meg.

Próbálom azt megválaszolni, amit kérdeztél:

A:
Files.walk(path).map(Sandbox::newInputStreamNullable).filter(Objects::nonNull).map(fooInstance::parse).collect(Collectors.toList());
// ...
public static InputStream newInputStreamNullable(final Path path) {
try {
return Files.newInputStream(path);
} catch (final IOException e) {
Log.error("opsz, ez szar lett", e);
return null;
}
}

B:
Files.walk(path).map(p -> {
try {
return Files.newInputStream(p);
} catch (final IOException e) {
Log.error("opsz, ez szar lett", e);
return null;
}
}).filter(Objects::nonNull).map(fooInstance::parse).collect(Collectors.toList());

C:
Files.walk(path).map(Sandbox::newOptionalInputStream).filter(Optional::isPresent).map(Optional::get).map(fooInstance::parse).collect(Collectors.toList());
// ...
public static Optional<InputStream> newOptionalInputStream(final Path path) {
try {
return Optional.of(Files.newInputStream(path));
} catch (final IOException e) {
Log.error("opsz, ez szar lett", e);
return Optional.empty();
}
}

KELL bele a try-catch, csak máshova tologatod.

S miért szopunk ezzel? Mert a Function-ról lehagyták a throws-t, hogy ne kelljen vele szopniuk.

Eddig java részt exception-re épült a hibakezelés, a most bejött újdonságok (Stream, alap Lambda típusok) meg nem igazán kompatibilisek az exception-ökkel.

Én ezeket a megoldásokat látom:

  1. Újdonságok használata (stream, lambdák), de ilyenkor minden exception-t el kell kapni és:
    • vagy helyben le kell kezelni,
    • vagy átcsomagolni Runtime exceptionbe,
    • vagy a hibát is vissza kell adni (Either).
  2. Nem használni ezen újdonságokat.

--
Ickenham template engine

Egyrészt semmi nem tiltja, hogy stream apiban saját helper függvényeket hívj, ahol lekezeled a kivételeket, másrészt kontextusfüggő, hogy el kell-e kapni vagy csak simán tovább dobod a hibát. Pl ha 100 képfeldolgozást indítana el a user éjjelre, akkor a későbbi baltás ámokfutások elkerülése érdekében ajánlott nem elszállni egy hiba miatt és megcsinálni a többi 99-et, ellenben ha összefüggenek akkor jobb a fail fast, és csak kidobod a hívónak. Nincs erre általánosan jó megoldás.

Nekem bejön a funkcionális programozás, de azért pár dolgot látni kell ezzel kapcsolatban:

- Ha valamit funkcionálisan írsz meg Javában, azzal vállalod, hogy a fejlesztők 80-90%-a alapból jobb, ha nem nyúl bele, 30-40%-uk lehet soha nem is fog eljutni arra a szintre, hogy értse. Ez van, ahol vállalható kompromisszum persze, de azért érdemes fejben tartani.
- Tetszik-nem tetszik nagyon sok esetben nehezebben érthető a funkcionális megoldás Java-ban, mint a nem funkcionális, hiába írja le "szebben", meg tömörebben a feladatot. Egész egyszerűen a Java nyelv nem erre lett kitalálva. A példád ezt nagyon jól mutatja, sokkal olvashatóbb lenne egy nagy try-catch blokkon belül "sorfolytonosan" megoldani a feladatot, mint ágyazni egymásba vég nélkül a lambdákat. A slusszpoén, hogy a te megoldásodnak nagyon előnye sincs ehhez képest, ugyan azt csinálja gyakorlatilag mind a kettő:


try {

DatabaseConfig databaseConfig = DatabaseConfig.load("conf/" + configFileName);
Repository repository = Repository.load(databaseConfig.driver, databaseConfig.connectionUrl);
CommunicationConfig communicationConfig = CommunicationConfig.loadFromDB(repository);
Main.run(repository, communicationConfig);

} catch (Exception e) {
logger.error(e);
}

Ha nagyon csámcsogni akarnék a példádon akkor bedobhatnék még egy Spring configot is megoldásként (ami még olvashatóbb, rugalmasabb lenne).

Baromi hasznos tud lenni a funkcionális programozás Java alatt is, meg a lambdázás, de azért csínján kell vele bánni. Collection elemeinek feldolgozásánál, ahol nem kéne egy lépés hibájának esetén elszállnia az egész folyamatnak, sokkal olvashatóbb megoldás az általad írt 'Either' wrapperek streamben láncolása. Vagy folyamatos 'if (valtozo != null)' vizsgálatok helyett az Optional. De konfigurációra, alkalmazás inicializációra biztosan nem használnám.

"lehet soha nem is fog eljutni arra a szintre, hogy értse"

Az nem a te hibád, hogy mások hülyék hozzá.

"a te megoldásodnak nagyon előnye sincs ehhez képest"

Az ő megoldása implicite megengedi, hogy a lambdák esetleg másik szálon fussanak le belül, vagy bedobhatóak legyenek mondjuk egy AccessController.doPrivileged hívásba. (Momentán nemtudom minek, de a lehetősége megvan.)

>Az nem a te hibád, hogy mások hülyék hozzá.

Ha a te hatáskörödben áll eldönteni, milyen eszközt és hogyan használjatok a cégnél, amihez utána nem lehet a szükséges mennyiségű és minőségű embert találni az adott keretek mellett a munkaerőpiacon (akár a te helyedre ha te továbblépnél), akkor bizony de, az a te sarad (is). Ebbe nagyon sokan nem gondolnak bele a szakmában, pedig elég fontos szempont.

>Momentán nemtudom minek, de a lehetősége megvan.

Tök jó, de egyik említett igénynek sincs sok racionalitása egy átlag alkalmazás konfig feladat esetén. Ha meg mégis felmerül, az én kódomat sem lenne akkora truváj átírni, nem igazán érzem a hozzáadott értéket ITT.

De felvetném még egyszer az IoC containeres megoldást is, ahol lehet ezekre a feladatokra eleve kész, egyszerűen konfigurálható megoldás létezik.

Nekem bejön a funkcionális programozás

Lehet, hogy neked nagyon bejön az FP, csak éppen a lényegét nem érted, hogy mire is jó.

A slusszpoén, hogy a te megoldásodnak nagyon előnye sincs ehhez képest, ugyan azt csinálja gyakorlatilag mind a kettő:

Ugyanazt csinálja, csak éppen a lényege más. Ahogy a null érték vs Optional is ugyanazt csinálja, csak az egyik esetben pontosan tudod, hogy nem fogsz NPE hibát kapni, a másikban meg nem, mert explicite nincs mindenhol az orrod alá dörgölve, hogy abban van érték, vagy nincs.

Ha nagyon csámcsogni akarnék a példádon akkor bedobhatnék még egy Spring configot is megoldásként (ami még olvashatóbb, rugalmasabb lenne).

Az olvashatóságot sokféleképpen lehet érteni. Az én olvasatomban: könnyű megérteni, hogy ténylegesen mit csinál. Nos a Spring config, és bővebben az IoC containerek ebben nagyon rosszak.
Ezeknél könnyű megérteni, hogy mit kellene csináljon.

Csak ezen kérdésekre nem tudod a választ:
- Mikor jön létre?
- Hol jön létre?
- Mi kerül bele?
- Ami belekerül az biztosan jó-e?

--
Ickenham template engine

Ezen kérdésekből a lényegiek eldöntésére szoktat tesztet írni. Amúgy nem hiszem, hogy én lennék olyan jó programozó, hogy elkerülnek a hatalmas szívások npe-vel (btw ioc pont erre is jó), minden esetre egyes emberek sokkal jobban rá vannak gyógyulva optionalre és társaira, mint amekkora problémának érzem az npe-t.

>Lehet, hogy neked nagyon bejön az FP, csak éppen a lényegét nem érted, hogy mire is jó.

Mindezt leszűrted egyetlen posztomból? Amiben leírtam, hogy az eredendően nem is erre tervezett Java-s világban nem mindig a funkcionális megközelítés az Egyetlen Helyes Út? :D

>Ugyanazt csinálja, csak éppen a lényege más.

Itt az általad említett null vs. Optional jellegű probléma nem jön elő. Bármelyik inicializációs lépés hibára fut (jelen esetben exception), nem fog hibás értékkel folytatódni a program, hanem ugyanúgy hibalog + kilépés. Nem kell vizsgálnod lépésenként semmit, pont ugyanannyira tudhatod, hogy ha oda eljutott a program, nem volt addig gond, a bemeneteid már inicializálva lettek.

>Az én olvasatomban: könnyű megérteni, hogy ténylegesen mit csinál. Nos a Spring config, és bővebben az IoC containerek ebben nagyon rosszak.

Ja, csak inicializációnál többnyire nincs szükséged arra, hogy részletesen, lépésről lépésre tudd, mi történik. Az a lényeg, hogy előálljon a konzisztens, helyes konfiguráció és induljon a lényegi kód, lehetőleg minél kevesebb mérnökórából, követelmény változás esetén könnyen módosítható formában.

A kérdéseidre meg bőven megfelelő választ lehet adni IoC esetén is az alkalmazások kilencvensok százalékában. Ahol nem, oda nyilván nem IoC containert használsz. Feladathoz az eszközt, tudod.

Mindezt leszűrted egyetlen posztomból?

Igen, de nem volt nehéz:
- Try-catch ugyanaz, mint az Either,
- Spring config még jobban is érthető, mint az explicit konfig.

Amiben leírtam, hogy az eredendően nem is erre tervezett Java-s világban nem mindig a funkcionális megközelítés az Egyetlen Helyes Út? :D

Ez pontosan így van, de ez nem ad hozzá, nem von le semmit az előző tekintetében.

Ja, csak inicializációnál többnyire nincs szükséged arra, hogy részletesen, lépésről lépésre tudd, mi történik. Az a lényeg, hogy előálljon a konzisztens, helyes konfiguráció és induljon a lényegi kód.

Ha nem tudod lépésről lépésre mi történik, akkor honnan tudod, hogy előáll a konzisztens és helyes konfiguráció?

A kérdéseidre meg bőven megfelelő választ lehet adni IoC esetén is az alkalmazások kilencvensok százalékában.

Mégis hogyan, ha ez az IoC container belső magánügye? Nem kilencvensok százalékban, de sohasem tudsz ezekre válaszolni.

--
Ickenham template engine

>Try-catch ugyanaz, mint az Either

Már bocs, de hol írtam ilyet? A fentebbi példa esetén nem nyersz kb. semmit a funkcionális (jellegű) megoldással a try-catchhez képest. Ettől még nem ugyan az a kettő és van ahol tényleg sokkal jobb a funkcionális megközelítés.

>Ha nem tudod lépésről lépésre mi történik, akkor honnan tudod, hogy előáll a konzisztens és helyes konfiguráció?

A beanjeid előállnak az általad megadott módon, a függőségek teljesülnek, nyilván ez a sorrendiséget is nagyban megköti. Ezt a containerek azért tudják. Ahol nincs sorrendiség ott a pontos sorrend, vagy hogy éppen a beanek létrehozása mellett mit piszmog a framework az az esetek nagy többségében kit érdekel?

Ezt értettem "bőven megfelelő válasz" alatt. Annyira, amennyire részletesen szükség van rá, az esetek nagy többségében megfelelő választ lehet adni IoC esetében is a kérdéseidre.

>Nem kilencvensok százalékban, de sohasem tudsz ezekre válaszolni.

Szerinted egyébként mire használja a szakma ezeket az eszközöket, ha - a te értelmezésed szerint - konfigurációra teljesen alkalmatlanok?

Már bocs, de hol írtam ilyet?

Én erre gondoltam:
A slusszpoén, hogy a te megoldásodnak nagyon előnye sincs ehhez képest, ugyan azt csinálja gyakorlatilag mind a kettő:

Röviden az előnyei az Eithernek a try-catch-hez képest:
- Könnyebben érthető
- Könnyebben módosítható
- Könnyebben újrafelhasználható
- Könnyebben kompozálható (compose, nem tudom van-e magyar megfelelője)

Tudom, hogy Te nem így gondolod, ezért is írtam, hogy nem érted az FP lényegét.

Szerinted egyébként mire használja a szakma ezeket az eszközöket, ha - a te értelmezésed szerint - konfigurációra teljesen alkalmatlanok?

Nem azt írtam, hogy használhatatlan, hanem azt, hogy nem jó módszer. Ilyen az IoC container, az ORM, az annotáció, a mock, illetve az OOP nagy része. Ezeket mind tömegével használjuk, pedig van náluk sokkal jobb.

--
Ickenham template engine

>"A slusszpoén, hogy a te megoldásodnak"

Még egyszer: nem általánosan írtam az either vs try-catch témakörben. Hanem a fenti példa kapcsán. Van, ahol az előnyei miatt megéri használni, van, ahol ezek a pluszok nem adnak hozzá sokat a kódhoz. Pl. a fenti példában. Nem tudom, mit értetlenkedsz még mindig. Nyilván ha a kódbázis alapból funkcionális jellegű, a cégnél ez norma, akkor én is így írnám meg. De ha nem, felesleges ilyen, hagyományos eszközökkel is jól megoldható feladatoknál játszani az eszed. Írd meg úgy, hogy a kollégáid is értsék.

>Tudom, hogy Te nem így gondolod, ezért is írtam, hogy nem érted az FP lényegét.

Ja, hát ha te tudod, akkor ok. Elkezdtem majdnem magyarázni a bizonyítványom, de igazából úgyis ugyanezt fogod vissza echozni, szóval tök mindegy.

>Ezeket mind tömegével használjuk, pedig van náluk sokkal jobb.

Szóval ezek szerint mégis tömegével használt eszközről beszélünk. Ha én nem is számítok, mert "nem értem a FP lényegét", a munkaerőpiac iszonyatosan nagy többsége szerint is olvashatóbb lesz egy Spring config, mint az egymásba ágyazott lambdák.

Hiába over-engineered szerintem is az IoC, attól még átlag szoftver esetén a feladatára teljesen megfelelő eszköz. Széllel szemben pisálni lehet, csak nem érdemes.

Még egyszer: nem általánosan írtam az either vs try-catch témakörben. Hanem a fenti példa kapcsán.

Én is. Épp ezt írom sokadjára, hogy nem látod az előnyeit a konkrét példánál.

Ha én nem is számítok, mert "nem értem a FP lényegét"

Nincs ebben semmi rossz, nagyon sokan nem értik és én sem értek nagyon sok mindenhez. Csak amihez nem értek, arra nem mondom, hogy nem jó.

a munkaerőpiac iszonyatosan nagy többsége szerint is olvashatóbb lesz egy Spring config, mint az egymásba ágyazott lambdák.

1 milliárd légy nem tévedhet.
Sajnos van szerencsém az "enterprise szoftverfejlesztésben" már jó ideje részt venni, így tudom miről van szó.
--
Ickenham template engine

> Mivel nem voltam ott a nyelv tervezésekor, és nem olvastam utána, ezért nem tudom, mi vezetett ahhoz a döntéshez, hogy ezek kezelése a Java-ban teljesen más, mint az objektumoké. Pl. a C#-ban ez meg van oldva, azaz egységes az API és mégis van jó teljesítmény.

Project Valhalla, jön majd a Javaba is lassan :)

Melyik az ami nem hoz be 2x annyi problémát, mint hasznot?

Amelyiket alaposan átgondolták előtte :)

Az operator overloading túlzott és zavaró használatára még csak nem is a C++ a legjobb példa, hanem a Scala. Na az komplett agymenés. Ennek ellenére úgy vagyok vele, hogy a szélsőségek egyik irányba sem jók. Sem a teljes szabadság, sem a teljes tiltás. Arról nem is beszélve, hogy akkor a String-re mégis miért van, és a BigDecimal-ra miért nincs.

"mondjuk semelyik másik nyelvben nincs ekkora állatság, a LINQ nagyon egyedülálló"

C# F# Scala JavaScript

Olyan hatalmas különbséget nem látok a megoldások között. :) Na jó de, F#-ban és JavaScriptben típusfüggő a megoldás, igaz utóbbi dinamikus jellege miatt annyira azért mégse.

Jó, azért van még egy pár LinQ-s függvény. De pl. ott van még az LinQ2SQL/Entity Framework is, ami önmagában megér egy külön említést abban, hogy csomó mindenben egész jó hidat tudott képezni az SQL és a C# között. Beleértve azt is, hogy gyakorlatilag C# Expression-okat volt képes átfordítani SQL kifejezésre. Lehet vitatkozni azon, hogy jó-e, hogy "más" fut a felszín alatt, mint ami kódot leírsz (pl. egy Entities.Select(e => new { e.Id, e.Randomfield }) -ből képes volt rendesen kioptimalizálni, hogy az adott Entity-ből csak azt a két mezőt kérje ki és egyéb, felszín alatti optimalizációkkal azt elérni, hogy a sima fapapucsos ADO.NET-es DataReadernél jóval gyorsabb legyen, de mindenesetre hatékony.

(És mondom ezt úgy, hogy az ORM-et koncepcionálisan egy nagy téveszmének gondolom és szerintem minimum 20 évig tévútra fogja vinni az ipart. :)

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

"Jó, azért van még egy pár LinQ-s függvény."

Scalaban is :), és ha ennyi nem lenne elég, implicit class-okkal további kiegészítő metódusok implementálhatóak. Ez a mechanizmus egész hasonló a C# extension methodjaihoz.

A LinQ2SQL jellegű okosságok is megoldhatóak Scalaban, vagy custom DSL-lel (mondjuk a LinQ is az, csak egy szinttel lejjebb), vagy makrókkal.

Szerintem nem rossz az ORM, csak tudni kell a helyén kezelni. A tévedés az, hogy pl. a csavart nem az ORM kalapáccsal kellene beverni. Aki egyszer megismerte, az mindenre ezt akarja használni, akkor is, ha nincs rá szüksége. Illetve sokan nincsenek tisztában azzal, hogy két teljesen különböző világ összekapcsolásánál bizony lesznek inkompatibilis struktúrák, és ezeket a helyükön kell tudni kezelni, különben nagy baj lesz.
Ami hibát nagyon sokan elkövetnek az, hogy teljesen normalizált relációs design-t álmodnak az alkalmazásnak, aztán megpróbálják OO oldalról ezt kiszolgálni. Ilyenkor szokott előfordulni, hogy egy szimpla many-to-many kapcsolat 2 oszlopos táblájának is készül entitás az OO rétegben... na ilyenkor kapok sikítófrászt.
Ez a baja az ORM-nek, hogy miatta az OO szoftver design még nem lépett tovább a relációs modellről. Nekem az a tapasztalatom, hogy ha megtervezem az alkalmazás domain modelljét OO alapon (értsd: leszarom a perzisztenciát), és utána gondolkodom el rajta, hogy ez hogyan menjen relációs táblákba, akkor sokkal kevesebb probléma fog fellépni. Persze ehhez ismerni kell az ORM réteget, hogy egyes szituációkat hogyan kell workaround-olni. Már ha egyáltalán relációs modellbe érdemes konvertálni, mert számomra (sokakkal ellentétben) ez nem egyértelmű.

Igen, másik oldalról meg azt látom, hogy olyan dolgokat kezdenek el implementálni és olyan dolgokon kell görcsölni, ami egyébként nem létezne, ha nem kódban akarnának megoldani mindent.

Kedvencem pl. mikor mass update vagy mass delete van. SQL-ben ugye viszonylag triviális tud lenni a legtöbb eset. ORM-mel meg potenciálisan egy halom felesleges adatmozgatás van. Külön aranyos, amikor az OO oldalról indulók megterveznek egy többrétegű alkalmazást és az egész logikát a business layerben akarják implementálni és még konvertálnak is DAL között, görcsölnek a konzisztenciával, stb. holott csak annyi kellett volna, hogy egy megfelelően megírt where-vel lefuttassanak egy SQL queryt.

Előbb-utóbb mindig oda jutok, hogy nekik vagy egy perzisztenciát is tudó object store kellene vagy igazából nem akarják szigorúan követni az OO elveket.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

A C# és F#-ban levő LINQ ugyanaz, tekintve hogy mindegyik .NET alapú :)

Amiben (akkor innentől így hivatkozok rá) a .NET-es LINQ egyedülálló, az hogy ez nem csak egy lambdás pipeline API, hanem egyrészt nyelvi szinten is integrálva van (ha már a neve is ez hehe), másrészt az Expression API-val karöltve runtime kód-analizálás és kód-generálást is lehetővé tesz. A megfelelő query provider-el egészen sokféle módon lehet integrálni külső adatforrásokkal, pl LINQ to Objects, LINQ to XML, sőt, sokat használtam az NHibernate-et is LINQ interfésszel. Ráadásul a nyelvi támogatás miatt akár lehetne "Language integrated monads"-nak is hívni, egyszerűen természetes akár így is használni.

Hát ehhez képest ma is Java a vezető programnyelv. Ajánlom figyelmedbe a 2018-as felmérést:
https://www.packtpub.com/skill-up-2018

A Pythont valóban komolyan kell venni. De a Kotlin egyelőre nem több egy durcis Oracle felé bemutatott Google középső ujjnál.

Normális HUP-ot használok!

Ahogy az Android Studio alapját képező IntelliJ -t is. A Google sokkal több dolgot karol fel vagy nyúl le mint amit valóban maga fejleszt nulláról.
És olvasd csak el a cikk, azaz hirdetés első sorát: "Július 26-án 30 órás online képzést indítunk Modern Android fejlesztés Koltin alapokon címmel. A képzés hiánypótló, hiszen Kotlin nyelv rövid úton kiváltja a Javát az Android ökoszisztémában - a Google támogatásával. "

Normális HUP-ot használok!

Vagy probal eloremenekulni az oracle alol.
Elsore, pl. a primitiv tipusok nelkulozese kisse fura nekem.
Amit irtak java vs kotlin kozott klulonbseget, elsore egy java 8.1-ben megoldhato lett volna. Bizonyara okuk volt, hogy nem azt leptek meg.
Kotlinhoz van free dev env? Vagy csak a nem-annyora-occo intellij?

Az intellij community és az android studio ingyenesek. Amúgy meg az IDEA nem vészes, kb 60e HUF évente. Pár éve, amikor ennél még jóval drágább volt kiszámoltuk, hogy kb. 3 hónap alatt térül meg (Eclipse-el összehasonlítva)

A primitív típusoknak pedig nincs helye egy objektum-orientált nyelvben, sosem volt. Mások meg tudták oldani ezt a problémát (performance vs. consize API), csak nekik nem sikerült.

A Java véleményem szerint teljesen elefántcsont-torony jellegű lett. A nagy okosok majd megmondják odafenn, hogy a népnek lenn mi kell. A nép meg megírja a Kotlint, a Scala-t, a Groovy-t, Ceylon-t (meg jruby. jython és a többi hehe), mert elege van abból, hogy megmondják neki, hogy a lambdák hiánya az direkt jó, hogy mire a committee megszavazza, hogy itt az ideje cselekedni, addigra Brian-t már megfeszítették, és a Júdeai Nemzeti Front Elit Öngyilkos Alakulata sem tud már segíteni.

> A primitív típusoknak pedig nincs helye egy objektum-orientált nyelvben, sosem volt.
ez egyébklnt ugyanúgy a csőben van, hogy megoldják.

Igen, elment a Java mellett a világ, kicsit az elmúlt ~10 évben.
Szerintem egyébként ők is észrevették, s a hat hónapos release ennek köszönhető.

Nem halott az a dinoszaurusz még... A COBOL sem halt még ki, pedig már sok helyen próbálkoznak kinyírni, de még mindig eléggé kulcsfontosságú rendszerek futnak benne. Amíg jobban fosnak az újraírástól, mint amennyire fáj nekik a rendszerek ára és karbantartási költsége, addig bizony marad is.
Amúgy a COBOL szoftvereket sok helyen Java-ra írják át :)

Lehet benne nagy méretű programot, stabilan, határidőre szállítva gyártani. Szoftverfejlesztő oldalról meg van mögötte egy
hihetetlen nagy ökoszisztéma, aminek a legtöbb nyelvben csak a töredéke van kész. Iszonyatosan egyszerű különböző rendszerekbe
beintegrálni, és elég jó teljesítményt ad. Igen, lehetne több feature a nyelvben, de igazából nem ezen múlik a történet.

Nem tudom mennyire vagy képben de a Java azért elég rendesen megújul időnként, lásd 8-9-10es ficsőrök, spring-boot, wildfly swarm, alternatív nyelvek (kotlin, scala, egyéb) a jvm felett, továbbá a fél big data-s világ is hadoopon és sparkon alapszik. Én inkább a folyamatos fejlődést látom. Persze az EE a maga konzervativitásával egy kicsit állóvíz(nek tűnik nekem).

--
debian,libreelec,openmediavault,ubuntu,windows,arch,lineageOS
zbook/elitebook/rpi3/nexus5_hammerhead

Képben vagyok. A Java nyelvvel van kissé bajom, nem a JVM-el. A nyelv nem újul túl sokat, az 5-ös után a 8-as volt, ami lényeges újításokat hozott, jó nagy késéssel. Valószínűleg az Oracle felvásárlás volt a fő ok a késlekedésre, de nem olvastam pontosan utána.

Az ilyen spring-boot, wilfly swarm, hadoop és egyéb dolgokat és az ökoszisztéma kategóriába sorolnám, nem pedig a nyelv megújulásához. Tévedés ne essék, ezzel semmi bajom, sőt rendkívül szeretem, hogy ekkora a választék és ilyen jók a lehetőségek. Magával a Java nyelvvel van problémám, hogy egyszerűen már kényelmetlen a szintaxisa, és pár (szerintem alap) képesség hiányzik belőle.

Igen, a language level hagy maga után kívánnivalókat (96: első publikus kiadás), de szerintem ha figyelembevesszük a kompatibilitás, fejlesztői közösség mérete és meglevő kódbázis mérete kérdését, akkor indokolt a visszafogott tempó.

--
debian,libreelec,openmediavault,ubuntu,windows,arch,lineageOS
zbook/elitebook/rpi3/nexus5_hammerhead

Én pénzintézeteknél találkoztam vele. Magyarországon nem nagyon van, tekintve hogy a COBOL a mainframe-éra egyik vezető nyelve, és nálunk ez az egész mainframe dolog kimaradt. Tőlünk nyugatabbra viszont sok megy még közülük, és rengeteg rendszer még COBOL. Pár hónapja pont ilyen melónk volt, Java-val kellett összekötnünk a COBOL programokat.

A nyelv nem lenne rossz, de mindig a tyukok jutnak eszembe rola...

"...Kotlin nyelv rövid úton kiváltja a Javát az Android ökoszisztémában"
A Kotlint meg a Dart? Lásd a Fluttert és a Fuchsia-t.

--
eutlantis

Azert a Flutter meg boven odebb van. Minimalis szamu a rendelkezesre allo libek szama, pl nincs meg hasznalhato google Maps wrapper vagy Retrofit alternativa (ami egy tok jo http lib), vagy dependency injection. A keresztplatformos kepesseg moge csak felig alltak be, es egyelore az az irany, hogy a widgetek iOS oldalat majd a kozosseg fejleszti. Ez igy keves komolyabb projekteknel.
Szerintem amig a Fuchsia-bol nincs valami kezzelfoghato, vagy nem allank ki rendesn a keresztplatformos kepessegek mellett, addig a Flutter meg a Dart nagyon marginalis marad. Es ez meg evek.

Ellenben a Kotlin most van itt, minden jelenlegi libbel lehet hasznalni, az androidos Java 7~8 utan feludules, es hetek alatt teszi jobba az eleted ha android heggeszto kisiparos vagy. Es nem meredek a tanulasi gorbeje java utan.

"Július 26-án 30 órás online képzést indítunk Modern Android fejlesztés Koltin alapokon címmel. "
Lehet én látom rosszul, de az június és nem július. :(