Ohjelmointi

Aloita menetelmäviitteiden käyttäminen Java-ohjelmassa

Lambdojen ohella Java SE 8 toi menetelmäviitteet Java-kieleen. Tässä opetusohjelmassa on lyhyt yleiskatsaus Java-menetelmäviitteisiin, minkä jälkeen pääset aloittamaan niiden käytön Java-koodiesimerkkien kanssa. Opetusohjelman loppuun mennessä opit käyttämään menetelmäviitteitä viitataksesi luokan staattisiin menetelmiin, sidottuihin ja sitomattomiin ei-staattisiin menetelmiin ja konstruktoreihin sekä kuinka käyttää niitä viitattaessa yliluokan ja nykyisen luokan ilmentymämenetelmiin tyypit. Ymmärrät myös, miksi monet Java-kehittäjät ovat ottaneet lambda-lausekkeet ja menetelmäviitteet puhtaammaksi, yksinkertaisemmaksi vaihtoehdoksi nimettömille luokille.

Huomaa, että tämän opetusohjelman koodiesimerkit ovat yhteensopivia JDK 12: n kanssa.

lataa Hanki koodi Lataa lähdekoodi esimerkiksi sovelluksiin tässä opetusohjelmassa. Luonut Jeff Friesen JavaWorldille.

Menetelmäviitteet: Aluke

Edellisessä Java 101 -opetusohjelmassa esiteltiin lambda-lausekkeita, joita käytetään määrittelemään anonyymejä menetelmiä, joita voidaan sitten käsitellä toiminnallisen käyttöliittymän esiintyminä. Joskus lambda-lauseke ei muuta kuin kutsu olemassa olevaa menetelmää. Esimerkiksi seuraava koodifragmentti käyttää lambdaa kutsuttaakseen System.outon mitätön println (s) menetelmä lambdan ainoalla argumentilla -sTyyppiä ei vielä tunneta:

-> System.out.println (t)

Lambda esittelee s virallisena parametriluettelona ja koodirunko, jonka System.out.println (t) lauseke tulostaa sarvon tavalliseen lähtövirtaan. Sillä ei ole nimenomaista käyttöliittymätyyppiä. Sen sijaan kääntäjä päättelee ympäröivästä kontekstista, minkä toiminnallisen käyttöliittymän tulee ilmentää. Harkitse esimerkiksi seuraavaa koodinpätkää:

Kuluttajakuluttaja = (t) -> System.out.println (s);

Kääntäjä analysoi edellisen ilmoituksen ja määrittää, että java.util.function.Cumer ennalta määritetyt toiminnalliset käyttöliittymät mitätön hyväksy (T t) menetelmä vastaa lambdan muodollista parametriluetteloa (s). Se myös määrittää sen hyväksyä()on mitätön palautustyypin ottelut println ()on mitätön palautustyyppi. Lambda on siis sidottu että Kuluttaja.

Tarkemmin sanottuna lambda on sidottu Kuluttaja. Kääntäjä luo koodin niin, että kutsutaan Kuluttajaon void accept (merkkijonot) menetelmä johtaa merkkijono argumentti välitetään s siirretään System.outon void println (merkkijonot) menetelmä. Tämä kutsu näkyy alla:

consumer.accept ("Hei"); // Siirrä "Hei" lambda-rungolle. Tulosta Hei vakiolähtöön.

Voit tallentaa näppäinpainallukset korvaamalla lambda: lla a menetelmän viite, joka on tiivis viittaus olemassa olevaan menetelmään. Esimerkiksi seuraava koodifragmentti korvaa (Merkkijonot) -> System.out.println (s) kanssa System.out :: println, missä :: tarkoittaa sitä System.outon void println (merkkijonot) menetelmään viitataan:

Kuluttajakuluttaja2 = System.out :: println; // Menetelmän viite on lyhyempi. kuluttaja2.hyväksy ("Hei"); // Siirrä "Hei" lambda-rungolle. Tulosta Hei vakiolähtöön.

Muodollista parametriluetteloa ei tarvitse määrittää edelliselle menetelmäviitteelle, koska kääntäjä voi päätellä tämän luettelon Kuluttaja Tämä parametrisoitu tyyppi on java.lang.String todellinen tyyppi -argumentti korvaa T sisään mitätön hyväksy (T t), ja se on myös lambda-rungon yksittäisen parametrin tyyppi System.out.println () menetelmäpuhelu.

Menetelmäviitteet perusteellisesti

A menetelmän viite on syntaktinen pikakuvake lambdan luomiseen olemassa olevasta menetelmästä. Toteutusrungon tarjoamisen sijaan menetelmäviite viittaa olemassa olevan luokan tai objektin menetelmään. Kuten lambda, menetelmäviite vaatii kohdetyypin.

Metodiviittausten avulla voit viitata luokan staattisiin menetelmiin, sidottuihin ja sitomattomiin ei-staattisiin menetelmiin ja konstruktoreihin. Voit myös käyttää menetelmäviitteitä viitataksesi yliluokan ja nykyisten luokkatyyppien ilmentymämenetelmiin. Esittelen sinulle kaikki nämä menetelmien viiteluokat ja näytän, miten niitä käytetään pienessä esittelyssä.

Lisätietoja menetelmäviitteistä

Kun olet lukenut tämän osan, tutustu Java 8: n Method References -artikkeliin (Toby Weston, helmikuu 2014) saadaksesi lisää tietoa menetelmäviitteistä sidotuissa ja sitomattomissa ei-staattisissa menetelmäkonteksteissa.

Viittaukset staattisiin menetelmiin

A staattinen menetelmäviite viittaa staattiseen menetelmään tietyssä luokassa. Sen syntaksia on luokan nimi::staticMethodName, missä luokan nimi tunnistaa luokan ja staticMethodName tunnistaa staattisen menetelmän. Esimerkki on Kokonaisluku :: bitCount. Listaus 1 osoittaa staattisen menetelmän viitteen.

Listing 1. MRDemo.java (versio 1)

tuo java.util.Arrays; tuo java.util.function.Consumer; public class MRDemo {public static void main (String [] args) {int [] array = {10, 2, 19, 5, 17}; Kuluttaja kuluttaja = Taulukot :: lajittelu; kuluttaja. hyväksy (taulukko); for (int i = 0; i <taulukon pituus; i ++) System.out.println (taulukko [i]); System.out.println (); int [] taulukko2 = {19, 5, 14, 3, 21, 4}; Kuluttajakuluttaja2 = (a) -> Taulukot. Lajittelu (a); kuluttaja2.hyväksy (taulukko2); for (int i = 0; i <matriisi2.pituus; i ++) System.out.println (taulukko2 [i]); }}

Listaus 1: stä main () method lajittelee parin kokonaislukumatriiseja java.util.Arrays luokan staattinen tyhjä lajittelu (int [] a) menetelmä, joka esiintyy staattisessa menetelmäviitteessä ja vastaavissa lambda-lausekekonteksteissa. Taulukon lajittelun jälkeen a varten loop tulostaa lajitellun matriisin sisällön vakiolähtövirtaan.

Ennen kuin voimme käyttää menetelmäviittausta tai lambdaa, se on sidottava toiminnalliseen rajapintaan. Käytän ennalta määritettyä Kuluttaja toiminnallinen rajapinta, joka täyttää menetelmän viitetiedot / lambda-vaatimukset. Lajitteluoperaatio aloitetaan siirtämällä lajiteltava taulukko Kuluttajaon hyväksyä() menetelmä.

Koosta luettelo 1 (javac MRDemo.java) ja suorita sovellus (java MRDemo). Havaitset seuraavan tuloksen:

2 5 10 17 19 3 4 5 14 19 21

Viittaukset sidottuihin ei-staattisiin menetelmiin

A sidottu ei-staattinen menetelmäviite viittaa ei-staattiseen menetelmään, joka on sidottu a: hon vastaanotin esine. Sen syntaksia on objectName::instanceMethodName, missä objectName tunnistaa vastaanottajan ja instanceMethodName tunnistaa instanssimenetelmän. Esimerkki on s :: leikkaus. Listaus 2 osoittaa sitoutuneen ei-staattisen menetelmäviitteen.

Listing 2. MRDemo.java (versio 2)

tuo java.util.function.Supplier; public class MRDemo {public static void main (String [] args) {String s = "Nopea ruskea kettu hyppäsi laiskan koiran yli"; painatus (s :: pituus); tulosta (() -> s. pituus ()); tulosta (uusi toimittaja () {@Override public Integer get () {return s.length (); // sulkeutuu yli s}}); } public static void print (toimittajan toimittaja) {System.out.println (toimittaja.get ()); }}

Listaus 2: sta main () method määrittää merkkijonon Merkkijono muuttuja s ja kutsuu sitten Tulosta() luokan menetelmä ja toiminnallisuus tämän merkkijonon pituuden saamiseksi tämän menetelmän argumenttina. Tulosta() kutsutaan menetelmäviitteessä (s :: pituus -- pituus() on sidottu s), vastaava lambda ja vastaavat nimettömät luokkakontekstit.

Olen määrittänyt Tulosta() käyttää java.util.function.Supplier ennalta määritelty toiminnallinen käyttöliittymä, jonka saada() method palauttaa tulosten toimittajan. Tässä tapauksessa Toimittaja ilmentymä siirretty Tulosta() toteuttaa sen saada() tapa palata s.pituus (); Tulosta() tuottaa tämän pituuden.

s :: pituus esittelee sulkimen, joka sulkeutuu s. Voit nähdä tämän selkeämmin lambda-esimerkissä. Koska lambdalla ei ole argumentteja, arvon arvo on s on saatavana vain oheisesta soveltamisalasta. Siksi lambda-runko on suljin, joka sulkeutuu s. Nimetön luokan esimerkki tekee siitä vielä selvemmän.

Käännä Listing 2 ja suorita sovellus. Havaitset seuraavan tuloksen:

44 44 44

Viittaukset sitomattomiin ei-staattisiin menetelmiin

An sitomaton ei-staattinen menetelmäviite viittaa ei-staattiseen menetelmään, joka ei ole sidottu vastaanottajaobjektiin. Sen syntaksia on luokan nimi::instanceMethodName, missä luokan nimi tunnistaa luokan, joka ilmoittaa ilmentymämenetelmän ja instanceMethodName tunnistaa instanssimenetelmän. Esimerkki on Merkkijono :: toLowerCase.

Merkkijono :: toLowerCase on sitomaton ei-staattinen menetelmäviite, joka tunnistaa ei-staattisen Merkkijono alempaan tapaukseen () menetelmä Merkkijono luokassa. Koska ei-staattinen menetelmä vaatii kuitenkin edelleen vastaanotinobjektin (tässä esimerkissä a Merkkijono esine, jota käytetään kutsumaan toLowerCase () menetelmäviitteen avulla) virtuaalikone luo vastaanottajaobjektin. toLowerCase () kutsutaan tälle objektille. Merkkijono :: toLowerCase määrittää menetelmän, joka kestää yhden Merkkijono argumentti, joka on vastaanottajaobjekti ja palauttaa a Merkkijono tulos. Merkkijono :: toLowerCase () vastaa lambdaa (Merkkijono) -> {palauta s.LowerCase (); }.

Listaus 3 osoittaa tämän sitomattoman ei-staattisen menetelmäviitteen.

Listaus 3. MRDemo.java (versio 3)

tuo java.util.function.Function; public class MRDemo {public static void main (String [] args) {print (String :: toLowerCase, "STRING LOWERCASE"); tulosta (s -> s.toLowerCase (), "STRING LOWERCASE"); tulosta (uusi toiminto () {@Override public String Apply (String s) // vastaanottaa argumentin parametrissa s; {// ei tarvitse sulkea yli s palauttaa s.toLowerCase ();}}, "STRING LOWERCASE" ); } public static void print (Function function, String s) {System.out.println (function.apply (s)); }}

Luettelo 3: sta main () menetelmä kutsuu Tulosta() luokan menetelmä toiminnallisuudella muuntaa merkkijono pieniksi ja muunnettava merkkijono menetelmän argumentteina. Tulosta() kutsutaan menetelmäviitteessä (Merkkijono :: toLowerCase, missä toLowerCase () ei ole sidottu käyttäjän määrittelemään objektiin) ja vastaaviin lambda- ja nimettömiin luokkakonteksteihin.

Olen määrittänyt Tulosta() käyttää java.util.function.Function ennalta määritetty toiminnallinen käyttöliittymä, joka edustaa funktiota, joka hyväksyy yhden argumentin ja tuottaa tuloksen. Tässä tapauksessa Toiminto ilmentymä siirretty Tulosta() toteuttaa sen R sovelletaan (T t) tapa palata s.toLowerCase (); Tulosta() antaa tämän merkkijonon.

vaikkakin Merkkijono osa Merkkijono :: toLowerCase näyttää siltä, ​​että luokkaan viitataan, vain tämän luokan ilmentymään viitataan. Nimetön luokan esimerkki tekee tästä selvemmän. Huomaa, että nimettömässä luokan esimerkissä lambda saa argumentin; se ei sulje parametria s (ts. se ei ole sulkeminen).

Koosta Listaus 3 ja suorita sovellus. Havaitset seuraavan tuloksen:

merkkijono pieniin merkkijonoihin pieniin merkkijonoihin pieniin

Viittaukset rakentajiin

Voit käyttää metodiviitettä viitataksesi rakentajaan nimeämättä luokkaa. Tällainen menetelmäviite tunnetaan nimellä rakentajan viite. Sen syntaksia on luokan nimi::Uusi. luokan nimi on tuettava esineiden luomista; se ei voi nimetä abstraktia luokkaa tai käyttöliittymää. Avainsana Uusi nimeää viitatun rakentajan. Tässä on joitain esimerkkejä:

  • Merkki :: uusi: vastaa lambdaa (Merkki ch) -> uusi merkki (ch)
  • Pitkä :: uusi: vastaa lambdaa (pitkä arvo) -> uusi Pitkä (arvo) tai (Merkkijonot) -> uudet pitkät
  • ArrayList :: uusi: vastaa lambdaa () -> uusi ArrayList ()
  • kellua [] :: uusi: vastaa lambdaa (int-koko) -> uusi kelluva [koko]

Viimeinen konstruktorin viite-esimerkki määrittelee ryhmätyypin luokkatyypin sijaan, mutta periaate on sama. Esimerkki osoittaa taulukon rakentajan viite matriisityyppiselle "konstruktorille".

Määritä luodaksesi rakentajaviitteen Uusi ilman rakentajaa. Kun luokka kuten java.lang.pitkä julistaa useita rakentajia, kääntäjä vertaa toiminnallisen rajapinnan tyyppiä kaikkiin rakentajiin ja valitsee parhaan vastaavuuden. Listaus 4 osoittaa rakentajan viitteen.

Listing 4. MRDemo.java (versio 4)

tuo java.util.function.Supplier; public class MRDemo {public static void main (String [] args) {Toimittajatoimittaja = MRDemo :: new; System.out.println (toimittaja.get ()); }}

Listaus 4: stä MRDemo :: uusi konstruktorin viite vastaa lambdaa () -> uusi MRDemo (). Ilmaisu toimittaja.get () toteuttaa tämän kutsuvan lambdan MRDemooletusarvoinen ei-argumenttirakentaja ja palauttaa MRDemo esine, joka välitetään System.out.println (). Tämä menetelmä muuntaa objektin merkkijonoksi, jonka se tulostaa.

Oletetaan, että sinulla on luokka, jossa ei ole argumenttia ja konstruktori, joka ottaa argumentin, ja haluat kutsua konstruktorin, joka ottaa argumentin. Voit suorittaa tämän tehtävän valitsemalla toisen toiminnallisen käyttöliittymän, kuten esimääritetyn Toiminto käyttöliittymä näkyy luettelossa 5.

Listing 5. MRDemo.java (versio 5)

tuo java.util.function.Function; julkisen luokan MRDemo {yksityinen merkkijono nimi; MRDemo () {nimi = ""; } MRDemo (merkkijono) {this.name = nimi; System.out.printf ("MRDemo (merkkijonon nimi) kutsuttu% s% n", nimi); } public static void main (Merkkijono [] argumentit) {Funktiofunktio = MRDemo :: new; System.out.println (function.apply ("jokin nimi")); }}

Toimintofunktio = MRDemo :: uusi; saa kääntäjän etsimään konstruktoria, joka ottaa a: n Merkkijono väite, koska Toimintoon Käytä() menetelmä vaatii yhden (tässä yhteydessä) Merkkijono Perustelu. Suoritetaan function.apply ("jokin nimi") johtaa "jokin nimi" siirretään MRDemo (merkkijono).