Öncəki məqalədə yazdığımız nümunələrdə biz istədiyimiz şərtin doğruluğunu yoxlamaq üçün Checker
funksional interface`nin test()
metodundan istifadə edirdik:
public interface Checker { boolean test(Animal a); }
Burada biz parametr olaraq ancaq Animal
tipində obyekt göndərə və şərtlərimizi ancaq Animal
classı üçün yoxlaya bilirdik. Tutaq ki, indi bizim Person
tipində classımız var və eyni şərtləri həmin class üçün də yoxlamalıyıq. Bunun üçün biz Person
tipində obyekt qəbul edən yeni abstract metod yaratmalıyıq. Ancaq funksional interface`də birdən artıq abstract metod yaratmaq mümkün olmadığından məcburuq yeni funksional interface yaradaq. Bu problemi aradan qaldırmaq üçün java özü bizi hazır functional interface`lər ilə təmin edir. Həmin functional interface`lər java.util.function
paketində yerləşir və OCA imtahanı üçün bizə bunlardan yalnız Predicate
interface`ni öyrənmək kifayət edir.
@FunctionalInterface // optional public interface Predicate<T> { boolean test(T t); }
Predicate
interface`nin bizim Checker
interface`indən ancaq bir fərqi var, o da generics olmağıdır. İndi biz yeni metod yaratmadan Predicate
interface`nin test()
metoduna Animal
, Person
, və yaxud hər hansı istənilən referans tip göndərə bilərik. Əgər Predicate
interface`inə hər hansı bir tip təyin edilməzsə, default olaraq Object
qəbul edir.
İndi öncəki məqalədə yazdığımız TraditionalSearch
classını heç bir functional interface yaratmadan Predicate
interface`i vasitəsilə yenidən yazaq:
import java.util.*; import java.util.function.*; public class PredicateSearch { public static void main(String[] args) { List<Animal> animals = new ArrayList<Animal>(); animals.add(new Animal("fish", false, true)); animals.add(new Animal("dog", true, true)); print(animals, a -> a.canHop()); } private static void print(List<Animal> animals, Predicate<Animal> checker) { for (Animal animal : animals) { if (checker.test(animal)) { System.out.print(animal + " "); } } System.out.println(); } }
Tam aydın olsun deyə daha bir nümunəyə baxaq. Bu nümunə https://dzone.com saytında rastıma çıxdı, lambdanın önəmini göstərmək baxımından daha faydalı gəldi mənə, ona görə qeyd etmək qərarına gəldim. Deməli sizin belə bir listiniz var:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Və sizdən bu listin bütün elementlərinin cəmini verən metod yazmağınız tələb olunur. Aşağıdakı kimi bir metod yazırsız:
public int sumAll(List<Integer> numbers) { int total = 0; for (int number : numbers) { total += number; } return total; }
Səhəri gün listin cüt elementlərinin cəmi də tələb olunduğu deyilir. Və ağlınıza gələn ilk şey həmin metodu kopyalayıb, adını və içindəki şərti dəyişmək olur:
public int sumEven(List<Integer> numbers) { int total = 0; for (int number : numbers) { if (number % 2 == 0) { total += number; } } return total; }
Növbəti gün isə listin 3-dən böyük olan elementlərinin cəmi lazımdır deyəndə artıq başa düşürsünüz ki, copy-paste üsulu bu işlər üçün uyğun deyil, sizə optimal bir yöntəm lazımdı. Bu zaman lambda bizim köməyimizə gəlir. Predicate
interface`indən istifadə edərək metodu bircə dəfə yazırıq:
public int sumAppropriateElements(List<Integer> numbers, Predicate<Integer> p) { int total = 0; for (int number : numbers) { if (p.test(number)) { total += number; } } return total; }
Və tələb olunan şərtə uyğun lambda ifadəsi göndərərək lazımı nəticəni alırıq:
sumAppropriateElements(numbers, n -> true); // all sumAppropriateElements(numbers, n -> n % 2 == 0); // only even sumAppropriateElements(numbers, n -> n > 3); // greater than 3
İmtahanda Predicate
ilə əlaqəli bilməli olduğumuz növbəti mövzu removeIf()
metodudur. Bu metod ArrayList
ilə istifadə edilir və parametr olaraq Predicate
qəbul edir. Bu metodun üstünlüyü nədir baxaq. Tutaq ki, bizim adlar listimiz var və biz istəyirik ki, “C” hərfi ilə başlamayan adlar bu listdən silinsin. Ənənəvi qayda ilə yanaşsaq biz bu listi dövrə salıb hər elementi bir-bir şərtlə yoxlayıb silə bilərik. removeIf()
metodunun köməkliyi ilə isə bunu bir sətirdə etmək mümkündür:
List<String> names = new ArrayList<>(); names.add("Elnur"); names.add("Ceyhun"); names.add("Cavid"); names.add("Adil"); names.add("Hasil"); names.add("Odər"); System.out.println(names); // [Elnur, Ceyhun, Cavid, Adil, Hasil, Odər] names.removeIf(s -> s.toLowerCase().charAt(0) != 'c'); System.out.println(names); // [Ceyhun, Cavid]
removeIf()
metodu ilə bağlı daha bir nümunəyə baxaq:
public class Whizlabs { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(21); list.add(13); list.add(30); list.add(11); list.add(2); // insert here System.out.println(list); } }
Bu nümunə Whizlabs test bankında rastıma çıxmışdı və soruşulur ki, “insert here” yazısının əvəzinə aşağıdakı bəndlərdən hansı əlavə edilməlidir ki, output [21, 13, 11]
olsun?
a. list.removeIf(e > e%2 != 0); b. list.removeIf(e -> e%2 != 0); c. list.removeIf(e -> e%2 == 0); d. list.remove(e -> e%2 == 0); e. Heç biri
Mövzunu yaxşı başa düşdüyünüzdən əmin olmaq üçün cavabı özünüz tapmağa cəhd edin 🙂
Enthuware-də rastlaşdığım suallardan biri də mənim üçün yenilik olmuşdu, kitabda həmin məsələyə rast gəlməmişdim. Kod nümunəsi və sual belə idi:
public class TestClass { public static boolean checkList(List list, Predicate<List> p) { return p.test(list); } public static void main(String[] args) { boolean b = //WRITE CODE HERE System.out.println(b); } }
Qeyd olunan hissəyə aşağıdakı bəndlərdən hansılar əlavə edilərsə, output true
olar?
a. checkList(new ArrayList(), al -> al.isEmpty()); b. checkList(new ArrayList(), ArrayList al -> al.isEmpty()); c. checkList(new ArrayList(), al -> return al.size() == 0); d. checkList(new ArrayList(), al -> al.add("hello")); e. checkList(new ArrayList(), (ArrayList al) -> al.isEmpty());
b
və c
bəndlərində aşkar sintaksis səhvi olduğundan düzgün cavablar deyil, qalır a
, d
və e
. add()
və isEmpty()
metodları geri true
qaytarır və sintaksis ilə hər şey qaydasında olduğuna görə a
və d
düzgün cavablardır. Geriyə bircə e
variantı qalır və mənim də ən çox diqqətimi çəkən bənd bu olmuşdu. Bu bənddə də hər şey qaydasında görünürdü, fikirləşirdim yəqin bu da düzgün cavab ola bilər, amma elə deyil, e
səhv cavabdır. Çünki checkList
metodunda Predicate
-in tipi List
göstərilib, e
bəndində də al
dəyişəninin tipi mütləq List
olmalıdır, ArrayList
ola bilməz. Buna diqqət etmək lazımdır.
Predicate
interface`i ilə birbaşa hazır filterlər də yaratmaq mümkündir. Məsələn, sizə belə bir filter lazımdı: sözün tərkibində kiçik “a” hərfi olsun, amma söz kiçik “a” ilə başlamasın. Bu filteri aşağıdakı şəkildə yaza bilərik:
Predicate<String> filter = s -> s.indexOf("a") > 0;
Sözün bu filterə uyğun gəlib-gəlmədiyini yoxlamaq üçün isə aşağıdakı kodu çağırmaq kifayətdir:
System.out.println(filter.test("java")); // true System.out.println(filter.test("asp")); // false
Mövzunun sonunda isə öz imtahan təcrübəmdən bir məqamı vurğulamaq istəyirəm. Deməli, mən imtahan verən zaman 1Z0-808 (digər adı ilə OCA SE 8) imtahanında 77 sual olurdu. Və mənə cəmi cümlətanı bircə lambda sualı düşmüşdü və həmin sualı da səhv cavablandırmışdım 🙂 İmtahandan çıxan kimi IDE-ni açıb birinci yoxladığım sual da elə bu sual idi və səhvin nədə olduğunu başa düşmüşdüm. Həqiqətən maraqlı sual idi, nə oxuduğum kitabda, nə də test banklarında bu tip sual ilə rastlaşmamışdım. Ola bilsin feedback`lər əsasında sonradan Enthuware test bankına əlavə etsinlər. Bu sual ilə bağlı ətraflı şəkildə blogda imtahan təcrübəm bölməsində qeyd etmişəm, kiməsə maraqlı olsa buradan baxa bilər.
[topics lang=az]