{"id":96,"date":"2017-05-18T19:21:49","date_gmt":"2017-05-18T17:21:49","guid":{"rendered":""},"modified":"2018-11-05T19:55:34","modified_gmt":"2018-11-05T18:55:34","slug":"java-8-metody-ako-first-class-citizen","status":"publish","type":"post","link":"https:\/\/spireng.sk\/en\/java-8-metody-ako-first-class-citizen\/","title":{"rendered":"Java 8 \u2013 met\u00f3dy ako first-class citizen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"imgp_img\" style=\"float: left; margin: 2px 5px;\" src=\"\/sites\/default\/files\/imagepicker\/1\/cxz687gf.png\" alt=\"Obr\u00e1zok\" width=\"200\" height=\"214\" \/>Toto je druh\u00fd zo s\u00e9rie \u010dl\u00e1nkov o tom, \u010do je nov\u00e9 v Jave 8. V tom <a href=\"http:\/\/spireng.sk\/en\/java-8-lambda\/\">prvom<\/a> sme si rozobrali lambda met\u00f3dy. Teda mo\u017enos\u0165, ako zadefinova\u0165 anonymn\u00fa met\u00f3du na jedno pou\u017eitie. Nov\u00e9 sp\u00f4soby met\u00f3d pri tomto ale nekon\u010dia. Dnes si uk\u00e1\u017eeme, \u017ee v novej Jave s\u00fa met\u00f3dy naozaj first-class citizen, a tie\u017e to, \u017ee rozhrania u\u017e nie s\u00fa to, \u010do b\u00fdvali.<!--more--><!--break--><\/p>\n<p>V prvom dieli sme si uk\u00e1zali, \u017ee Lambda v\u00fdraz je vlastne anonymn\u00e1 met\u00f3da, ktor\u00e1 sa d\u00e1 posla\u0165 ako parameter do inej met\u00f3dy. Napr\u00edklad:<\/p>\n<pre>doSomething(e -&gt; System.out.println(x));<\/pre>\n<p>Ot\u00e1zka, ktor\u00e1 v\u00e1s ale m\u00f4\u017ee tr\u00e1pi\u0165 je, ako vlastne vyzer\u00e1 defin\u00edcia met\u00f3dy doSomething a hlavne jej parametra? Existuje nejak\u00fd nov\u00fd typ, ktor\u00fd reprezentuje tak\u00fato lambda v\u00fdraz met\u00f3du? Odpove\u010f je nie. Ale met\u00f3du po novom zastupuje \u0161peci\u00e1lny typ rozhrania \u2013 funkcion\u00e1lne rozhranie.<\/p>\n<p>Funkcion\u00e1lne rozhranie je rozhranie, ktor\u00e9 m\u00e1 len jednu abstraktn\u00fa met\u00f3du \u2013 teda met\u00f3du bez definovan\u00e9ho obsahu. Napr\u00edklad nov\u00e9 rozhranie <em>Consumer,<\/em> ktor\u00e9 vieme n\u00e1js\u0165 v Jave v bal\u00edku java.util.function:<\/p>\n<pre>@FunctionalInterface\r\n  public interface Consumer&lt;T extends Object&gt; {\r\n  public void accept(T t);\r\n}<\/pre>\n<p><span style=\"font-weight: normal;\">Toto rozhranie m\u00e1 jednu met\u00f3du, ktor\u00e1 ako parameter berie pr\u00e1ve jeden objekt a ni\u010d nevracia. Ak si v\u0161imnete lambda v\u00fdraz vy\u0161\u0161ie (<\/span><em><span style=\"font-weight: normal;\">System.out.println(<\/span><\/em><em><span style=\"font-weight: normal;\">x<\/span><\/em><em><span style=\"font-weight: normal;\">)<\/span><\/em><span style=\"font-weight: normal;\">), tak to presne sp\u013a\u0148a to, \u010do met\u00f3da <\/span><em><span style=\"font-weight: normal;\">accept<\/span><\/em><span style=\"font-weight: normal;\"> s\u013eubuje. Ak to v\u0161etko d\u00e1me dokopy, met\u00f3da doSomething by mohla vyzera\u0165 takto:<\/span><\/p>\n<pre>public void doSomething(final Consumer&lt;String&gt; consumer) {\r\n  String text = \u201ehello\u201c;\r\n  consumer.accept(hello);\r\n}<\/pre>\n<p>\u010co sa to stalo s Lambdou v met\u00f3de doSomething? Premenila sa na objekt, ktor\u00fd implementuje rozhranie! \u00c1no, takto nejako to funguje. Na jednej strane popis funkcie. Na tej druhej, objekt definovan\u00fd cez rozhranie. Zjednodu\u0161ene (a obrazne) by sa dalo poveda\u0165, \u017ee Java vezme lambda v\u00fdraz a rozhranie, ktor\u00e9 m\u00e1 reprezentova\u0165. Na pozad\u00ed zadefinuje triedu, ktor\u00e1 implementuje dan\u00e9 rozhranie a na implement\u00e1ciu jeho jedinej met\u00f3dy pou\u017eije Lambda v\u00fdraz. N\u00e1sledne vyrob\u00ed in\u0161tanciu tejto triedy a po\u0161le ju ako parameter do met\u00f3dy doSomething.<\/p>\n<p>\u010co to v\u0161etko znamen\u00e1? Napr\u00edklad aj to, \u017ee ako parameter met\u00f3dy mus\u00ed by\u0165 pou\u017eit\u00e9 rozhranie s jednou abstraktnou met\u00f3dou. Ak by rozhranie malo met\u00f3d viac, hroz\u00ed, \u017ee pri vyr\u00e1ban\u00ed implement\u00e1cie rozhrania Java nebude vedie\u0165, ktor\u00fa met\u00f3du v rozhran\u00ed m\u00e1 Lambda v\u00fdraz zastupova\u0165. A tie\u017e to znamen\u00e1, \u017ee z odkazov na met\u00f3dy v prvom bode pri ich preposlan\u00ed sa st\u00e1vaj\u00fa vlastne objekty.<\/p>\n<p><span style=\"font-weight: normal;\">Po\u010fme ale sp\u00e4\u0165 k tomu rozhraniu s jednou met\u00f3dou. <\/span><span style=\"font-weight: normal;\">Ako som tu u\u017e sk\u00f4r spom\u00ednal, <\/span><span style=\"font-weight: normal;\">ide o<\/span><span style=\"font-weight: normal;\"> takzvan\u00e9 funkcion\u00e1lne rozhrani<\/span><span style=\"font-weight: normal;\">e<\/span><span style=\"font-weight: normal;\">. Aby to bolo jasn\u00e9, aj <\/span><span style=\"font-weight: normal;\">v <\/span><span style=\"font-weight: normal;\">Jav<\/span><span style=\"font-weight: normal;\">e<\/span><span style=\"font-weight: normal;\"> je na to nov\u00e1 anot\u00e1cia <\/span><em><span style=\"font-weight: normal;\">@FunctionalInterface<\/span><\/em><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">. <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">T\u00e1 nie je povinn\u00e1<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\"> a sl\u00fa\u017ei hlavne, a<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">by<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">aj <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">kompil\u00e1tor <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">vedel,<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\"> \u010do s rozhran\u00edm zam\u00fd\u0161\u013eate, a ak tam bude viac abstraktn\u00fdch met\u00f3d, tak hne\u010f zahl\u00e1si\u0165 chybu.<\/span><\/span><\/p>\n<p><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">Funkcion\u00e1lne rozhrani<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">e<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\"> teda nemus\u00ed by\u0165 \u0161peci\u00e1lne ni\u010d\u00edm in\u00fdm ako len t\u00fdm, \u017ee m\u00e1 pr\u00e1ve jednu abstraktn\u00fa met\u00f3du. <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">Ja viem, dook<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">o<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">la tu p\u00ed\u0161em o abstraktnej met\u00f3de, ako keby Java rozhrania mohli ma\u0165 aj in\u00e9 ako abstraktn<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">\u00e9 met\u00f3dy<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">. <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">Tak to b\u00fdvalo vo v\u0161etk\u00fdch predch\u00e1dzaj\u00facich verzi\u00e1ch. Java 8 m\u00e1 aj v tomto smere novinku.<\/span><\/span><\/p>\n<p><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">V tejto verzii je toti\u017e mo\u017en\u00e9 zadefinova\u0165 nie\u010do, \u010do sa naz\u00fdva def<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">a<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">ultn\u00e1 met\u00f3da. <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">To je met\u00f3da, ktor\u00e1 m\u00e1 aj svoje telo. A teda nie je abstraktn\u00e1. Vlastne to vyzer\u00e1 ako klasick\u00e1 met\u00f3da niekde v triede, akur\u00e1t, \u017ee je v rozhran\u00ed. Pred chv\u00ed\u013e<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">o<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">u som uviedol rozhrani<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">e<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\"> Consumer. Po pravde som ho trochu osekal. Re\u00e1lne to rozhrani<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">e<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\"> obsahuje met\u00f3dy dve:<\/span><\/span><\/p>\n<pre>@FunctionalInterface\r\npublic interface Consumer&lt;T extends Object&gt; {\r\n  public void accept(T t);\r\n  public default Consumer&lt;T&gt; andThen(Consumer&lt;? super T&gt; cnsmr) {\r\n    ...\r\n  }\r\n}<\/pre>\n<p><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">Druh\u00e1 met\u00f3da je ale defaultn\u00e1 (v\u0161imnite si k\u013e\u00fa\u010dov\u00e9 slovo <\/span><\/span><em><span style=\"font-weight: normal;\">defa<\/span><\/em><em><span style=\"font-weight: normal;\">u<\/span><\/em><em><span style=\"font-weight: normal;\">lt<\/span><\/em><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">v jej defin\u00edcii). To v praxi znamen\u00e1, \u017ee ak budete implementova\u0165 toto rozhrani<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">e,<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\"> nemus\u00edte implementova\u0165 dan\u00fa met\u00f3du. Aj preto sa potom toto rozhranie d\u00e1 pou\u017ei\u0165 s Lambda v\u00fdrazmi. V skuto\u010dnosti, aj ke\u010f m\u00e1 met\u00f3d viac, podstatn\u00e9 je, \u017ee m\u00e1 len jednu abstraktn\u00fa.<\/span><\/span><\/p>\n<p><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">S defaul<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">t<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">n\u00fdmi met\u00f3dami si Java otvorila dvere (a mo\u017eno pandorinu skrinku) k nie\u010domu, \u010do naz\u00fdva viacn\u00e1sobn\u00e9 dedenie implement\u00e1cie. <\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">V\u00fdhody a \u00faskalia tohto princ\u00edpu by sta\u010dili na vlastn\u00fd \u010dl\u00e1nok a tak to tu pre tento pr\u00edpad vynech\u00e1m. \u010co v\u00e1s ale napadne, m\u00f4\u017ee by\u0165 ot\u00e1zka, na \u010do je dobr\u00e9? Pre\u010do by som chcel definova\u0165 rozhranie, ktor\u00e9 u\u017e m\u00e1 met\u00f3dy. Odpove\u010f je sp\u00e4tn\u00e1 kompatibilita.<\/span><\/span><\/p>\n<p><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">Java 8 so sebou prin\u00e1\u0161a naozaj pomerne ve\u013ea ve\u013ek\u00fdch zmien. A niektor\u00e9 s\u00fa tak ve\u013ek\u00e9, \u017ee je potrebn\u00e9 upravi\u0165 aj z\u00e1kladn\u00e9 kamene, na ktor\u00fdch Java stoj\u00ed. To s\u00fa napr\u00edklad rozhrania ako List, Map a pod. Kv\u00f4li nov<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">\u00e9<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">m Collection API (o ktorom si povieme niekedy nabud\u00face) bolo potrebn\u00e9 do t\u00fdchto rozhran\u00ed prida\u0165 nov\u00e9 met\u00f3dy. Probl\u00e9m je, \u017ee je to z\u00e1sah do rozhrania, ktor\u00fd sp\u00f4sob\u00ed probl\u00e9m v\u0161etk\u00fdm implement<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">\u00e1ci<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">\u00e1<\/span><\/span><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">m tam vonku. A za t\u00fa dobu ich je pre tieto rozhrania naozaj dos\u0165. Tak\u017ee sa Oracle rozhodol, \u017ee nebude hladka\u0165 tigra proti srsti a pridal do t\u00fdchto rozhran\u00ed defaultn\u00e9 met\u00f3dy, ktor\u00e9 nevy\u017eaduj\u00fa \u017eiaden nov\u00fd development.<\/span><\/span><\/p>\n<p>Mohlo by sa zda\u0165, \u017ee t\u00fdch zmien oh\u013eadom met\u00f3d u\u017e bolo aj dos\u0165, ale e\u0161te st\u00e1le to nie je v\u0161etko. Uk\u00e1zali sme si, ako sa definuj\u00fa anonymn\u00e9 met\u00f3dy a ako sa preposielaj\u00fa. Preposiela\u0165 sa ale nemusia len anonymn\u00e9 met\u00f3dy. A pr\u00e1ve teraz na sc\u00e9nu vstupuj\u00fa referencie na met\u00f3dy.<\/p>\n<p>Pre n\u00e1zorn\u00fa uk\u00e1\u017eku si zadefinujme triedu Car:<\/p>\n<pre>public class Car {\r\n  public static Car create(final Supplier&lt;Car&gt; supplier) { \u2026 }\r\n  public static void collide(final Car car) { \u2026 }\r\n  public void follow(final Car another) { \u2026 }\r\n  public void repair() { \u2026 }\r\n}<\/pre>\n<p>Uk\u00e1\u017ekov\u00fa triedu by sme mali. Po\u010fme si teraz uk\u00e1za\u0165, ako sa vieme odkazova\u0165 na jej met\u00f3dy. Ako prv\u00e9 je to odkaz na klasick\u00fa in\u0161tan\u010dn\u00fa met\u00f3du:<\/p>\n<pre>cars.forEach(Car::repair);<\/pre>\n<p>Dve dvojboky za sebou s\u00fa zase syntaktickou novinkou v Jave. Na in\u0161tan\u010dn\u00fa met\u00f3du sa vieme odk\u00e1za\u0165 aj cez in\u0161tanciu:<\/p>\n<pre>final Car police = new Car();\r\ncars.forEach(police::follow);<\/pre>\n<p>V\u0161imnite si, \u017ee met\u00f3da follow pod\u013ea defin\u00edcie potrebuje jeden parameter typu triedy Car. Ten ale v tomto k\u00f3de neposielam. Po\u0161le sa tam automaticky. Teda ak vol\u00e1m in\u0161tan\u010dn\u00fa met\u00f3du nad in\u0161tanciou, tak t\u00e1 met\u00f3da ju dostane ako parameter.<\/p>\n<p>Takto vyzer\u00e1 volanie statickej met\u00f3dy:<\/p>\n<pre>cars.forEach(Car::collide);<\/pre>\n<p>A na z\u00e1ver si pozrieme odkaz na kon\u0161truktor:<\/p>\n<pre>final Car car = Car.create(Car::new);<\/pre>\n<p><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">Kon\u0161truktor je teda tie\u017e met\u00f3da, na ktor\u00fa sa d\u00e1 odkazova\u0165. Namiesto n\u00e1zvu met\u00f3dy sa pou\u017eije k\u013e\u00fa\u010dov\u00e9 slovo <\/span><\/span><em><span style=\"font-weight: normal;\">new<\/span><\/em><span style=\"font-style: normal;\"><span style=\"font-weight: normal;\">. <\/span><\/span><\/p>\n<p>Ak\u00fd je vlastne rozdiel medzi Lambda v\u00fdrazmi a referenciami na met\u00f3du? Ve\u013ek\u00fd nie. Vlastne len to, \u017ee Lambda v\u00fdraz nem\u00e1 meno, a tak sa na nich ned\u00e1 odkazova\u0165 mimo toho, kde s\u00fa pou\u017eit\u00e9. Referencie na met\u00f3dy meno maj\u00fa, a teda s\u00fa viackr\u00e1t pou\u017eite\u013en\u00e9 (a v\u010faka tomu aj lep\u0161ie identifikovate\u013en\u00e9 pri \u010d\u00edtan\u00ed k\u00f3du). Inak sa s nimi pracuje rovnako. Odpor\u00fa\u010dan\u00fd postup je tak\u00fd, \u017ee ak potrebujete met\u00f3du pou\u017ei\u0165 na jednom mieste, pou\u017eite Lambdu. Ak na viacer\u00fdch, zadefinujete ju niekde a pou\u017eijete referencie na \u0148u.<\/p>\n<p>Ako je vidno, Java 8 neberie met\u00f3dy na \u013eahk\u00fa v\u00e1hu. Prin\u00e1\u0161a \u0161irok\u00fd arzen\u00e1l mo\u017enost\u00ed, ktor\u00fd ur\u010dite zak\u00fdva doteraj\u0161\u00edmi postupmi v\u00fdvoja (mysl\u00edm si, \u017ee u\u017e aj z\u00e1kladn\u00e1 sada n\u00e1vrhov\u00fdch vzorov po tomto dostane svoj update). Na v\u0161etky tieto novinky sa treba pozera\u0165 ako na nov\u00fd n\u00e1stroj, ktor\u00fd stoj\u00ed za to pozna\u0165 a aj pou\u017ei\u0165. Obzvl\u00e1\u0161\u0165 zauj\u00edmav\u00e9 je to v spojen\u00ed s nov\u00fdm Collection API, o ktorom si povieme nabud\u00face.<\/p>","protected":false},"excerpt":{"rendered":"<p>Toto je druh\u00fd zo s\u00e9rie \u010dl\u00e1nkov o tom, \u010do je nov\u00e9 v Jave 8. V tom prvom sme si rozobrali lambda met\u00f3dy. Teda mo\u017enos\u0165, ako zadefinova\u0165 anonymn\u00fa met\u00f3du na jedno pou\u017eitie. Nov\u00e9 sp\u00f4soby met\u00f3d pri tomto ale nekon\u010dia. Dnes si uk\u00e1\u017eeme, \u017ee v novej Jave s\u00fa met\u00f3dy naozaj first-class citizen, a tie\u017e to, \u017ee rozhrania [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-96","post","type-post","status-publish","format-standard","hentry","category-vyvoj-softveru"],"_links":{"self":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts\/96","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/comments?post=96"}],"version-history":[{"count":4,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts\/96\/revisions"}],"predecessor-version":[{"id":311,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts\/96\/revisions\/311"}],"wp:attachment":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/media?parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/categories?post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/tags?post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}