Programmēšana

Sāciet ar lambda izteicieniem Java

Pirms Java SE 8 anonīmās klases parasti tika izmantotas, lai nodotu funkcionalitāti metodei. Šī prakse apgrūtināja avota kodu, padarot to grūtāk saprotamu. Java 8 novērsa šo problēmu, ieviešot lambdas. Šī apmācība vispirms iepazīstina ar lambda valodas funkciju, pēc tam detalizētāk iepazīstina ar funkcionālo programmēšanu ar lambda izteiksmēm kopā ar mērķa tipiem. Jūs arī uzzināsiet, kā lambdas mijiedarbojas ar darbības jomām, vietējiem mainīgajiem, šo un super atslēgvārdus un Java izņēmumus.

Ņemiet vērā, ka šīs apmācības kodu piemēri ir saderīgi ar JDK 12.

Atklājiet veidus sev

Šajā apmācībā es neieviesīšu nevienu ar lambda nesaistītu funkciju, par kuru jūs iepriekš nebūtu mācījies, bet es demonstrēšu lambdas, izmantojot veidus, kurus iepriekš neesmu apspriedis šajā sērijā. Viens piemērs ir java.lang.Math klasē. Es iepazīstināšu ar šiem veidiem nākamajās Java 101 apmācībās. Pagaidām iesaku izlasīt JDK 12 API dokumentāciju, lai uzzinātu vairāk par tām.

lejupielādēt Iegūt kodu Lejupielādējiet šajā apmācībā avota kodu, piemēram, lietojumprogrammām. Izveidoja Jeff Friesen JavaWorld.

Lambdas: grunts

A lambda izteiksme (lambda) apraksta koda bloku (anonīmu funkciju), kuru var nodot konstruktoriem vai metodēm turpmākai izpildei. Konstruktors vai metode kā argumentu saņem lambda. Apsveriet šādu piemēru:

() -> System.out.println ("Sveiki")

Šis piemērs identificē lambda ziņojuma izvadīšanai standarta izvades straumē. No kreisās uz labo () identificē lambda formālo parametru sarakstu (piemērā nav parametru), -> norāda, ka izteiciens ir lambda, un System.out.println ("Labdien") ir izpildāmais kods.

Lambdas vienkāršo funkcionālās saskarnes, kas ir anotētas saskarnes, kuras katra deklarē tieši vienu abstraktu metodi (lai gan tās var deklarēt arī jebkuru noklusējuma, statisko un privāto metožu kombināciju). Piemēram, standarta klases bibliotēka nodrošina a java.lang. Skrienams saskarne ar vienu abstraktu anulēt palaist () metodi. Šīs funkcionālās saskarnes deklarācija ir parādīta zemāk:

@FunctionalInterface publiskā saskarne Runnable {public abstract void run (); }

Klases bibliotēka anotē Skrienams ar @ Funkcionālā saskarne, kas ir java.lang.FunctionalInterface anotācijas veids. Funkcionālā saskarne tiek izmantots, lai anotētu tās saskarnes, kuras jāizmanto lambda kontekstā.

Lambda nav noteikta saskarnes veida. Tā vietā kompilators izmanto apkārtējo kontekstu, lai secinātu, kuru funkcionālo interfeisu veikt, kad tiek norādīta lambda - lambda ir saistīts šai saskarnei. Piemēram, pieņemsim, ka es norādīju šādu koda fragmentu, kas iepriekšējo lambda nodod kā argumentu java.lang.Thread klases Vītne (skrienams mērķis) konstruktors:

jauns pavediens (() -> System.out.println ("Labdien"));

Sastādītājs nosaka, ka lambda tiek nodota Vītne (Runnable r) jo tas ir vienīgais konstruktors, kas apmierina lambda: Skrienams ir funkcionāls interfeiss, lambda tukšais formālo parametru saraksts () sērkociņi palaist ()tukšo parametru saraksts un atgriešanās veidi (spēkā neesošs) arī piekrītu. Lambda ir saistīta ar Skrienams.

1. sarakstā tiek parādīts avota kods nelielai lietojumprogrammai, kas ļauj jums spēlēt ar šo piemēru.

Saraksts 1. LambdaDemo.java (1. versija)

public class LambdaDemo {public static void main (String [] args) {new Thread (() -> System.out.println ("Labdien")). start (); }}

Sastādīt 1. sarakstu (javac LambdaDemo.java) un palaidiet lietojumprogrammu (java LambdaDemo). Jums jāievēro šāda izeja:

Sveiki

Lambdas var ievērojami vienkāršot avota koda daudzumu, kas jums jāraksta, kā arī padarīt koda daudz vieglāk saprotamu. Piemēram, bez lambdas jūs, iespējams, norādīsit 2. saraksta precīzāku kodu, kura pamatā ir anonīmas klases eksemplārs, kas ievieš Skrienams.

