JavaRush /Блоги Java /Random-TG /Интерфейсҳои функсионалӣ дар Java

Интерфейсҳои функсионалӣ дар Java

Дар гурӯҳ нашр шудааст
Салом! Дар ҷустуҷӯи Java Syntax Pro, мо ифодаҳои лямбдаро омӯхтем ва гуфтем, ки онҳо ҷуз татбиқи усули функсионалӣ аз интерфейси функсионалӣ чизе нестанд. Ба ибораи дигар, ин амалисозии баъзе синфҳои беном (номаълум), усули амалӣнашудаи он аст. Ва агар дар лексияҳои курс мо ба манипуляцияҳо бо ифодаҳои лямбда машғул бошем, ҳоло мо, ба ибораи дигар, тарафи дигарро баррасӣ хоҳем кард: маҳз ҳамин интерфейсҳо. Интерфейсҳои функсионалӣ дар Java - 1Варианти ҳаштуми Java консепсияи интерфейсҳои функсионалии онро муаррифӣ кард . Ин чи аст? Интерфейси як усули иҷронашуда (абстрактӣ) функсионалӣ ҳисобида мешавад. Бисёр интерфейсҳои берун аз қуттӣ ба ин таъриф дохил мешаванд, масалан, интерфейси қаблан баррасӣшуда Comparator. Ва инчунин интерфейсҳое, ки мо худамон эҷод мекунем, ба монанди:
@FunctionalInterface
public interface Converter<T, N> {
   N convert(T t);
}
Мо интерфейс дорем, ки вазифаи он табдил додани an objectҳои як намуд ба an objectҳои дигар (як намуди адаптер) мебошад. Эзоҳ @FunctionalInterfaceчизи хеле мураккаб ё муҳим нест, зеро ҳадафи он ба компилятор гуфтан аст, ки ин интерфейс функсионалӣ аст ва набояд бештар аз як усулро дар бар гирад. Агар интерфейс бо ин эзоҳ зиёда аз як усули иҷронашуда (абстрактӣ) дошта бошад, компилятор ин интерфейсро намегузаронад, зеро онро ҳамчун рамзи хато қабул мекунад. Интерфейсҳоро бидуни ин эзоҳ метавон функсионалӣ ҳисоб кард ва кор хоҳад кард, аммо @FunctionalInterfaceин ҷуз суғуртаи иловагӣ чизе нест. Биёед ба синф баргардем Comparator. Агар шумо ба рамзи он (ё ҳуҷҷатҳои ) нигаред, шумо мебинед, ки он зиёда аз як усул дорад. Пас шумо мепурсед: пас чӣ гуна онро интерфейси функсионалӣ ҳисобидан мумкин аст? Интерфейсҳои абстрактӣ метавонанд усулҳое дошта бошанд, ки дар доираи як усули ягона нестанд:
  • статикӣ
Мафҳуми интерфейсҳо маънои онро дорад, ки воҳиди codeи додашуда наметавонад ягон усули амалӣ дошта бошад. Аммо аз Java 8 сар карда, дар интерфейсҳо истифода бурдани усулҳои статикӣ ва пешфарз имконпазир гардид. Усулҳои статикӣ мустақиман ба синф вобастаанд ва an objectи мушаххаси он синфро талаб намекунанд, ки чунин методро даъват кунанд. Яъне, ин усулҳо ба консепсияи интерфейсҳо мувофиқат мекунанд. Ба сифати мисол, биёед усули статикиро барои санҷиши an object барои нул ба синфи қаблӣ илова кунем:
@FunctionalInterface
public interface Converter<T, N> {

   N convert(T t);

   static <T> boolean isNotNull(T t){
       return t != null;
   }
}
Пас аз гирифтани ин усул, компилятор шикоят накард, яъне интерфейси мо то ҳол фаъол аст.
  • усулҳои пешфарз
Пеш аз Java 8, агар ба мо лозим буд, ки методеро дар интерфейсе, ки аз синфҳои дигар мерос гирифта буд, эҷод кунем, мо метавонем танҳо як усули абстрактӣ эҷод кунем, ки дар ҳар як синфи мушаххас амалӣ карда мешавад. Аммо чӣ мешавад, агар ин усул барои ҳама синфҳо якхела бошад? Дар ин маврид бештар дарсҳои абстрактӣ истифода мешуданд . Аммо аз Java 8 сар карда, имкони истифодаи интерфейсҳо бо усулҳои амалӣ мавҷуд аст - усулҳои пешфарз. Ҳангоми мерос гирифтани интерфейс, шумо метавонед ин усулҳоро бекор кунед ё ҳама чизро тавре ки ҳаст, тарк кунед (мантиқи пешфарзро тарк кунед). Ҳангоми сохтани усули пешфарз, мо бояд калимаи калидиро илова кунем - 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());
   }
}
Боз мебинем, ки компилятор ба шикоят оғоз накардааст ва мо аз маҳдудиятҳои интерфейси функсионалӣ берун нарафтем.
  • Усулҳои синфи an object
