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. Versi 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 predikat
Konsumen
Supplier
Fungsi
UnaryOperator
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 @FunctionalInterface
dudu 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 @FunctionalInterface
iki 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
@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
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
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 Converter
isih 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, Converter
ngowahi 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.
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 Predicate
sing 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 ( ): Function
String
Integer
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 apply
kanggo 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? Lan akeh cara singStream
bisa digunakake kanthi khusus karo antarmuka fungsional kasebut. Ayo goleki carane antarmuka fungsional bisa digunakake ing Stream
.
Metode karo Predikat
Contone, ayo njupuk metode kelasStream
- filter
sing njupuk minangka argumentasi Predicate
lan Stream
mung ngasilake unsur-unsur sing nyukupi kondisi kasebut Predicate
. Ing konteks Stream
-a, iki tegese mung liwat unsur-unsur sing bali true
nalika digunakake ing cara test
antarmuka 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 evenNumbers
bakal kalebu unsur {2, 4, 6, 8}. Lan, kaya sing kita eling, collect
bakal nglumpukake kabeh unsur menyang koleksi tartamtu: ing kasus kita, menyang List
.
Metode karo Konsumen
Salah sawijining cara ingStream
, sing nggunakake antarmuka fungsional Consumer
, yaiku peek
. Iki minangka conto kita Consumer
bakal 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 peek
dianggo karo Consumer
, modifikasi saka strings ing Stream
ora bakal kelakon, nanging peek
bakal bali Stream
karo unsur asli: padha teka menyang. Mulane, dhaptar peopleGreetings
bakal 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 singStream
nggunakake antarmuka fungsional Supplier
yaiku generate
, sing ngasilake urutan tanpa wates adhedhasar antarmuka fungsional sing diterusake. Ayo nggunakake conto kita Supplier
kanggo 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 kanthiStream
argumentasi Function
yaiku metode map
sing njupuk unsur saka siji jinis, nindakake apa wae karo dheweke lan diterusake, nanging iki bisa dadi unsur saka jinis sing beda. Apa conto karo Function
in 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 digunakakeUnaryOperator
minangka 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.
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. Iku kabeh! Iku bakal apik yen sawise maca artikel iki sampeyan wis selangkah luwih cedhak kanggo mangerteni lan nguwasani Stream API ing Jawa!
GO TO FULL VERSION