Saraksts 2. LambdaDemo.java (2. versija)

public class LambdaDemo {public static void main (String [] args) {Runnable r = new Runnable () {@Override public void run () {System.out.println ("Sveiki"); }}; jauns pavediens (r) .start (); }}

Pēc šī avota koda sastādīšanas palaidiet lietojumprogrammu. Jūs atradīsit to pašu izvadi, kas parādīts iepriekš.

Lambdas un Stream API

Papildus avota koda vienkāršošanai, lambdas spēlē nozīmīgu lomu Java funkcionāli orientētajā Streams API. Tie apraksta funkcionalitātes vienības, kas tiek nodotas dažādām API metodēm.

Java lambdas padziļināti

Lai efektīvi izmantotu lambdas, jums ir jāsaprot lambda izteicienu sintakse kopā ar mērķa veida jēdzienu. Jums arī jāsaprot, kā lambdas mijiedarbojas ar darbības jomām, vietējiem mainīgajiem, šo un super atslēgvārdi un izņēmumi. Es apskatīšu visas šīs tēmas turpmākajās sadaļās.

Kā tiek īstenotas lambdas

Lambdas tiek ieviestas Java virtuālās mašīnas ziņā izsauktsdinamiski instrukcijas un java.lang.invoke API. Noskatieties video Lambda: palūrēt zem pārsega, lai uzzinātu par lambda arhitektūru.

Lambda sintakse

Katra lambda atbilst šādai sintaksei:

( formālo parametru saraksts ) -> { izteiksme vai paziņojumi }

The formālo parametru saraksts ir komatu atdalīts formālo parametru saraksts, kam izpildes laikā jāatbilst funkcionālās saskarnes vienas abstraktās metodes parametriem. Ja jūs izlaižat to veidus, sastādītājs secina šos veidus no konteksta, kurā tiek izmantota lambda. Apsveriet šādus piemērus:

(dubultā a, dubultā b) // skaidri norādītie tipi (a, b) // kompilatora secinātie tipi

Lambdas un var

Sākot ar Java SE 11, tipa nosaukumu var aizstāt ar var. Piemēram, jūs varētu norādīt (var a, var b).

Jums ir jānorāda iekavas vairākiem formāliem parametriem vai bez tiem. Norādot vienu formālu parametru, iekavas var izlaist (lai gan tas nav jādara). (Tas attiecas tikai uz parametra nosaukumu - iekavas ir nepieciešamas, ja ir norādīts arī tips.) Apsveriet šādus papildu piemērus:

x // iekavas ir izlaistas viena formāla parametra dēļ (dubultā x) // ir nepieciešamas iekavas, jo ir arī tips () // iekavas ir nepieciešamas, ja nav formālu parametru (x, y) // iekavas ir nepieciešamas vairāku formālu parametru dēļ

The formālo parametru saraksts seko a -> žetons, kam seko izteiksme vai paziņojumi- izteiksme vai izteikumu bloks (vai nu ir pazīstams kā lambda ķermenis). Atšķirībā no izteiksmēm balstītiem ķermeņiem uz paziņojumiem balstīti ķermeņi jānovieto starp atvērtajiem{) un aizveriet (}) figūriekavas:

(dubultais rādiuss) -> Math.PI * rādiuss * rādiusa rādiuss -> {return Math.PI * rādiuss * rādiuss; } rādiuss -> {System.out.println (rādiuss); atgriezties Math.PI * rādiuss * rādiuss; }

Pirmā piemēra izteiksmē balstītais lambda korpuss nav jānovieto starp lencēm. Otrais piemērs pārveido uz izteiksmi balstītu ķermeni uz paziņojumiem balstītu ķermeni, kurā atgriešanās jānorāda, lai atgrieztu izteiksmes vērtību. Pēdējais piemērs parāda vairākus apgalvojumus, un to nevar izteikt bez lencēm.

Lambda ķermeņi un semikoli

Ievērojiet semikolu neesamību vai klātbūtni (;) iepriekšējos piemēros. Katrā gadījumā lambda ķermenis nav izbeigts ar semikolu, jo lambda nav paziņojums. Tomēr uz apgalvojumiem balstītā lambda korpusā katrs apgalvojums ir jābeidz ar semikolu.

3. saraksts parāda vienkāršu lietojumprogrammu, kas parāda lambda sintaksi; ņemiet vērā, ka šis saraksts balstās uz diviem iepriekšējiem kodu piemēriem.

Saraksts 3. LambdaDemo.java (3. versija)