Дар лексияи «Муқоисаи an objectҳо» мо дар бораи он сӯҳбат кардем, ки ҳама синфҳо аз синф мерос мегиранд Object. Ин ба интерфейсҳо дахл надорад. Аммо агар мо дар интерфейс усули абстрактӣ дошта бошем, ки ба имзо бо ягон усули синф мувофиқат кунад Object, чунин усул (ё усулҳо) маҳдудияти функсионалии интерфейси моро вайрон намекунад:
@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);
}
Ва боз, компилятори мо шикоят намекунад, бинобар ин интерфейс Converterто ҳол функсионалӣ ҳисобида мешавад. Ҳоло савол ин аст: чаро мо бояд худро бо як усули иҷронашуда дар интерфейси функсионалӣ маҳдуд кунем? Ва он гоҳ, ки мо метавонем онро бо истифода аз ламбдаҳо амалӣ кунем. Биёед инро бо як мисол дида бароем Converter. Барои ин, биёед як синф эҷод кунем 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;
  }
}
Ва монанди ин Raccoon(ракун):
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;
  }
}
Фарз мекунем, ки мо an object дорем Dogва мо бояд дар асоси майдонҳои он an object созем Raccoon. Яъне Converteran objectи як намудро ба намуди дигар табдил медиҳад. Он чӣ гуна хоҳад буд:
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);
}
Вақте ки мо онро иҷро мекунем, мо баромади зеринро ба консол мегирем:

Raccoon has parameters: name - Bobbbie, age - 5, weight - 3
Ва ин маънои онро дорад, ки усули мо дуруст кор кардааст.Интерфейсҳои функсионалӣ дар Java - 2

Интерфейсҳои функсионалии асосии Java 8

Хуб, ҳоло биёед ба якчанд интерфейсҳои функсионалӣ, ки Java 8 ба мо овард ва дар якҷоягӣ бо Stream API фаъолона истифода мешаванд, бубинем.

Предикат

Predicate— интерфейси функсионалӣ барои тафтиши иҷро шудани шарти муайян. Агар шарт иҷро шавад, бар мегардонад true, дар акси ҳол - false:
@FunctionalInterface
public interface Predicate<T> {
   boolean test(T t);
}
Ҳамчун мисол, эҷоди якеро дида бароед Predicate, ки паритети як қатор намудҳоро тафтиш мекунад 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));
}
Натиҷаи консол:

true
false

Истеъмолкунанда

Consumer(аз инглисӣ - "истеъмолкунанда") - интерфейси функсионалӣ, ки an objectи навъи T-ро ҳамчун далели вурудӣ қабул мекунад, баъзе амалҳоро иҷро мекунад, аммо ҳеҷ чиз барнамегардонад:
@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
}
Ҳамчун мисол, баррасӣ кунед , ки вазифаи он баровардани салом ба консол бо аргументи сатри гузашта аст: Consumer
public static void main(String[] args) {
   Consumer<String> greetings = x -> System.out.println("Hello " + x + " !!!");
   greetings.accept("Elena");
}
Натиҷаи консол:

Hello Elena !!!

Таъминкунанда

Supplier(аз инглисӣ - провайдер) - интерфейси функсионалӣ, ки ягон аргумент намегирад, аммо an objectи навъи T -ро бармегардонад:
@FunctionalInterface
public interface Supplier<T> {
   T get();
}
Ҳамчун мисол, баррасӣ кунед Supplier, ки номҳои тасодуфиро аз рӯйхат тавлид мекунад:
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());
}
Ва агар мо инро иҷро кунем, мо натиҷаҳои тасодуфиро аз рӯйхати номҳо дар консол мебинем.

Функсия

Function— ин интерфейси функсионалӣ аргументи T-ро мегирад ва онро ба an objectи навъи R мефиристад, ки дар натиҷа баргардонида мешавад:
@FunctionalInterface
public interface Function<T, R> {
   R apply(T t);
}
Мисол, биёед гирем , ки рақамҳоро аз формати сатр ( ) ба формати рақамӣ ( ) табдил медиҳад: FunctionStringInteger
public static void main(String[] args) {
   Function<String, Integer> valueConverter = x -> Integer.valueOf(x);
   System.out.println(valueConverter.apply("678"));
}
Вақте ки мо онро иҷро мекунем, мо баромади зеринро ба консол мегирем:

678
PS: агар мо на танҳо рақамҳо, балки дигар аломатҳоро низ ба сатр гузаронем, истисно партофта мешавад - NumberFormatException.

UnaryOperator

UnaryOperator— интерфейси функсионалӣ, ки an objectи навъи Т-ро ҳамчун параметр қабул карда, дар он баъзе амалҳоро иҷро мекунад ва натиҷаи амалҳоро дар шакли an objectи як навъи T бармегардонад:
@FunctionalInterface
public interface UnaryOperator<T> {
   T apply(T t);
}
UnaryOperator, ки усули худро applyбарои квадрат кардани адад истифода мебарад:
public static void main(String[] args) {
   UnaryOperator<Integer> squareValue = x -> x * x;
   System.out.println(squareValue.apply(9));
}
Натиҷаи консол:

