Spolu s lambdas přinesla Java SE 8 odkazy na metody v jazyce Java. Tento výukový program nabízí stručný přehled odkazů na metody v Javě a poté je můžete začít používat s příklady kódu Java. Na konci tohoto kurzu budete vědět, jak používat odkazy na metody k odkazování na statické metody třídy, vázané a nevázané nestatické metody a konstruktory, a také jak je používat k odkazování na metody instance v nadtřídě a aktuální třídě typy. Pochopíte také, proč mnoho vývojářů Java přijalo výrazy lambda a odkazy na metody jako čistší a jednodušší alternativu k anonymním třídám.
Všimněte si, že příklady kódu v tomto kurzu jsou kompatibilní s JDK 12.
stáhnout Získat kód Stáhněte si zdrojový kód například pro aplikace v tomto výukovém programu. Vytvořil Jeff Friesen pro JavaWorld.Odkazy na metody: Základní nátěr
Můj předchozí výukový program Java 101 představil výrazy lambda, které se používají k definování anonymních metod, s nimiž lze potom zacházet jako s instancemi funkčního rozhraní. Výraz lambda někdy neudělá nic jiného než volání existující metody. Například následující fragment kódu používá k vyvolání lambda System.out
je neplatný tisk (y)
metoda na jediném argumentu lambda -s
typ zatím není znám:
(s) -> System.out.println (s)
Lambda představuje (s)
jako jeho formální seznam parametrů a tělo kódu, jehož System.out.println (s)
tisk výrazů s
hodnota pro standardní výstupní proud. Nemá explicitní typ rozhraní. Místo toho kompilátor vyvozuje z okolního kontextu, které funkční rozhraní má vytvořit instanci. Zvažte například následující fragment kódu:
Spotřebitel spotřebitel = (s) -> System.out.println (s);
Kompilátor analyzuje předchozí deklaraci a určuje, že java.util.function.Consumer
předdefinované funkční rozhraní neplatnost přijmout (T t)
metoda odpovídá formálnímu seznamu parametrů lambda ((s)
). To také určuje akceptovat()
je prázdnota
návratový typ odpovídá println ()
je prázdnota
návratový typ. Lambda je tedy vázaný na Spotřebitel
.
Přesněji řečeno, lambda je vázána na Spotřebitel
. Kompilátor generuje kód tak, že vyvolá Spotřebitel
je void přijmout (řetězce)
metoda má za následek předání řetězcového argumentu s
předán System.out
je void println (String s)
metoda. Toto vyvolání je uvedeno níže:
consumer.accept ("Hello"); // Předejte „Hello“ tělu lambda. Tisk Hello na standardní výstup.
Chcete-li uložit stisknutí kláves, můžete lambdu nahradit a odkaz na metodu, což je kompaktní odkaz na existující metodu. Například nahradí následující fragment kódu (String s) -> System.out.println (s)
s System.out :: println
, kde ::
znamená to System.out
je void println (String s)
metoda je odkazována:
Spotřebitel consumer2 = System.out :: println; // Odkaz na metodu je kratší. consumer2.accept ("Hello"); // Předejte „Hello“ tělu lambda. Tisk Hello na standardní výstup.
Není nutné specifikovat formální seznam parametrů pro předchozí odkaz na metodu, protože kompilátor může tento seznam odvodit na základě Spotřebitel
Tento parametrovaný typ řetězec java.lang
skutečný typ argumentu nahrazuje T
v neplatnost přijmout (T t)
, a je také typem jediného parametru v těle lambda System.out.println ()
volání metody.
Metodické odkazy do hloubky
A odkaz na metodu je syntaktická zkratka pro vytvoření lambda z existující metody. Místo poskytnutí těla implementace odkaz na metodu odkazuje na metodu existující třídy nebo objektu. Stejně jako u lambda vyžaduje odkaz na metodu cílový typ.
Odkazy na metody můžete použít k odkázání na statické metody třídy, vázané a nevázané nestatické metody a konstruktory. Můžete také použít odkazy na metody k odkazování na metody instance v nadtřídě a aktuálních typech tříd. Představím vám každou z těchto referenčních kategorií metod a ukážu, jak se používají v malé ukázce.
Další informace o odkazech na metody
Po přečtení této části se podívejte na Odkazy na metody v Javě 8 (Toby Weston, únor 2014), kde získáte další informace o odkazech na metody ve vázaných a nevázaných nestatických kontextech metod.
Odkazy na statické metody
A statická reference metody odkazuje na statickou metodu v konkrétní třídě. Jeho syntaxe je jméno třídy::staticMethodName
, kde jméno třídy
identifikuje třídu a staticMethodName
identifikuje statickou metodu. Příkladem je Celé číslo :: bitCount
. Výpis 1 ukazuje odkaz na statickou metodu.
Výpis 1. MRDemo.java (verze 1)
import java.util.Arrays; import java.util.function.Consumer; veřejná třída MRDemo {public static void main (String [] args) {int [] pole = {10, 2, 19, 5, 17}; Spotřebitel spotřebitel = Pole :: řazení; consumer.accept (pole); for (int i = 0; i <array.length; i ++) System.out.println (pole [i]); System.out.println (); int [] pole2 = {19, 5, 14, 3, 21, 4}; Spotřebitel consumer2 = (a) -> Arrays.sort (a); consumer2.accept (array2); for (int i = 0; i <array2.length; i ++) System.out.println (pole2 [i]); }}
Seznam 1 hlavní()
metoda seřadí dvojici celočíselných polí přes java.util.Arrays
třídy static void sort (int [] a)
metoda, která se objevuje ve statických referencích metod a ekvivalentních kontextech výrazů lambda. Po seřazení pole a pro
smyčka vytiskne obsah seřazeného pole do standardního výstupního proudu.
Než budeme moci použít odkaz na metodu nebo lambdu, musí být vázán na funkční rozhraní. Používám předdefinované Spotřebitel
funkční rozhraní, které splňuje požadavky metody reference / lambda. Operace třídění začíná předáním pole, do kterého se má řadit Spotřebitel
je akceptovat()
metoda.
Zkompilovat výpis 1 (javac MRDemo.java
) a spusťte aplikaci (java MRDemo
). Budete sledovat následující výstup:
2 5 10 17 19 3 4 5 14 19 21
Odkazy na vázané nestatické metody
A vázaný odkaz na nestatickou metodu odkazuje na nestatickou metodu, která je vázána na a přijímač objekt. Jeho syntaxe je název_objektu::instanceMethodName
, kde název_objektu
identifikuje příjemce a instanceMethodName
identifikuje metodu instance. Příkladem je s :: trim
. Výpis 2 ukazuje vázaný odkaz na nestatickou metodu.
Výpis 2. MRDemo.java (verze 2)
import java.util.function.Supplier; veřejná třída MRDemo {public static void main (String [] args) {String s = "Rychlá hnědá liška přeskočila na líného psa"; tisk (s :: délka); print (() -> s.length ()); print (new Supplier () {@Override public Integer get () {return s.length (); // zavírá přes s}}); } public static void print (dodavatel dodavatele) {System.out.println (supplier.get ()); }}
Výpis 2 hlavní()
metoda přiřadí řetězec Tětiva
proměnná s
a poté vyvolá tisk()
metoda třídy s funkčností k získání délky tohoto řetězce jako argumentu této metody. tisk()
je vyvolána v odkazu na metodu (s :: délka
-- délka()
je vázán s
), ekvivalentní lambda a ekvivalentní kontexty anonymních tříd.
Definoval jsem tisk()
používat java.util.function.Supplier
předdefinované funkční rozhraní, jehož dostat()
metoda vrací dodavatele výsledků. V tomto případě Dodavatel
instance předána tisk()
implementuje své dostat()
způsob návratu s.length ()
; tisk()
výstupy této délky.
s :: délka
zavádí uzávěr, který se uzavírá s
. Vidíte to jasněji v příkladu lambda. Protože lambda nemá žádné argumenty, hodnota s
je k dispozici pouze z přiloženého rozsahu. Proto je lambda tělo uzávěrem, který se zavírá s
. Příklad anonymní třídy to činí ještě jasnějším.
Zkompilujte výpis 2 a spusťte aplikaci. Budete sledovat následující výstup:
44 44 44
Odkazy na nevázané nestatické metody
An nevázaný odkaz na nestatickou metodu odkazuje na nestatickou metodu, která není vázána na objekt přijímače. Jeho syntaxe je jméno třídy::instanceMethodName
, kde jméno třídy
identifikuje třídu, která deklaruje metodu instance a instanceMethodName
identifikuje metodu instance. Příkladem je String :: toLowerCase
.
String :: toLowerCase
je nevázaná nestatická reference na metodu, která identifikuje nestatickou Řetězec toLowerCase ()
metoda Tětiva
třída. Protože však statická metoda stále vyžaduje objekt přijímače (v tomto příkladu a Tětiva
objekt, který se používá k vyvolání toLowerCase ()
prostřednictvím odkazu na metodu) je objekt přijímače vytvořen virtuálním strojem. toLowerCase ()
bude vyvolán u tohoto objektu. String :: toLowerCase
určuje metodu, která trvá jeden Tětiva
argument, který je objektem příjemce, a vrací a Tětiva
výsledek. String :: toLowerCase ()
je ekvivalentní lambda (String s) -> {return s.toLowerCase (); }
.
Výpis 3 ukazuje tento nevázaný odkaz na nestatickou metodu.
Výpis 3. MRDemo.java (verze 3)
import java.util.function.Function; public class MRDemo {public static void main (String [] args) {print (String :: toLowerCase, "STRING TO LOWERCASE"); print (s -> s.toLowerCase (), "STRING TO LOWERCASE"); print (new Function () {@Override public String apply (String s) // přijímá argument v parametru s; {// nemusí uzavírat přes s return s.toLowerCase ();}}, „STRING TO LOWERCASE“ ); } public static void print (Function function, String s) {System.out.println (function.apply (s)); }}
Výpis 3 hlavní()
metoda vyvolá tisk()
metoda třídy s funkcemi pro převod řetězce na malá písmena a řetězec, který má být převeden jako argumenty metody. tisk()
je vyvolána v odkazu na metodu (String :: toLowerCase
, kde toLowerCase ()
není vázán na objekt zadaný uživatelem) a ekvivalentní kontexty lambda a anonymní třídy.
Definoval jsem tisk()
používat java.util.function.Function
předdefinované funkční rozhraní, které představuje funkci, která přijímá jeden argument a vytváří výsledek. V tomto případě Funkce
instance předána tisk()
implementuje své R platí (T t)
způsob návratu s.toLowerCase ()
; tisk()
vypíše tento řetězec.
Ačkoliv Tětiva
část String :: toLowerCase
vypadá, že se odkazuje na třídu, odkazuje se pouze na instanci této třídy. Díky příkladu anonymní třídy je to jasnější. Všimněte si, že v příkladu anonymní třídy lambda obdrží argument; nezavírá se nad parametrem s
(tj. nejde o uzávěr).
Zkompilujte výpis 3 a spusťte aplikaci. Budete sledovat následující výstup:
řetězec na malá písmena řetězec na malá písmena řetězec na malá písmena
Odkazy na konstruktory
Odkaz na metodu můžete použít k odkázání na konstruktor bez vytvoření instance pojmenované třídy. Tento druh odkazu na metodu je znám jako a odkaz na konstruktor. Jeho syntaxe je jméno třídy::Nový
. jméno třídy
musí podporovat vytváření objektů; nemůže pojmenovat abstraktní třídu nebo rozhraní. Klíčové slovo Nový
pojmenuje odkazovaný konstruktor. Zde jsou nějaké příklady:
Znak :: nový
: ekvivalentní lambda(Znak ch) -> nový Znak (ch)
Dlouhé :: nové
: ekvivalentní lambda(dlouhá hodnota) -> nová dlouhá (hodnota)
nebo(String s) -> new Long (s)
ArrayList :: nový
: ekvivalentní lambda() -> new ArrayList ()
float [] :: nové
: ekvivalentní lambda(int size) -> new float [size]
Poslední referenční příklad konstruktoru určuje typ pole místo typu třídy, ale princip je stejný. Příklad ukazuje odkaz na konstruktor pole na „konstruktor“ typu pole.
Chcete-li vytvořit odkaz na konstruktor, zadejte Nový
bez konstruktoru. Když třída jako java.lang.Long
deklaruje více konstruktorů, kompilátor porovná typ funkčního rozhraní se všemi konstruktory a vybere nejlepší shodu. Výpis 4 ukazuje odkaz na konstruktor.
Výpis 4. MRDemo.java (verze 4)
import java.util.function.Supplier; veřejná třída MRDemo {public static void main (String [] args) {dodavatel dodavatele = MRDemo :: nový; System.out.println (supplier.get ()); }}
Výpis 4 MRDemo :: nové
odkaz na konstruktor je ekvivalentní lambda () -> nový MRDemo ()
. Výraz supply.get ()
provede tuto lambdu, která vyvolá MRDemo
je výchozí konstruktor bez argumentů a vrátí MRDemo
objekt, který je předán System.out.println ()
. Tato metoda převede objekt na řetězec, který vytiskne.
Nyní předpokládejme, že máte třídu s konstruktorem bez argumentu a konstruktorem, který přebírá argument, a chcete zavolat konstruktoru, který přebírá argument. Tuto úlohu můžete provést výběrem jiného funkčního rozhraní, například předdefinovaného Funkce
rozhraní zobrazené v seznamu 5.
Výpis 5. MRDemo.java (verze 5)
import java.util.function.Function; veřejná třída MRDemo {soukromé jméno řetězce; MRDemo () {name = ""; } MRDemo (název řetězce) {this.name = name; System.out.printf ("MRDemo (název řetězce) s názvem% s% n", jméno); } public static void main (String [] args) {Function function = MRDemo :: new; System.out.println (function.apply ("nějaké jméno")); }}
Funkce funkce = MRDemo :: new;
způsobí, že kompilátor hledá konstruktor, který přebírá a Tětiva
argument, protože Funkce
je aplikovat()
metoda vyžaduje jeden (v tomto kontextu) Tětiva
argument. Provádění function.apply ("nějaké jméno")
výsledky v "nějaké jméno"
předán MRDemo (název řetězce)
.