Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Java 8 introduserer såkalte lambda-uttrykk som kan være svært nyttige i å forenkle kode og utføre funksjonell programmering i Java. For å kunne skjønne lambda-uttrykkrykk uttrykk bør vi først nevne litt om funksjonelle grensesnitt.

...

Vi kan ta i bruk dette grensesnittet på den tradisjonelle måten ved å opprette en egen klasse som implementerer Multiplier, og deretter opprette en instans av denne klassen, som vi kaller multiply fra. Men dette blir utrolig tungvint for å bruke en så enkel metode som multiplysom multiply. For å slippe dette lar Java oss definere et objekt som implementerer grensesnittet direkte, ved at man definerer metoden(e) til grensesnittet i initaliseringen av objektet (se venstre kolonne under). Merk at dette fungerer også for grensesnitt med flere metoder.

Denne direkte implementasjonen sparer oss mye kode, men det er fortsatt ganske tungvint. Lambda-uttrykk lar oss gjøre dette mye enklere. Høyre kolonne viser hvordan man kan gjøre nøyaktig det samme, på én linje.

Direkte implementasjon 

Code Block
themeEclipse
languagejava
titleDirekte implementasjon
Multiplier multiplier = new Multiplier() {
    @Override
    public double multiply(double x, double y) {
        return x * y;
    }
};

 

Med lambda 

Code Block
themeEclipse
languagejava
titleMed lambda
Multiplier multiplier = (x, y) -> x * y;

 

...

Eksemplene under vil være forskjellige implementasjoner av run()-metoden til PersonMain.java.

 

anyMatch

Vi begynner med et enkelt og nyttig eksempel på bruk av Predicate-grensesnittet og streams. anyMatch er en metode som tar inn en Predicate-instans og returnerer true dersom minst ett av elementene i den aktuelle streamen tilfredsstiller predikatet. For eksempel, finnes det en kvinne i lista vår?

Code Block
themeEclipse
languagejava
titleTradisjonell måte
 for (Person p : persons) {
    if (p.getGender() == 'F') {
        System.out.println(true);
    }
}
Code Block
themeEclipse
languagejava
titleMed stream og lambda
 System.out.println(persons.stream().anyMatch(p -> p.getGender() == 'M'));

Til høyre tar vi lista vår persons, kaller metoden stream() på den for å gjøre den til en stream og få tak i den innebygde anyMatch-metoden. anyMatch tar som kjent et predikatobjekt som argument, som vi definerer på lambdavis. Predicate-instansen vi oppretter får inn et Person-objekt (p) som argument, og returnerer true dersom den aktuelle personens kjønn er kvinne. 

Det er flere andre metoder som ligner på anyMatch: allMatch (alle element i en stream tilfredsstiller predikatet), findAny (returnerer et element som tilfredsstiller predikatet), findFirst (returnerer det første elementet som tilfredsstiller predikatet).

 

Filter

Filter er en svært vanlig operasjon på lister (i likhet med map og reduce som vi nevner senere), som er mange programmeringsspråk har støtte for. Filter kalles på en liste, og returnerer en ny liste med kun de elementene som tilfredsstiller et gitt predikat. For eksempel: Hvilke personer er over 18 år?

 

Code Block
themeEclipse
languagejava
titleTradisjonell måte
List<Person> overEighteen = new ArrayList<Person>();
for (Person p : persons) {
    if (p.getAge() >= 18) {
        overEighteen.add(p);
    }
}
System.out.println(overEighteen);

 

 

Code Block
themeEclipse
languagejava
titleMed stream og lambda
 System.out.println(persons.stream().filter(p -> p.getAge() >= 18).collect(Collectors.toList()));

 

Siden filter-funksjonen returnerer en stream, bruker vi collect for å gjøre den til en List.

 

forEach

forEach tar inn en Consumer-instans og kaller denne instansens ene metode på alle elementene i streamen. La oss legge til et år på alle personenes alder.

 

Code Block
themeEclipse
languagejava
titleTradisjonell måte
for (Person p : persons) {
    p.setAge(p.getAge() + 1);
}

 

 

Code Block
themeEclipse
languagejava
titleMed lambda
persons.stream().forEach(p -> p.setAge(p.getAge() + 1));

 

Vi kan også kombinere funksjoner på streams, for eksempel filter og forEach. La oss si vi vil legge til et år på alderen til alle gutter under 18:

 

Code Block
themeEclipse
languagejava
titleTradisjonell måte
for (Person p : persons) {
    if (p.getAge() < 18 && p.getGender() == 'M')
        p.setAge(p.getAge() + 1);
}

 

 

Code Block
themeEclipse
languagejava
titleMed lambda
persons.stream()
	.filter(p -> p.getAge() < 18 && p.getGender() == 'M')
	.forEach(p -> p.setAge(p.getAge() + 1));