În numărul 23 al revistei Today Software Magazine am început o discuţie despre ceea ce aduce nou Java SE8. Aproape unanim, specialiştii în Java susţin că expresiile lambda, ca topic general, dar şi implicaţiile produse de acestea, reprezintă cele mai importante feature-uri ale versiunii actuale. De aceea am considerat util ca primul articol să fie despre acest topic.
Discuţiile din acest articol sunt purtate la un nivel de dificultate mai ridicat, pentru a permite evidenţierea unor aspecte de performanţă, productivitate şi de reducere a dimensiunii codului scris.
Pentru început revin la expresiile lambda. Prin expresii lambda putem crea metode anonime. Uneori însă, expresiile lambda apelează metode care au deja un nume.
Pentru a clarifica lucrurile revin la exemplul din articolul amintit la început. Avem o clasă Product cu două atribute, name
și price
, getter-i şi setter-i. Voi mai adăuga proiectului nostru o clasă POJO în care se află diverse metode de comparare, cu semnături apropiate de ale metodei compare()
din interfaţa Comparator:
public class ProductComparisons {
public int compareByName(
Product a, Product b) {
return a.getName().
compareTo(b.getName());
}
public int compareByPrice(
Product a, Product b) {
return a.getPrice() -
b.getPrice();
}
}
În clasa de test vom crea două obiecte Product, p1
şi p2
, pe care le vom pune într-un array:
Product[] basket = { p1, p2 };
Vom sorta array-ul folosind expresiile:
ProductComparisons myComparison =
new ProductComparisons();
Arrays.sort(basket,
(a,b)->myComparison.
compareByName(a, b));
Această sintaxă este posibilă pentru că rezultatul expresiei lambda este o clasă anotată @FunctionalInterface
, în cazul nostru, Comparator.
În locul folosirii expresiilor lambda, Java SE8 oferă posibilitatea utilizării referinţelor de metode, prin intermediul operatorului de domeniu ::
. Sintaxa este astfel mult simplificată.
Revin la exemplul nostru şi aplic operatorul anterior. Sintaxa devine:
Arrays.sort(basket,
myComparison::compareByName);
Avem următoarele tipuri de referinţe:
Arrays.sort(basket,
myComparison::compareByName);
Supplier s = Product::new;
unde Supplier
este din
java.util.function.Supplier;
Un alt subiect pe care vreau să vi-l supun atenţiei este legat de interfeţe. Interfeţele conţineau, până la această versiune, doar semnături de metode şi constante. Java 8 propune o abordare care să îmbunătăţescă utilizabilitatea interfeţelor. Dacă adaugăm noi semnături în interfaţa atunci clasele ce o implementează ar trebui rescrise. Pentru a evita procesul rescrierii s-au introdus metodele default. Pe lângă semnături şi constante, interfeţele vor conţine astfel şi implementări.
Voi da un exemplu simplu, care să evidenţieze noile abordări:
public interface MyInterface {
void myClassicMethod();
default void myDefaultMethod() {
System.out.println(“hello default!”);
}
static void myStaticMethod(){
System.out.println(“hello static!”);
}
}
Respectiv clasa ce implementează interfaţa:
public class MyClass implements MyInterface {
@Override
public void myClassicMethod() {
System.out.println(“hello classic!”);
}
}
Ca test avem:
public static void main(String[] args) {
MyInterface mine = new MyClass();
mine.myClassicMethod();
mine.myDefaultMethod();
MyInterface.myStaticMethod();
}
Surprindem astfel cele trei comportamente:
public abstract
(myClassicMethod).Procesul de moştenire are suport și pentru acest nou comportament. Altfel:
Nu voi încheia acest articol fără să descriu câteva dintre API-urile folosite în discuţiile anterioare.
java.util.function
, ce furnizează interfeţele funcţionale ce sunt returnate ca tip prin intermediul expresii lambda. Interfeţele funcționale reprezintă concepte abstracte precum funcţiile, acțiunile sau predicatele.java.util.stream
, ce furnizează clase pentru operaţii pe stream-uri de elemente. Stream-urile diferă de colecţii prin:
limit()
, findFirst()
)Discuţiile despre Java SE8 vor continua şi în ediţiile viitoare ale TSM. Pînă atunci lectură plăcută şi o vară frumoasă!