Metodehenvisninger i Java

1. Oversikt

En av de mest velkomne endringene i Java 8 var introduksjonen av lambdauttrykk, ettersom disse tillater oss å gi avkall på anonyme klasser, noe som reduserer kjeleplatekoden og forbedrer lesbarheten.

Metodehenvisninger er en spesiell type lambdauttrykk. De brukes ofte til å lage enkle lambdauttrykk ved å referere til eksisterende metoder.

Det er fire typer metodereferanser:

  • Statiske metoder
  • Forekomstmetoder for bestemte objekter
  • Forekomstmetoder for et vilkårlig objekt av en bestemt type
  • Konstruktør

I denne opplæringen vil vi utforske metodereferanser i Java.

2. Henvisning til en statisk metode

Vi begynner med et veldig enkelt eksempel, kapitalisering og utskrift av en liste over Strenger:

Listemeldinger = Arrays.asList ("hei", "baeldung", "lesere!");

Vi kan oppnå dette ved å bruke et enkelt lambdauttrykk som kaller StringUtils.capitalize () metode direkte:

meldinger.forEach (ord -> StringUtils.capitalize (ord));

Eller vi kan bruke en referanse til å referere til kapitalisere statisk metode:

messages.forEach (StringUtils :: kapitaliser);

Legg merke til at metodereferanser alltid bruker :: operatør.

3. Henvisning til en instansmetode for et spesielt objekt

For å demonstrere denne typen referanse, la oss vurdere to klasser:

offentlig klasse Sykkel {private String merkevare; private HeltalsrammeSize; // standard konstruktør, getters og setter} offentlig klasse BicycleComparator implementerer Comparator {@Override public int Compare (Bicycle a, Bicycle b) {return a.getFrameSize (). CompareTo (b.getFrameSize ()) }}

Og la oss lage en BicycleComparator objekt for å sammenligne sykkelstørrelser:

BicycleComparator bikeFrameSizeComparator = ny BicycleComparator ();

Vi kan bruke et lambdauttrykk til å sortere sykler etter rammestørrelse, men vi må spesifisere to sykler for sammenligning:

createBicyclesList (). stream () .sorted ((a, b) -> bikeFrameSizeComparator.compare (a, b));

I stedet kan vi bruke en metodereferanse for å få kompilatorhåndteringsparameteren passert for oss:

createBicyclesList (). stream () .sorted (bikeFrameSizeComparator :: sammenlign);

Metodehenvisningen er mye renere og mer lesbar, da intensjonen vår tydelig vises av koden.

4. Henvisning til en instansemetode for et vilkårlig objekt av en bestemt type

Denne typen metodehenvisning ligner på forrige eksempel, men uten å måtte opprette et egendefinert objekt for å utføre sammenligningen.

La oss lage en Heltall liste som vi vil sortere:

Listetall = Arrays.asList (5, 3, 50, 24, 40, 2, 9, 18);

Hvis vi bruker et klassisk lambdauttrykk, må begge parametrene overføres eksplisitt, mens det å bruke en metodereferanse er mye enklere:

numbers.stream () .sorted ((a, b) -> a.compareTo (b)); numbers.stream () .sorted (Heltall :: sammenlignTo);

Selv om det fremdeles er en linje, er referansen til metoden mye lettere å lese og forstå.

5. Henvisning til en konstruktør

Vi kan referere til en konstruktør på samme måte som vi refererte til en statisk metode i vårt første eksempel. Den eneste forskjellen er at vi bruker ny nøkkelord.

La oss lage en Sykkel array ut av en String liste med forskjellige merker:

Liste bikeBrands = Arrays.asList ("Giant", "Scott", "Trek", "GT");

Først legger vi til en ny konstruktør i vår Sykkel klasse:

offentlig sykkel (strengmerke) {this.brand = merkevare; this.frameSize = 0; } 

Deretter bruker vi den nye konstruktøren vår fra en metodereferanse og lager en Sykkel matrise fra originalen String liste:

bikeBrands.stream () .map (Sykkel :: ny) .toArray (Sykkel [] :: ny); 

Legg merke til hvordan vi kalte begge deler Sykkel og Array konstruktører som bruker en metodereferanse, og gir koden vår et mye mer kortfattet og tydelig utseende.

6. Ytterligere eksempler og begrensninger

Som vi har sett så langt, er metodereferanser en fin måte å gjøre koden og intensjonene våre veldig klare og lesbare. Vi kan imidlertid ikke bruke dem til å erstatte alle slags lambdauttrykk, siden de har noen begrensninger.

Deres viktigste begrensning er et resultat av det som også er deres største styrke: utgangen fra forrige uttrykk må samsvare med inngangsparametrene til den refererte metodesignaturen.

La oss se et eksempel på denne begrensningen:

createBicyclesList (). forEach (b -> System.out.printf ("Sykkelmerke er '% s' og rammestørrelse er '% d'% n", b.getBrand (), b.getFrameSize ()));

Denne enkle saken kan ikke uttrykkes med en metodehenvisning, fordi printf metoden krever 3 parametere i vårt tilfelle, og bruk createBicyclesList (). forEach () ville bare tillate at metoden refererer til å utlede en parameter ( Sykkel gjenstand).

Til slutt, la oss utforske hvordan du oppretter en funksjonsfri funksjon som det kan refereres til fra et lambdauttrykk.

I dette tilfellet vil vi bruke et lambdauttrykk uten å bruke parametrene.

La oss først lage gjør ingenting metode:

privat statisk tomrom doNothingAtAll (Object ... o) {}

Siden det er en varargs-metode, vil den fungere i ethvert lambdauttrykk, uansett det refererte objektet eller antall parametere som er utledet.

La oss nå se det i aksjon:

createBicyclesList () .forEach ((o) -> MethodReferenceExamples.doNothingAtAll (o)); 

7. Konklusjon

I denne raske opplæringen lærte vi hvilke metodereferanser som er i Java og hvordan vi kan bruke dem til å erstatte lambdauttrykk, og derved forbedrer lesbarheten og klargjør programmørens intensjon.

All kode presentert i denne artikkelen er tilgjengelig på GitHub.