1. Arayüzler
Lambda fonksiyonlarının ne olduğunu anlamak için öncelikle arayüzlerin ne olduğunu anlamanız gerekir. Öyleyse, ana noktaları hatırlayalım.
Arayüz , sınıf kavramının bir varyasyonudur. Büyük ölçüde kısaltılmış bir sınıf diyelim. Bir sınıfın aksine, bir arayüzün kendi değişkenleri olamaz (statik olanlar hariç). Ayrıca türü arabirim olan nesneler de oluşturamazsınız:
- Sınıfın değişkenlerini bildiremezsiniz
- nesne oluşturamazsın
Örnek:
interface Runnable
{
void run();
}
Arayüz kullanma
Peki bir arayüze neden ihtiyaç duyulur? Arabirimler yalnızca kalıtımla birlikte kullanılır. Aynı arabirim farklı sınıflar tarafından miras alınabilir veya daha önce de belirtildiği gibi — sınıflar arabirimi uygular .
Bir sınıf bir arabirim uygularsa, arabirim tarafından bildirilen ancak uygulanmayan yöntemleri uygulaması gerekir. Örnek:
interface Runnable
{
void run();
}
class Timer implements Runnable
{
void run()
{
System.out.println(LocalTime.now());
}
}
class Calendar implements Runnable
{
void run()
{
var date = LocalDate.now();
System.out.println("Today: " + date.getDayOfWeek());
}
}
Sınıf arabirimi Timer
uygular Runnable
, bu nedenle arabirimdeki tüm yöntemleri kendi içinde bildirmeli Runnable
ve bunları uygulamalıdır, yani bir yöntem gövdesinde kod yazmalıdır. Aynı şey Calendar
sınıf için de geçerli.
Ancak artık Runnable
değişkenler, arayüzü uygulayan nesnelere referansları saklayabilir Runnable
.
Örnek:
kod | Not |
---|---|
|
run() Sınıftaki yöntem Timer çağrılacak Sınıftaki yöntem çağrılacak Sınıftaki yöntem çağrılacak run() Timer run() Calendar |
Bu tür, nesnenin ata sınıflarından biri olduğu sürece, herhangi bir türdeki değişkene her zaman bir nesne başvurusu atayabilirsiniz. Timer
ve sınıfları için Calendar
bu türden iki tür vardır: Object
ve Runnable
.
Bir değişkene bir nesne başvurusu atarsanız Object
, yalnızca sınıfta bildirilen yöntemleri çağırabilirsiniz Object
. Ve bir değişkene bir nesne başvurusu atarsanız Runnable
, türün yöntemlerini çağırabilirsiniz Runnable
.
Örnek 2:
ArrayList<Runnable> list = new ArrayList<Runnable>();
list.add (new Timer());
list.add (new Calendar());
for (Runnable element: list)
element.run();
Bu kod çalışacaktır, çünkü Timer
ve Calendar
nesneleri mükemmel bir şekilde çalışan çalıştırma yöntemlerine sahiptir. Yani, onları aramak sorun değil. Her iki sınıfa da bir run() yöntemi eklemiş olsaydık, onları bu kadar basit bir şekilde çağıramazdık.
Temel olarak, Runnable
arabirim yalnızca run yöntemini koymak için bir yer olarak kullanılır.
2. Sıralama
Daha pratik bir şeye geçelim. Örneğin, dizeleri sıralamaya bakalım.
Bir dize koleksiyonunu alfabetik olarak sıralamak için Java'nın harika bir yöntemi vardır.Collections.sort(collection);
Bu statik yöntem, geçirilen koleksiyonu sıralar. Ve sıralama sürecinde, öğelerin değiş tokuşunun gerekip gerekmediğini anlamak için öğelerinin ikili karşılaştırmalarını gerçekleştirir.
compareTo
Sıralama sırasında bu karşılaştırmalar, tüm standart sınıfların sahip olduğu () yöntemi kullanılarak gerçekleştirilir : Integer
, String
, ...
Integer sınıfının CompareTo() yöntemi iki sayının değerlerini karşılaştırırken, String sınıfının CompareTo() yöntemi dizelerin alfabetik sırasına bakar.
Böylece, bir sayı koleksiyonu artan düzende sıralanırken, bir dize koleksiyonu alfabetik olarak sıralanır.
Alternatif sıralama algoritmaları
Peki ya dizeleri alfabetik olarak değil de uzunluklarına göre sıralamak istiyorsak? Peki ya sayıları azalan düzende sıralamak istersek? Bu durumda ne yaparsın?
Bu tür durumlarla başa çıkmak için sınıfın iki parametresi olan Collections
başka bir yöntemi vardır :sort()
Collections.sort(collection, comparator);
Karşılaştırıcı , bir sıralama işlemi sırasında bir koleksiyondaki nesnelerin nasıl karşılaştırılacağını bilen özel bir nesnedir . Comparator terimi , "karşılaştırmak" anlamına gelen Compare kelimesinden türeyen İngilizce comparator kelimesinden gelir.
Peki nedir bu özel nesne?
Comparator
arayüz
Her şey çok basit. sort()
Yöntemin ikinci parametresinin türü :Comparator<T>
T, koleksiyondaki öğelerin türünü belirten bir tür parametresi ve tek bir yöntemi Comparator
olan bir arabirimdir.int compare(T obj1, T obj2);
Başka bir deyişle, bir karşılaştırma nesnesi, Karşılaştırıcı arabirimini uygulayan herhangi bir sınıfın herhangi bir nesnesidir. Karşılaştırıcı arayüzü çok basit görünüyor:
public interface Comparator<Type>
{
public int compare(Type obj1, Type obj2);
}
Yöntem compare()
, kendisine iletilen iki bağımsız değişkeni karşılaştırır.
Yöntem negatif bir sayı döndürürse, bunun anlamı obj1 < obj2
. Yöntem pozitif bir sayı döndürürse, bunun anlamı obj1 > obj2
. Yöntem 0 döndürürse, bunun anlamı obj1 == obj2
.
Dizeleri uzunluklarına göre karşılaştıran bir karşılaştırıcı nesne örneği:
public class StringLengthComparator implements Comparator<String>
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
}
Dize uzunluklarını karşılaştırmak için bir uzunluğu diğerinden çıkarmanız yeterlidir.
Dizeleri uzunluğa göre sıralayan bir programın tam kodu şöyle görünür:
public class Solution
{
public static void main(String[] args)
{
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Collections.sort(list, new StringLengthComparator());
}
}
class StringLengthComparator implements Comparator<String>
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
}
3. sözdizimsel şeker
Ne dersiniz, bu kod daha derli toplu yazılabilir mi? Temel olarak, faydalı bilgiler içeren tek bir satır vardır — obj1.length() - obj2.length();
.
Ancak kod bir yöntemin dışında var olamaz, bu yüzden bir compare()
yöntem eklemek zorunda kaldık ve yöntemi saklamak için yeni bir sınıf eklemek zorunda kaldık — StringLengthComparator
. Ayrıca değişkenlerin türlerini de belirtmemiz gerekiyor... Her şey doğru görünüyor.
Ancak bu kodu kısaltmanın yolları var. Sizin için biraz sözdizimsel şekerimiz var. İki kaşık toz!
Anonim iç sınıf
Karşılaştırma kodunu doğrudan yöntemin içine yazabilirsiniz main()
ve derleyici gerisini halleder. Örnek:
public class Solution
{
public static void main(String[] args)
{
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Comparator<String> comparator = new Comparator<String>()
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
};
Collections.sort(list, comparator);
}
}
Comparator
Açıkça bir sınıf oluşturmadan arabirimi uygulayan bir nesne oluşturabilirsiniz ! Derleyici otomatik olarak oluşturacak ve geçici bir isim verecektir. Hadi karşılaştıralım:
Comparator<String> comparator = new Comparator<String>()
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
};
Comparator<String> comparator = new StringLengthComparator();
class StringLengthComparator implements Comparator<String>
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
}
İki farklı durumda aynı kod bloklarını belirtmek için aynı renk kullanılır. Pratikte farklar oldukça küçüktür.
Derleyici ilk kod bloğuyla karşılaştığında, karşılık gelen ikinci bir kod bloğu üretir ve sınıfa rastgele bir ad verir.
4. Java'da Lambda ifadeleri
Diyelim ki kodunuzda anonim bir iç sınıf kullanmaya karar verdiniz. Bu durumda, şöyle bir kod bloğunuz olacaktır:
Comparator<String> comparator = new Comparator<String>()
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
};
Burada bir değişkenin bildirimini anonim bir sınıfın oluşturulmasıyla birleştiriyoruz. Ancak bu kodu kısaltmanın bir yolu var. Örneğin, bunun gibi:
Comparator<String> comparator = (String obj1, String obj2) ->
{
return obj1.length() – obj2.length();
};
Noktalı virgül gereklidir, çünkü burada yalnızca örtük bir sınıf bildirimimiz değil, aynı zamanda bir değişken yaratmamız da var.
Bunun gibi notasyona lambda ifadesi denir .
Derleyici, kodunuzda buna benzer bir gösterimle karşılaşırsa, yalnızca kodun ayrıntılı sürümünü (anonim bir iç sınıfla) oluşturur.
Lambda ifadesini yazarken sadece sınıfın adını değil , yöntemin adını da atladığımıza dikkat edin .Comparator<String>
int compare()
Derleme yöntemi belirlemekte sorun yaşamaz çünkü bir lambda ifadesi yalnızca tek bir yöntemi olan arabirimler için yazılabilir . Bu arada, bu kuralı aşmanın bir yolu var, ancak bunu OOP'yi daha derinlemesine çalışmaya başladığınızda öğreneceksiniz (varsayılan yöntemlerden bahsediyoruz).
Kodun ayrıntılı versiyonuna tekrar bakalım, ancak bir lambda ifadesi yazarken atlanabilecek kısmı gri yapacağız:
Comparator<String> comparator = new Comparator<String>()
{
public int compare (String obj1, String obj2)
{
return obj1.length() – obj2.length();
}
};
Önemli bir şey atlanmamış gibi görünüyor. Aslında, Comparator
arayüzün yalnızca bir compare()
yöntemi varsa, derleyici devre dışı kalan kodu kalan koddan tamamen kurtarabilir.
Sıralama
Bu arada sıralama kodunu şu şekilde yazabiliriz:
Comparator<String> comparator = (String obj1, String obj2) ->
{
return obj1.length() – obj2.length();
};
Collections.sort(list, comparator);
Hatta şöyle:
Collections.sort(list, (String obj1, String obj2) ->
{
return obj1.length() – obj2.length();
}
);
comparator
Değişkeni hemen değişkene atanan değerle değiştirdik comparator
.
Tür çıkarımı
Ama hepsi bu kadar değil. Bu örneklerdeki kod daha da derli toplu yazılabilir. İlk olarak, derleyici kendisi için obj1
ve obj2
değişkenlerinin olduğunu belirleyebilir Strings
. İkincisi, yöntem kodunda yalnızca tek bir komutunuz varsa kaşlı ayraçlar ve dönüş ifadesi de atlanabilir.
Kısaltılmış versiyon şu şekilde olacaktır:
Comparator<String> comparator = (obj1, obj2) ->
obj1.length() – obj2.length();
Collections.sort(list, comparator);
Ve değişkeni kullanmak yerine comparator
hemen değerini kullanırsak, aşağıdaki sürümü elde ederiz:
Collections.sort(list, (obj1, obj2) -> obj1.length() — obj2.length() );
Buna ne dersin? Gereksiz bilgi içermeyen tek bir kod satırı - yalnızca değişkenler ve kod. Daha kısa yapmanın bir yolu yok! Yoksa var mı?
5. Nasıl çalışır?
Aslında, kod daha da kompakt bir şekilde yazılabilir. Ama bunun hakkında daha sonra.
Bir interface tipini tek metod ile kullanacağınız bir lambda ifadesi yazabilirsiniz .
Örneğin, kodda bir lambda ifadesi yazabilirsiniz çünkü yöntemin imzası şöyledir:Collections.sort(list, (obj1, obj2) -> obj1.length() - obj2.length());
sort()
sort(Collection<T> colls, Comparator<T> comp)
Koleksiyonu sort yöntemine ilk argüman olarak ilettiğimizde ArrayList<String>
, derleyici ikinci argümanın türünü belirleyebildi . Buradan da, bu arayüzün tek bir metodu olduğu sonucuna varılmıştır. Diğer her şey bir tekniktir.Comparator<String>
int compare(String obj1, String obj2)
GO TO FULL VERSION