@FunctionalInterface interfeiss BinaryCalculator {divreiz aprēķināt (dubultā vērtība1, dubultā vērtība2); } @FunctionalInterface interfeiss UnaryCalculator {divreiz aprēķināt (dubultā vērtība); } public class LambdaDemo {public static void main (String [] args) {System.out.printf ("18 + 36,5 =% f% n", aprēķiniet ((double v1, double v2) -> v1 + v2, 18, 36.5)); System.out.printf ("89 / 2,9 =% f% n", aprēķiniet ((v1, v2) -> v1 / v2, 89, 2,9)); System.out.printf ("- 89 =% f% n", aprēķiniet (v -> -v, 89)); System.out.printf ("18 * 18 =% f% n", aprēķiniet ((double v) -> v * v, 18)); } statisks dubultrēķins (BinaryCalculator calc, double v1, double v2) {return calc.calculate (v1, v2); } statisks dubultrēķins (UnaryCalculator calc, double v) {return calc.calculate (v); }}

3. uzskaitījums vispirms ievieš Binārais kalkulators un UnaryCalculator funkcionālās saskarnes, kuru aprēķināt () metodes aprēķina attiecīgi divus ievades argumentus vai vienu ievades argumentu. Šis saraksts arī ievieš a LambdaDemo klase, kuras galvenais () metode demonstrē šīs funkcionālās saskarnes.

Funkcionālās saskarnes ir parādītas statisks dubultrēķins (BinaryCalculator calc, double v1, double v2) un statisks dubultrēķins (UnaryCalculator calc, double v) metodes. Lambdas nodod kodu kā datus šīm metodēm, kuras saņem kā Binārais kalkulators vai UnaryCalculator gadījumi.

Sastādiet 3. sarakstu un palaidiet lietojumprogrammu. Jums jāievēro šāda izeja:

18 + 36.5 = 54.500000 89 / 2.9 = 30.689655 -89 = -89.000000 18 * 18 = 324.000000

Mērķa veidi

Lambda ir saistīta ar netiešu mērķa tips, kas identificē objekta tipu, kuram ir piesaistīta lambda. Mērķa tipam ir jābūt funkcionālam interfeisam, kas izsecināts no konteksta, kas ierobežo lambdas parādīšanos šādos kontekstos:

  • Mainīga deklarācija
  • Uzdevums
  • Atgriešanās paziņojums
  • Masīva inicializētājs
  • Metodes vai konstruktora argumenti
  • Lambda korpuss
  • Trīskāršā nosacītā izteiksme
  • Aktieru izteiksme

4. saraksts parāda lietojumprogrammu, kas parāda šos mērķa veida kontekstus.

4. saraksts: LambdaDemo.java (4. versija)

importēt java.io.File; importēt java.io.FileFilter; importēt java.nio.file.Files; importēt java.nio.file.FileSystem; importēt java.nio.file.FileSystems; importēt java.nio.file.FileVisitor; importēt java.nio.file.FileVisitResult; importēt java.nio.file.Path; importēt java.nio.file.PathMatcher; importēt java.nio.file.Paths; importēt java.nio.file.SimpleFileVisitor; importēt java.nio.file.attribute.BasicFileAttributes; importēt java.security.AccessController; importēt java.security.PrivilegedAction; importēt java.util.Arrays; importēt java.util.Collections; importēt java.util.Comparator; importēt java.util.List; importēt java.util.concurrent.Callable; public class LambdaDemo {public static void main (String [] args) throws Exception {// Mērķa tips # 1: mainīgā deklarācija Runnable r = () -> {System.out.println ("darbojas"); }; r.run (); // Mērķa tips # 2: piešķiršana r = () -> System.out.println ("darbojas"); r.run (); // Mērķa tips # 3: atgriešanās paziņojums (getFilter () failā [] faili = jauns fails ("."). ListFiles (getFilter ("txt")); for (int i = 0; i path.toString (). beidzas ar ("txt"), (ceļš) -> path.toString (). beidzas ar ("java")}; FileVisitor apmeklētājs; apmeklētājs = jauns SimpleFileVisitor () { @Orride public FileVisitResult visitFile (Ceļa fails, BasicFileAttributes atribūti) {Ceļa nosaukums = file.getFileName (); for (int i = 0; i System.out.println ("darbojas")). Start (); // Mērķa tips # 6: lambda ķermenis (ligzdota lambda) Zvanāms, izsaucams = () -> () -> System.out.println ("izsaukts"); callable.call (). Run (); // 7. mērķa tips: trīskāršais nosacītā izteiksme Būla augošā secība = nepareiza; Salīdzinātājs cmp; cmp = (ascendingSort)? (s1, s2) -> s1.compareTo (s2): (s1, s2) -> s2.compareTo (s1); Sarakstiet pilsētas = Arrays.asList ("Vašingtona", "Londona", "Roma", "Berlīne", "Jeruzaleme", "Otava", "Sidneja", "Maskava"); Collections.sort (pilsētas, cmp); for (int i = 0; es ("lietotājvārds ")); System.out.println (lietotājs); } static FileFilter getFilter (String ext) {return (pathname) -> pathname.toString (). endWith (ext); }}
$config[zx-auto] not found$config[zx-overlay] not found