Салом! Дар ҷустуҷӯи Java Syntax Pro, мо ифодаҳои лямбдаро омӯхтем ва гуфтем, ки онҳо ҷуз татбиқи усули функсионалӣ аз интерфейси функсионалӣ чизе нестанд. Ба ибораи дигар, ин амалисозии баъзе синфҳои беном (номаълум), усули амалӣнашудаи он аст. Ва агар дар лексияҳои курс мо ба манипуляцияҳо бо ифодаҳои лямбда машғул бошем, ҳоло мо, ба ибораи дигар, тарафи дигарро баррасӣ хоҳем кард: маҳз ҳамин интерфейсҳо. Варианти ҳаштуми Java консепсияи интерфейсҳои функсионалии онро муаррифӣ кард . Ин чи аст? Интерфейси як усули иҷронашуда (абстрактӣ) функсионалӣ ҳисобида мешавад. Бисёр интерфейсҳои берун аз қуттӣ ба ин таъриф дохил мешаванд, масалан, интерфейси қаблан баррасӣшуда Предикат
Истеъмолкунанда
Таъминкунанда
Функсия
UnaryOperator
Comparator
. Ва инчунин интерфейсҳое, ки мо худамон эҷод мекунем, ба монанди:
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
}
Мо интерфейс дорем, ки вазифаи он табдил додани an objectҳои як намуд ба an objectҳои дигар (як намуди адаптер) мебошад. Эзоҳ @FunctionalInterface
чизи хеле мураккаб ё муҳим нест, зеро ҳадафи он ба компилятор гуфтан аст, ки ин интерфейс функсионалӣ аст ва набояд бештар аз як усулро дар бар гирад. Агар интерфейс бо ин эзоҳ зиёда аз як усули иҷронашуда (абстрактӣ) дошта бошад, компилятор ин интерфейсро намегузаронад, зеро онро ҳамчун рамзи хато қабул мекунад. Интерфейсҳоро бидуни ин эзоҳ метавон функсионалӣ ҳисоб кард ва кор хоҳад кард, аммо @FunctionalInterface
ин ҷуз суғуртаи иловагӣ чизе нест. Биёед ба синф баргардем Comparator
. Агар шумо ба рамзи он (ё ҳуҷҷатҳои ) нигаред, шумо мебинед, ки он зиёда аз як усул дорад. Пас шумо мепурсед: пас чӣ гуна онро интерфейси функсионалӣ ҳисобидан мумкин аст? Интерфейсҳои абстрактӣ метавонанд усулҳое дошта бошанд, ки дар доираи як усули ягона нестанд:
- статикӣ
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
static <T> boolean isNotNull(T t){
return t != null;
}
}
Пас аз гирифтани ин усул, компилятор шикоят накард, яъне интерфейси мо то ҳол фаъол аст.
- усулҳои пешфарз
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
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
. Яъне Converter
an 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 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);
}
Мисол, биёед гирем , ки рақамҳоро аз формати сатр ( ) ба формати рақамӣ ( ) табдил медиҳад: Function
String
Integer
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 зич алоқаманданд. Чӣ тавр, шумо мепурсед? Ва чунон ки бисёр усулҳо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
бо . Аз ин рӯ, рӯйхат аз унсурҳои "Елена", "Ҷон", "Алекс", "Ҷим", "Сара" иборат хоҳад буд. Инчунин як усули маъмулан истифодашаванда вуҷуд дорад , ки ба усул монанд аст , аммо фарқият дар он аст, ки он ниҳоӣ аст - терминал.Consumer
Stream
peek
Stream
peopleGreetings
foreach
peek
Усули бо таъминкунанда
Намунаи усуле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
Яъне, ҳар як элементи мо ба худ зарб карда мешавад ва ғайра барои чор рақами аввал. Ҳамааш ҳамин! Хеле хуб мебуд, агар пас аз хондани ин мақола шумо як қадам ба фаҳмидан ва азхудкунии Stream API дар Java наздиктар шавед!
GO TO FULL VERSION