JSR 341 – Expression Language 3
Expression Language, kısaca “EL” bir Java standardıdır. En yeni hali ise, JSR 341 olarak temsil edilen EL 3′dir. Expression Language, ilk çıkış noktasında JSP sayfalarında kullanılmaya başlandı. JSF ′nin çıkması ile genelleşti ve Unified EL olarak nitelenmeye başlandı. EL 3, ile de tamamen ortam bağımsız olarak Java SE ve Java EE ortamlarında bağımsız olarak kullanılabilir hale geldi. Expression Language 3 ile beraber, EL deyimleri çok zenginleşti. Bu zenginliğin kaynağını aslında genel olarak Lambda ifadeleri sağlamaktadır. Java 8 içerisinde karşımıza çıkacak Lambda ifadeleri, EL 3 içerisinde de kısmi olarak destekleniyor. Fakat, EL 3 kullanmak için JDK 8 ihtiyacını bulunmuyor, JDK 7 ile de EL 3 üzerinde Lambda deyimleri kullanılabilmektedir.
Expression Language Örnekler
Örnek 1: Lambda Deyimleri
Java 8 ile Lambda deyimleri koşturulabilmektedir. Bu sayede Java dili çok daha esnek bir yapıya sahip olmaktadır. Lambda deyimlerinin en büyük avantajlarından biri de, Java Collection API ile yapılan genel operasyonları inanılmaz kolaylaştırmasıdır.
Örneğin, aşağıda bir dizi isim bilgisini barındıran listeye, Lambda deyimleri ile, filtreleme, sıralama ve türe dönüştürüm işlemleri tek satır ile zincirlemeli olarak yapılabilmektedir.
Lambda
List<String> liste = Arrays.asList("Ali", "Zehra", "Selami", "Beyza", null, "Melike", "Hakkı", "Ayşe", "Ruhan", "Cem", "Berşan", "Yusuf");
List<String> sonuc =liste
.stream()
.filter(e -> e != null)
.filter(e -> e.length() > 3)
.sorted()
.collect(Collectors.toList());
Yukarıdaki Lambda deyimini kullanabilmek için JDK 8’in geliştirme ortamınızda bulunması gerekmektedir. Lambda deyimleri sonucu elde edilen çıktı ise;
[Ayşe, Berşan, Beyza, Hakkı, Melike, Ruhan, Selami, Yusuf, Zehra] ‘dir.
Yani “Ali”, “Cem” ve null ifade listeden süzülmüş, ve isme göre sıralama yapılmıştır. Aynı ifade, EL 3 deyim diliyle de gerçekleştirilebilir. EL 3 Lambda deyimlerini birebir karşılamamakla birlikte, benzeşim oranı bilhayli yüksektir.
EL 3 deyimleri, Java SE ve Java EE uygulamalarında rahatlıkla kullanılabilir. EL 3 deyimlerini koşturmak için ise, javax.el paketi altındaki ELProcessor sınıfından faydalanılmaktadır. EL ortamına bir nesne eriştirilmesi için ELProcessor# setValue metodu kullanılırken, EL deyimlerini işletmek için ise, ELProcessor# eval metodu kullanılmaktadır. ELProcessor# eval metodu ,EL deyimlerini “String ” türünden kabul etmektedir. Yani tip güvenliği söz konusu değildir. Bunun dezavantajı, çalışma zamanında beklenmedik istisnalar ile karşılaşabilmek iken, avantajlı tarafı ise, dinamik olarak EL deyimlerinin hazırlanabilmesidir. Yani istenirse, EL deyimlerini çalışma zamanında dinamil olarak da hazırlayabilirsiniz.
EL 3 ile Lambda
ELProcessor processor = new ELProcessor();
processor.setValue("liste", liste);
List<String> sonuc = (List<String>) processor.eval("liste.stream().filter(e -> e != null).filter(e -> e.length() > 3).sorted().toList()");
Şu anda EL deyimlerinde collect Lambda metoduna destek sunmamaktadır, fakat istenirse elde edilen sonuç toList deyimi ile, List türüne dönüştürülebilmektedir. Bu deyimden elde edilen sonuç, bir önceki Lambda örneğinde olduğu gibidir.
Örnek 2: EL List & Map
EL deyimleri ile List ve Map türünden veri tipleri tanımlanabilmektedir. Bu tanımlama biçimi, Javascript dilindeki List [ ] ve Map { } tip tanımalamalarıyla bir bir aynıdır.
ELProcessor el= new ELProcessor();
// İki eleman barındıran bir List nesnesi üretir.
el.eval("['Evet','Hayır']"); // List["Evet","Hayır"]
// Bir listenin herhangi bir indisteki elemanı elde edilebilir.
el.eval("['Evet','Hayır'][1]"); // "Hayır"
// İstenirse, ara çıktılar değişkenlere aktarılabilir (durum).
// Değişkene tip tanıtımına gerek yoktur.
el.eval("durum=['Evet','Hayır']; durum"); //List["Evet","Hayır"]
// Değişkenler, devam eden satırlarda kullanılabilir.
// İfadedeki, son komut satırı, EL çıktısını temsil eder.
el.eval("durum=['Evet','Hayır']; durum[0]"); // "Evet"
// Map türünden ifadeler, {} karakterleriyle tanımlanabilir.
// Javascript nesnesi tanımlar gibi.
el.eval("{'a':1,'b':2}"); // Map{"a":1,"b":2}
// Anahtar değer ile karşılık değere erişilebilir.
el.eval("durum={'a':1,'b':2,'a':'otuz'}; durum['a']"); // "otuz"
Örnek 3: Operatörler
EL 3 matematiksel ve mantıksal operatörler kullanılabilmektedir. İşin güzel yanı, bu operatörleri Lambda fonksiyonları ile birlikte kullanabilirsiniz.
ELProcessor el = new ELProcessor();
// a > b ise true, değilse false
el.eval("test = (a,b)-> (a>b); test(2,-1)"); // true
// Yukarıdaki Lambda fonksiyonu, aşağıdaki Javascript fonksiyonuna benzetilebilir.
// var test = function(a,b){ return a>b; }
// test(2,-1); // true
// Lambda fonksiyonunu peşisıra koşturabilirsiniz.
el.eval("((a,b)-> (a>b))(2,-1)"); // true
// Yukarıdaki Lambda fonksiyonu, aşağıdaki Javascript fonksiyonuna benzetilebilir.
// (function(a,b){ return a>b; })(2,-1); // true
// Sayısal bir değeri, 2 veya ‘2’ gibi tanımlayabilirsiniz. EL bu konuda akıllıdır.
el.eval("test = (a,b)->(a>b) ; test('2',-1)"); // true
// Matematiksel operatörler de kullanılabilir. 2+(-1) = 1
el.eval("test = (a,b)->(a+b) ; test('2',-1)"); // 1
// + ifadesi, matematiksel toplama içindir. String verilerde eklemeli toplama için += kullanılabilir.
el.eval("test=(a,b)-> a+=b; test('Hey','Yolcu')");
// Çıktı: Hey Yolcu
// veya String#concat metodu kullanılabilir.
el.eval("test=(a,b)->(a.concat(b));test('Hey','Yolcu')");)");
// Çıktı: Hey Yolcu
Örnek 4: EL Bean & Variable
EL 3 ile Java ortamındaki nesneler ve değişkenler, EL ortamına eriştirilebilir. Nesne eriştirimi için ELProcessor# defineBean metodu kullanılırken, değişken eriştirimi için ise, ELProcessor#setVariable metodu kullanılmaktadır.
ELProcessor processor=new ELProcessor();
Kitap kitap = new Kitap();
kitap.setAd("Java Mimarisiyle Kurumsal Çözümler");
kitap.setYazar(new Yazar("Rahman", "Usta"));
processor.defineBean("kitap",kitap);
processor.setVariable("adSoyad","kitap.yazar.ad+=' '+=kitap.yazar.soyad");
processor.getValue("kitap.ad",String.class);
// Çıktı: Java Mimarisiyle Kurumsal Çözümler
processor.getValue("adSoyad",String.class);
// Çıktı: Rahman Usta
ELProcessor# defineBean ile tanımlanan nesneye ve onun alanlarına dot ( . ) notasyon il erişilebilir. Örn: aBean.bField.cField.dValue gibi.
ELProcessor# defineBean veya ELProcessor# setVariable ile EL ortamına eriştirilen nesne ve değerlere, ELProcessor# getValue metoduyla erişilebilmektedir.
Örnek 5: ELManager#importPackage
EL ifadeleri içinde java.lang paketi altındaki tüm nesneler varsayılan olarak kullanılabilmektedir.
Örn: processor.eval(Math.pow(2,5)); // 32 gibi
Fakat java.lang paketi haricindeki nesnelere erişim için ELManager#importPackage metodu kullanılmaktadır. ELManager nesnesi mevcut ELProcessor nesnesinin getELManager() metodu ile elde edilmektedir.
ELProcessor processor = new ELProcessor();
ELManager elManager = processor.getELManager();
elManager.importPackage("java.util.concurrent"); // Dikkat
processor.eval("ThreadLocalRandom.current().nextInt(1,100)");
// Çıktı: 1-100 arası bir değer.
Benzer biçimde, ELManager sınıfının importStatic, importClass adında iki metodu daha bulunmaktadır.
Örnek 6: ELProcessor#defineFunction
Java ortamında yazılmış metodlar, EL ortamında koşturulabilirdir. Bunun için ELProcessor#defineFunction metodu ile, Java metodları EL ortamına tanıtılmalıdır.
public class Toplayici {
public static int topla(int a,int b){
return a+b;
}
}
Örneğin, yukarıdaki gibi bir Toplayici#topla metodunu EL 3 ortamında kullanmak istersek, aşağıdaki 3 biçimde de kullanabiliriz.
ELProcessor#defineFunction metodu 4 parametre almaktadır.
void defineFunction(String prefix, String function, String className, String method);
ELProcessor processor = new ELProcessor();
processor.defineFunction("","","com.kodcu.Toplayici","topla");
// prefix ve function boş ise;
processor.eval("topla(3,4)");
processor.defineFunction("","hesapla","com.kodcu.Toplayici","topla");
// function ismi tanımlandıysa;
processor.eval("hesapla(3,4)");
processor.defineFunction("kodcu","hesapla","com.kodcu.Toplayici","topla");
//Ön ek verildiyse;
processor.eval("kodcu:hesapla(3,4)");
Örnek 7: ELManager#addBeanNameResolver
ELManager#addBeanNameResolver metodu, Java ve EL Bean çözümlemesini dinamik olarak tanımlama imkanı sunmaktadır. ELManager#addBeanNameResolver metodu BeanNameResolver sınıfı türünden tek parametre almaktadır.
ELProcessor processor = new ELProcessor();
Kitap kitap = new Kitap();
kitap.setAd("Java ve Yazılım Tasarımı");
Yazar yazar = new Yazar("Altuğ Bilgin", "Altıntaş");
kitap.setYazar(yazar);
ELManager elManager = processor.getELManager();
elManager.addBeanNameResolver(new BeanNameResolver() {
@Override
public Object getBean(String beanName) {
// bean adı “kitap” ise kitap, değilse yazar nesnesini döndürür.
return beanName.equals("kitap")?kitap:yazar;
}
@Override
public boolean isNameResolved(String beanName) {
// bean adı kitap veya yazar ise, bu nesne adı burada çözümlenebilir.
return "kitap".equals(beanName) || "yazar".equals(beanName);
}
});
processor.eval("kitap.ad"); // Java ve Yazılım Tasarımı
processor.eval("yazar.soyad"); // Altıntaş
Tekrar görüşmek dileğiyle..
Tag:backend, expression language, lambda