Pattern Matching -Java14
Bu makalede Java’da bir nesnenin ait olduğu sınıfı(class) tespit etmek için kullandığımız “instanceof” komutunun Java14 versiyon itibariyle gelen yeni özelliğini inceleyeceğiz.
Aslında bu yapının genel amacı ve söylemi “Pattern Matching (Desen-Kalıp Karşılaştırma)” şeklindedir.
Pattern Matching dediğimizde,sadece bu komuta bağlı kalmayarak,bu iş ve süreçlerde kullanılan diğer komut ve yapılara da değinmemiz gerekir. Ancak bu makalenin amacı “instanceof” komutunun yeni ve oldukça kullanışlı içeriğiyle alakalıdır.
Temel java bilgisine sahip bir geliştirici bu komutun yapısı ve çalışma mimarisini bilir. Dolayısıyla bu komutun görevini işlemeyeceğiz. Ancak yeni özelliğini inceleyebilmemiz için java14 sürümü öncesinde kullandığımız şekliyle karşılaştırma amaçlı bir örnek vererek başlayacağız.
Aşağıda eski sistem bir kullanım gösteriliyor.
if (x instanceof Integer) {
int intValue = ((Integer) x).intValue();
//..
}
Yukarıdaki örnekte birkaç işlem gerçekleşiyor. İlk işlem “x” nesnesi “Integer” ile karşılaştırılıyor.
Elbette bu işlemde bir problem yok. Ancak if bloğu içerisinde gerçekleşen casting işlemi,benim daha önce üzerinde önemle durduğum “Boxing-Unboxing” konusuyla tam alakalı. Yani “x” nesnesi “Integer” kaynaklı üretilmiş ise bu nesneyi işleme alıyoruz ve bir dönüştürmeye tabi tutuyoruz. Elbette küçük ve sık tekrarlanmayan programlarda göze batmaz. Ancak tersi durumda bu kullanımın dezavantajlarını önceki yazılarımda konuşmuştuk.
Örneğin aşağıdaki gibi bir kullanım durumu daha da kötüleştiriyor.
String formatted = "unknown";
if (x instanceof Integer) {
int i = (Integer) x;
formatted = String.format("int %d", i);
}
else if (x instanceof Byte) {
byte b = (Byte) x;
formatted = String.format("byte %d", b);
}
else if (x instanceof Long) {
long l = (Long) x;
formatted = String.format("long %d", l);
}
else if (x instanceof Double) {
double d = (Double) x;
formatted = String.format(“double %f", d);
}
else if (x instanceof String) {
String s = (String) x;
formatted = String.format("String %s", s);
}
Bu örnekte ise “x” nesnesi birden fazla olası hedef türüne karşı test ediliyor.
Bu kod parçasıyla ilgili çok şey söylenebilir. Örneğin karmaşıklık,gereksiz birçok karşılaştırma,optimizasyon,performans,hataya elverişli ortam vb. gibi ayrıca konular konuşmamıza sebep olur.
Yeni instanceof
Java14 ile gelen yeni özellik neticesinde “instanceof” komutu aşağıdaki gibi kullanılıyor.
if (x instanceof Integer i) {
// "i"'yi tamsayı türünden bir nesne olarak kullanabiliriz.
}
Görüldüğü gibi komut yapısı itibariyle bir değişiklik yok. Ancak karşılaştırma kısmında karşılaştırma yapılan sınıfın ayrıca bir nesnesi oluşturulduğu görülüyor. Dolayısıyla eğer “x” Integer sınıfına ait bir nesne ise yine Integer’dan “i” ismiyle bir nesne oluşturuluyor ve “x” nesnesi “i”’ye atanıyor. Yani karşılaştırma esnasında olup bitenleri manuel olarak biz yaparsak aşağıdaki örnek(eski versiyon kullanım) ortaya çıkacaktır.
if (x instanceof Integer) {
Integer i = (Integer)x;
//i'yi tamsayı türünden bir nesne olarak kullanabiliriz.
}
Yeni kullanımın karmaşıklığı önlemesi ve dolayısıyla daha okunabilir kod geliştirmemize fırsat verdiğini aşağıda verilen örneklerden de görebiliriz. Bu örnekte “Point” sınıfı için bir “equals” fonksiyonu yazılmıştır.
Eski versiyon:
public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point other = (Point) o;
return x == other.x
&& y == other.y;
}
Yeni versiyon:
public boolean equals(Object o) {
return (o instanceof Point other)
&& x == other.x
&& y == other.y;
}
Görüldüğü gibi yeni özellik ile oldukça temiz,okunaklı,düzenli ve tek bir satır ile Point sınıfına ait equals sürecini gerçekleştirebiliyoruz.
Benzer şekilde yukarıda incelediğimiz if-else zincirinin yeni haliyle aşağıdaki gibi örnekleyebiliriz.
String formatted = "unknown";
if (x instanceof Integer i) {
formatted = String.format("int %d", i);
}
else if (x instanceof Byte b) {
formatted = String.format("byte %d", b);
}
else if (x instanceof Long l) {
formatted = String.format("long %d", l);
}
else if (x instanceof Double d) {
formatted = String.format(“double %f", d);
}
else if (x instanceof String s) {
formatted = String.format("String %s", s);
}
Değişken Kapsamı(Variable Scope)
Yukarıda işlediğimiz yeni özellik içeriğinde,kod düzenini oluşturan etkenlerden birisi de tanımlanan değişkenin-nesnenin sadece if bloğu içinde geçerli olmasıdır.Aşağıda verilen örnekte değişkenin geçerli olduğu ve dolayısıyla kullanılabilir kapsamı veriliyor.
if (x instanceof String s) {
System.out.println(s + " bir string'dir");
// s'yi bu if bluğu içinde kullanabiliriz.
String new_str = "new string " + s;
System.out.println("new str:" + new_str);
}
else {
//"s" Kapsam dışında.
System.out.println(s); //Error!
}
Kapsam üzerinde düşünürken yukarıda verilen kullanımı elbette tahmin edebiliriz.Ancak hem tanımlama ve hem de herhangi bir değeri kontrol amaçlı tasarlanan bir “instanceof” if bloğunda durum değişebilir.
Buna bağlı olarak aşağıdaki örnekleri inceleyelim.
if (x instanceof String s && s.length() > 0){
System.out.println(s);
}
Yukarıda verilen örnekte “s” değişkeni “s.length() > 0” kontrolü kapsamında olacaktır.Çünkü if bloğunda “String s”’den sonra “&&(VE)” operatörü kullanılmıştır. Dolayısıyla “x instanceof String s” sağlandığında zaten “s” değişkeni “&&” operatörüyle garantiye alınmıştır. Ancak aşağıdaki örnek için aynı şeyi söyleyemeyiz.
if (x instanceof String s || s.length() > 0) { // Error!
//...
}
Yukarıdaki kullanım hatalıdır. Çünkü kullanılan “||(VEYA)” operatörü ile
“x instanceof String s” şartı garantiye alınmamıştır.
Dolayısıyla instanceof başarılı olmayabilir. Bu nedenle “s” oluşturulmaz ve “s.lentgh()” kullanımı hatalıdır.
KAYNAKLAR:
https://openjdk.java.net/
https://cr.openjdk.java.net/
-end of