81
Мо панҷ интерфейси функсионалии онро дида баромадем. Ин на ҳама чизест, ки барои мо аз Java 8 сар карда дастрас аст - ин интерфейсҳои асосӣ мебошанд. Боқимондаи дастрас аналогҳои мураккаби онҳо мебошанд. Рӯйхати пурраро дар ҳуҷҷатҳои расмии Oracle пайдо кардан мумкин аст .

Интерфейсҳои функсионалӣ дар Stream

Тавре ки дар боло баррасӣ шуд, ин интерфейсҳои функсионалӣ бо Stream API зич алоқаманданд. Чӣ тавр, шумо мепурсед? Интерфейсҳои функсионалӣ дар Java - 3Ва чунон ки бисёр усулҳо Streamмахсусан бо ин интерфейсҳои функсионалӣ кор мекунанд. Биёед бубинем, ки чӣ тавр интерфейсҳои функсионалӣ дар Stream.

Усул бо Predicate

Масалан, биёед усули синфро гирем Stream- filterон ҳамчун далел қабул карда Predicate, танҳо он унсурҳоеро бармегардонад Stream, ки шартро қонеъ мекунанд Predicate. Дар контексти Stream-a, ин маънои онро дорад, ки он танҳо аз он унсурҳое мегузарад, ки trueҳангоми истифода дар усули testинтерфейс баргардонида мешаванд Predicate. Ин аст он чизе ки мисоли мо барои Predicate, аммо барои филтри унсурҳо дар 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());
}
Дар натиҷа, рӯйхат evenNumbersаз унсурҳои {2, 4, 6, 8} иборат хоҳад буд. Ва, тавре ки мо дар хотир дорем, collectон ҳама унсурҳоро дар коллексияи муайян ҷамъ мекунад: дар ҳолати мо, ба List.

Усули бо истеъмолкунанда

Яке аз усулҳои дар Stream, ки интерфейси функсионалӣ истифода мебарад Consumer, ин аст peek. Ин аст он чизе ки намунаи мо дар Consumerон чунин хоҳад буд 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());
}
Натиҷаи консол:

Hello Elena !!!
Hello John !!!
Hello Alex !!!
Hello Jim !!!
Hello Sara !!!
Аммо азбаски ин усул peekбо . Аз ин рӯ, рӯйхат аз унсурҳои "Елена", "Ҷон", "Алекс", "Ҷим", "Сара" иборат хоҳад буд. Инчунин як усули маъмулан истифодашаванда вуҷуд дорад , ки ба усул монанд аст , аммо фарқият дар он аст, ки он ниҳоӣ аст - терминал.ConsumerStreampeekStreampeopleGreetingsforeachpeek

Усули бо таъминкунанда

Намунаи усуле Stream, ки дар он интерфейси функсионалӣ истифода мешавад , Supplierин аст generate, ки пайдарпайии беохирро дар асоси интерфейси функсионалии ба он интиқолёфта тавлид мекунад. Биёед мисоли худро Supplierбарои чопи панҷ номи тасодуфӣ ба консол истифода барем:
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);
}
Ва ин натиҷаест, ки мо дар консол мегирем:

John
Elena
Elena
Elena
Jim
Дар ин ҷо мо усулро limit(5)барои муқаррар кардани маҳдудият дар метод истифода кардем generate, вагарна барнома номҳои тасодуфиро ба консол ба таври номуайян чоп мекунад.

Усул бо функсия

Намунаи маъмулии усул бо Streamаргумент Functionусулест map, ки унсурҳои як намудро мегирад, бо онҳо коре мекунад ва ба онҳо интиқол медиҳад, аммо онҳо аллакай унсурҳои навъи дигар буда метавонанд. Намунае бо Functionдар чӣ гуна буда метавонад 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());
}
Дар натиҷа, мо рӯйхати рақамҳоро мегирем, аммо дар Integer.

Усул бо UnaryOperator

Ҳамчун усуле, ки UnaryOperatorҳамчун далел истифода мебарад, биёед усули синфро гирем Stream- iterate. Ин усул ба усул монанд аст generate: он инчунин пайдарпайии беохирро тавлид мекунад, аммо ду далел дорад:
  • якум унсурест, ки тавлиди пайдарпай аз он сар мешавад;
  • дуюм аст UnaryOperator, ки принсипи тавлиди элементҳои навро аз элементи якум нишон медиҳад.
Намунаи мо чунин хоҳад буд UnaryOperator, аммо дар усул iterate:
public static void main(String[] args) {
   Stream.iterate(9, x -> x * x)
           .limit(4)
           .forEach(System.out::println);
}
Вақте ки мо онро иҷро мекунем, мо баромади зеринро ба консол мегирем:

9
81
6561
43046721
Яъне, ҳар як элементи мо ба худ зарб карда мешавад ва ғайра барои чор рақами аввал. Интерфейсҳои функсионалӣ дар Java - 4Ҳамааш ҳамин! Хеле хуб мебуд, агар пас аз хондани ин мақола шумо як қадам ба фаҳмидан ва азхудкунии Stream API дар Java наздиктар шавед!
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION