JavaRush /Blog Jawa /Random-JV /Antarmuka Fungsional ing Jawa

Antarmuka Fungsional ing Jawa

Diterbitake ing grup
Hello! Ing quest Java Syntax Pro, kita sinau ekspresi lambda lan ujar manawa ora luwih saka implementasine metode fungsional saka antarmuka fungsional. Ing tembung liya, iki minangka implementasi saka sawetara kelas anonim (ora dingerteni), cara sing ora bisa diwujudake. Lan yen ing kuliah kursus kita nyelidiki manipulasi karo ekspresi lambda, saiki kita bakal nimbang, supaya bisa ngomong, sisih liya: yaiku, antarmuka kasebut. Antarmuka Fungsional ing Jawa - 1Versi Jawa kaping wolu ngenalake konsep antarmuka fungsional . Apa iki? Antarmuka kanthi siji cara sing ora diimplementasikake (abstrak) dianggep fungsional. Akeh antarmuka out-of-the-box kalebu ing definisi iki, kayata, contone, antarmuka sing wis dibahas sadurunge Comparator. Lan uga antarmuka sing digawe dhewe, kayata:

@FunctionalInterface
public interface Converter<T, N> {
   N convert(T t);
}
Kita duwe antarmuka sing tugas kanggo ngowahi obyek saka siji jinis menyang obyek liyane (jinis adaptor). Anotasi kasebut @FunctionalInterfacedudu perkara sing rumit utawa penting, amarga tujuane kanggo ngandhani kompiler manawa antarmuka iki fungsional lan ora ngemot luwih saka siji metode. Yen antarmuka karo anotasi iki nduweni luwih saka siji cara (abstrak) sing ora dileksanakake, kompiler ora bakal ngliwati antarmuka iki, amarga bakal dianggep minangka kode sing salah. Antarmuka tanpa anotasi iki bisa dianggep fungsional lan bakal bisa digunakake, nanging @FunctionalInterfaceiki ora luwih saka asuransi tambahan. Ayo bali menyang kelas Comparator. Yen sampeyan ndeleng kode (utawa dokumentasi ), sampeyan bisa ndeleng manawa ana luwih saka siji cara. Banjur sampeyan takon: kepiye carane bisa dianggep minangka antarmuka fungsional? Antarmuka abstrak bisa duwe metode sing ora ana ing ruang lingkup metode siji:
  • statis
Konsep antarmuka nuduhake yen unit kode sing diwenehake ora bisa ngetrapake metode apa wae. Nanging wiwit karo Java 8, dadi bisa nggunakake cara statis lan standar ing antarmuka. Cara statis diikat langsung menyang kelas lan ora mbutuhake obyek tartamtu saka kelas kasebut kanggo nelpon metode kasebut. Tegese, metode kasebut cocog karo konsep antarmuka. Minangka conto, ayo nambah cara statis kanggo mriksa obyek kanggo null menyang kelas sadurunge:

@FunctionalInterface
public interface Converter<T, N> {
 
   N convert(T t);
 
   static <T> boolean isNotNull(T t){
       return t != null;
   }
}
Sawise nampa metode iki, kompiler ora sambat, tegese antarmuka kita isih bisa digunakake.
  • cara gawan
Sadurunge Java 8, yen kita kudu nggawe cara ing antarmuka sing diwarisake dening kelas liyane, kita mung bisa nggawe cara abstrak sing dileksanakake ing saben kelas tartamtu. Nanging apa yen cara iki padha kanggo kabeh kelas? Ing kasus iki , kelas abstrak paling asring digunakake . Nanging wiwit karo Java 8, ana pilihan kanggo nggunakake antarmuka karo cara dileksanakake - cara standar. Nalika marisi antarmuka, sampeyan bisa ngilangi cara kasebut utawa ninggalake kabeh kaya apa wae (ninggalake logika standar). Nalika nggawe metode standar, kita kudu nambah tembung kunci - default:

@FunctionalInterface
public interface Converter<T, N> {
 
   N convert(T t);
 
   static <T> boolean isNotNull(T t){
       return t != null;
   }
 
   default void writeToConsole(T t) {
       System.out.println("Текущий an object - " + t.toString());
   }
}
Maneh, kita waca sing compiler ora miwiti sambat, lan kita ora ngluwihi watesan saka antarmuka fungsi.
  • Metode kelas obyek
Ing kuliah Comparing Objects , kita ngomong babagan kasunyatan sing kabeh kelas warisan saka kelas Object. Iki ora ditrapake kanggo antarmuka. Nanging yen kita duwe metode abstrak ing antarmuka sing cocog karo teken karo sawetara metode kelas Object, metode kasebut (utawa metode) ora bakal ngilangi watesan antarmuka fungsional:

@FunctionalInterface
public interface Converter<T, N> {
 
   N convert(T t);
 
   static <T> boolean isNotNull(T t){
       return t != null;
   }
 
   default void writeToConsole(T t) {
       System.out.println("Текущий an object - " + t.toString());
   }
 
   boolean equals(Object obj);
}
Lan maneh, kompiler kita ora sambat, mula antarmuka Converterisih dianggep fungsional. Saiki pitakonan yaiku: kenapa kita kudu mbatesi awake dhewe menyang siji cara sing ora ditindakake ing antarmuka fungsional? Banjur supaya kita bisa ngleksanakake nggunakake lambdas. Ayo ndeleng iki kanthi conto Converter. Kanggo nindakake iki, ayo nggawe kelas Dog:

public class Dog {
  String name;
  int age;
  int weight;
 
  public Dog(final String name, final int age, final int weight) {
     this.name = name;
     this.age = age;
     this.weight = weight;
  }
}
Lan sing padha Raccoon(rakun):

public class Raccoon {
  String name;
  int age;
  int weight;
 
  public Raccoon(final String name, final int age, final int weight) {
     this.name = name;
     this.age = age;
     this.weight = weight;
  }
}
Upaminipun kita duwe obyek Dog, lan kita kudu nggawe obyek adhedhasar sawijining kothak Raccoon. Yaiku, Converterngowahi obyek saka siji jinis menyang liyane. Carane bakal katon kaya:

public static void main(String[] args) {
  Dog dog = new Dog("Bobbie", 5, 3);
 
  Converter<Dog, Raccoon> converter = x -> new Raccoon(x.name, x.age, x.weight);
 
  Raccoon raccoon = converter.convert(dog);
 
  System.out.println("Raccoon has parameters: name - " + raccoon.name + ", age - " + raccoon.age + ", weight - " + raccoon.weight);
}
Nalika kita mbukak, kita entuk output ing ngisor iki menyang konsol:

Raccoon has parameters: name - Bobbbie, age - 5, weight - 3
Lan iki tegese cara kita bisa digunakake kanthi bener.Antarmuka Fungsional ing Jawa - 2

Dhasar Java 8 Antarmuka Fungsional

Saiki ayo goleki sawetara antarmuka fungsional sing diwenehake Java 8 lan digunakake kanthi aktif bebarengan karo Stream API.

predikat

Predicate- antarmuka fungsional kanggo mriksa apa kondisi tartamtu wis ketemu. Yen kondisi wis ketemu, bali true, yen ora - false:

@FunctionalInterface
public interface Predicate<T> {
   boolean test(T t);
}
Minangka conto, nimbang nggawe Predicatesing bakal mriksa paritas saka sawetara jinis Integer:

public static void main(String[] args) {
   Predicate<Integer> isEvenNumber = x -> x % 2==0;
 
   System.out.println(isEvenNumber.test(4));
   System.out.println(isEvenNumber.test(3));
}
Output konsol:

true
false

Konsumen

Consumer(saka basa Inggris - "konsumen") - antarmuka fungsional sing njupuk obyek saka jinis T minangka argumen input, nindakake sawetara tumindak, nanging ora ngasilake apa-apa:

@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
}
Minangka conto, nimbang , sing tugase kanggo ngasilake salam menyang konsol kanthi argumen string sing dilewati: Consumer

public static void main(String[] args) {
   Consumer<String> greetings = x -> System.out.println("Hello " + x + " !!!");
   greetings.accept("Elena");
}
Output konsol:

Hello Elena !!!

Supplier

Supplier(saka Inggris - panyedhiya) - antarmuka fungsional sing ora njupuk bantahan, nanging ngasilake obyek saka jinis T:

@FunctionalInterface
public interface Supplier<T> {
   T get();
}
Minangka conto, nimbang Supplier, sing bakal ngasilake jeneng acak saka dhaptar:

public static void main(String[] args) {
   ArrayList<String> nameList = new ArrayList<>();
   nameList .add("Elena");
   nameList .add("John");
   nameList .add("Alex");
   nameList .add("Jim");
   nameList .add("Sara");
 
   Supplier<String> randomName = () -> {
       int value = (int)(Math.random() * nameList.size());
       return nameList.get(value);
   };
 
   System.out.println(randomName.get());
}
Lan yen kita mbukak iki, kita bakal weruh asil acak saka dhaptar jeneng ing console.

Fungsi

Function- antarmuka fungsional iki njupuk argumen T lan ngirim menyang obyek saka jinis R, sing bali minangka asil:

@FunctionalInterface
public interface Function<T, R> {
   R apply(T t);
}
Minangka conto, ayo njupuk , sing ngowahi angka saka format string ( ) dadi format angka ( ): FunctionStringInteger

public static void main(String[] args) {
   Function<String, Integer> valueConverter = x -> Integer.valueOf(x);
   System.out.println(valueConverter.apply("678"));
}
Nalika kita mbukak, kita entuk output ing ngisor iki menyang konsol:

678
PS: yen kita pass ora mung nomer, nanging uga karakter liyane menyang senar, pangecualian bakal di buwang - NumberFormatException.

UnaryOperator

UnaryOperator- antarmuka fungsional sing njupuk obyek saka jinis T minangka parameter, nindakake sawetara operasi lan ngasilake asil operasi ing wangun obyek saka jinis padha T:

@FunctionalInterface
public interface UnaryOperator<T> {
   T apply(T t);
}
UnaryOperator, sing nggunakake cara applykanggo kuadrat nomer:

public static void main(String[] args) {
   UnaryOperator<Integer> squareValue = x -> x * x;
   System.out.println(squareValue.apply(9));
}
Output konsol:

81
Kita nyawang limang antarmuka fungsional. Iki ora kabeh sing kasedhiya kanggo kita wiwit karo Java 8 - iki antarmuka utama. Liyane sing kasedhiya yaiku analog sing rumit. Dhaptar lengkap bisa ditemokake ing dokumentasi Oracle resmi .

Antarmuka fungsional ing Stream

Kaya sing wis dibahas ing ndhuwur, antarmuka fungsional iki digandhengake karo Stream API. Carane, sampeyan takon? Antarmuka Fungsional ing Jawa - 3Lan akeh cara sing Streambisa digunakake kanthi khusus karo antarmuka fungsional kasebut. Ayo goleki carane antarmuka fungsional bisa digunakake ing Stream.

Metode karo Predikat

Contone, ayo njupuk metode kelas Stream- filtersing njupuk minangka argumentasi Predicatelan Streammung ngasilake unsur-unsur sing nyukupi kondisi kasebut Predicate. Ing konteks Stream-a, iki tegese mung liwat unsur-unsur sing bali truenalika digunakake ing cara testantarmuka Predicate. Iki minangka conto kita Predicate, nanging kanggo panyaring unsur ing Stream:

