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.out
on mitätön println (s)
menetelmä lambdan ainoalla argumentilla -s
Tyyppiä ei vielä tunneta:
-> System.out.println (t)
Lambda esittelee s
virallisena parametriluettelona ja koodirunko, jonka System.out.println (t)
lauseke tulostaa s
arvon 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 Kuluttaja
on void accept (merkkijonot)
menetelmä johtaa merkkijono argumentti välitetään s
siirretään System.out
on 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.out
on 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 Kuluttaja
on 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 MRDemo
oletusarvoinen 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 Toiminto
on Käytä()
menetelmä vaatii yhden (tässä yhteydessä) Merkkijono
Perustelu. Suoritetaan function.apply ("jokin nimi")
johtaa "jokin nimi"
siirretään MRDemo (merkkijono)
.