public static void main(String[] args) {
   List<Integer> evenNumbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8)
           .filter(x -> x % 2==0)
           .collect(Collectors.toList());
}
Akibaté, dhaptar evenNumbersbakal kalebu unsur {2, 4, 6, 8}. Lan, kaya sing kita eling, collectbakal nglumpukake kabeh unsur menyang koleksi tartamtu: ing kasus kita, menyang List.

Metode karo Konsumen

Salah sawijining cara ing Stream, sing nggunakake antarmuka fungsional Consumer, yaiku peek. Iki minangka conto kita Consumerbakal katon kaya Stream:

public static void main(String[] args) {
   List<String> peopleGreetings = Stream.of("Elena", "John", "Alex", "Jim", "Sara")
           .peek(x -> System.out.println("Hello " + x + " !!!"))
           .collect(Collectors.toList());
}
Output konsol:

Hello Elena !!!
Hello John !!!
Hello Alex !!!
Hello Jim !!!
Hello Sara !!!
Nanging wiwit cara peekdianggo karo Consumer, modifikasi saka strings ing Streamora bakal kelakon, nanging peekbakal bali Streamkaro unsur asli: padha teka menyang. Mulane, dhaptar peopleGreetingsbakal kalebu unsur "Elena", "John", "Alex", "Jim", "Sara". Ana uga cara sing umum digunakake foreach, sing padha karo metode kasebut peek, nanging bedane yaiku final - terminal.

Cara karo Supplier

Conto cara sing Streamnggunakake antarmuka fungsional Supplieryaiku generate, sing ngasilake urutan tanpa wates adhedhasar antarmuka fungsional sing diterusake. Ayo nggunakake conto kita Supplierkanggo nyithak limang jeneng acak menyang console:

public static void main(String[] args) {
   ArrayList<String> nameList = new ArrayList<>();
   nameList.add("Elena");
   nameList.add("John");
   nameList.add("Alex");
   nameList.add("Jim");
   nameList.add("Sara");

   Stream.generate(() -> {
       int value = (int) (Math.random() * nameList.size());
       return nameList.get(value);
   }).limit(5).forEach(System.out::println);
}
Lan iki minangka output sing kita entuk ing konsol:

John
Elena
Elena
Elena
Jim
Kene kita nggunakake cara limit(5)kanggo nyetel watesan ing cara generate, yen program bakal print jeneng acak kanggo console moho.

Metode kanthi Fungsi

Conto khas saka metode kanthi Streamargumentasi Functionyaiku metode mapsing njupuk unsur saka siji jinis, nindakake apa wae karo dheweke lan diterusake, nanging iki bisa dadi unsur saka jinis sing beda. Apa conto karo Functionin bisa katon kaya Stream:

public static void main(String[] args) {
   List<Integer> values = Stream.of("32", "43", "74", "54", "3")
           .map(x -> Integer.valueOf(x)).collect(Collectors.toList());
}
Akibaté, kita njaluk dhaptar nomer, nanging ing Integer.

Metode karo UnaryOperator

Minangka metode sing digunakake UnaryOperatorminangka argumen, ayo njupuk metode kelas Stream- iterate. Cara iki padha karo cara generate: uga ngasilake urutan tanpa wates nanging nduweni rong argumen:
  • pisanan unsur saka kang generasi urutan wiwit;
  • kaloro iku UnaryOperator, kang nuduhake prinsip ngasilaken unsur anyar saka unsur pisanan.
Iki bakal katon kaya conto kita UnaryOperator, nanging ing cara iterate:

public static void main(String[] args) {
   Stream.iterate(9, x -> x * x)
           .limit(4)
           .forEach(System.out::println);
}
Nalika kita mbukak, kita entuk output ing ngisor iki menyang konsol:

9
81
6561
43046721
Sing, saben unsur kita pingan dhewe, lan kanggo papat nomer pisanan. Antarmuka Fungsional ing Jawa - 4Iku kabeh! Iku bakal apik yen sawise maca artikel iki sampeyan wis selangkah luwih cedhak kanggo mangerteni lan nguwasani Stream API ing Jawa!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION