It"s spring… the time of changes and hope… Oracle contributes to all that with a new version of the standard Java platform. I am talking about version 8, released in March 2014.
Beginning with the current issue of Today Software Magazine, I wish to change the type of articles that I write. I cannot say I abandon the idea of book reviews, which represent an important way of putting forth some valuable books from the IT library, but I will also add some articles of a higher technical degree. By doing this, I hope the readers of the magazine will be incited to discover what is new and performant in the world of software applications development.
I am very glad this issue is launched in Brasov as well, and, though it is the first launching here, I hope it to be followed by many others. Brasov has an enormous potential, and I love this city very much.
Java SE8 is considered to be revolutionary, due to some of the newly introduced features. Initially scheduled for September 2013, the release was postponed to March 2014. The reasons are manifold, but they are basically related to debugging and security improvement, especially on the client side, having JavaFX as the main reason.
There are many changes and additions in the language, but probably the most spectacular one is the introduction of lambda capabilities. They are seen as an important benefit in parallel programming. Actually, the efforts for increasing the performance in parallel programming were seen even from version 7, the introduction of the Fork-Join framework is only an example.
In the first part of the article I will focus mainly on lambda expressions; in the final part I will discuss a bit about a brand-new JavaScript engine, and in the following articles I will talk about other Java SE8 related topics.
A lambda function (anonymous function) is a function that is defined and called without being connected to an identifier. Lambda functions are a form of nested functions, meaning that they allow access to the variables from the domain of the function where they are contained.
The anonymous functions were introduced by Alonzo Church in 1936, in his theory on the lambda calculations. In the programming languages, the anonymous functions were implemented in the year 1958, as part of the Lisp language. In some Aspect Oriented Languages such as Java, there are similar concepts, such as the anonymous classes. It is only in the ٨th version of Java language that the anonymous functions are added. Other languages, such as C#, JavaScript, Perl, Python, Ruby had been offering support for this concept for a long time.
Lambda expressions allow us to create instances of classes with one single method in a much more compact manner.
A lambda expression is made of:
A functional interface is any interface containing only one abstract method. For this reason, we can omit the name of the method when we are implementing the interface and we can eliminate the usage of anonymous classes. Instead, we will have lambda expressions. A functional interface is annotated with @FunctionalInterface.
In order to understand the way of working with lambda expressions, I have built a little example in which I have created collections of objects sorted out according to different criteria. The implementation of the Comparator interface was done in an anonymous class, by using lambda expressions. The implementation with lambda expressions was possible because in version ٨, Comparator is annotated with @FunctionalInterface.
The basic item of the collection is the Product class, which is a POJO class with getters and setters. The class contains two anonymous implementations of the comparator, determining the ascending or decreasing classification of the collection items.
package model;
import java.util.Comparator;
public class Product {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public void printProduct() {
System.out.println(this.toString());
}
@Override
public String toString() {
return "Product [name=" + name + ", price=" +
price + "]";
}
public static Comparator
ascendingPrice = (p1, p2) -> {
return p1.getPrice() - p2.getPrice();
};
public static Comparator
descendingPrice = (p1, p2) -> {
return p2.getPrice() - p1.getPrice();
}
}
The test class will bring something in addition, compared to a class known until version 8. The collection processing will not be done with a classical foreach. As a part of the Collections API, we have the new java.util.stream API, which offers support for functional operations on streams of items. In our example, we will use a basic interface of this API, namely Consumer, which represents a procedure that accepts only one entrance argument and does not return anything. With Consumer, we will be able to use lambda expressions:
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;
import model.Product;
public class TestLambda {
public static void processProducts(
Set products, Consumer block) {
for (Product p : products) {
block.accept(p);
}
}
public static void main(String[] args) {
Product p1 = new Product();
p1.setName("onion");
p1.setPrice(10);
Product p2 = new Product();
p2.setName("tomato");
p2.setPrice(20);
Set ascendingPriceProducts =
new TreeSet<>(
Product.ascendingPrice);
ascendingPriceProducts.add(p1);
ascendingPriceProducts.add(p2);
System.out.println("In ascending order:");
processProducts(ascendingPriceProducts,
p -> p.printProduct());
Set descendingPriceProducts =
new TreeSet<>(Product.descendingPrice);
descendingPriceProducts.add(p1);
descendingPriceProducts.add(p2);
System.out.println("
In descending order:");
processProducts(descendingPriceProducts,
p -> p.printProduct());
}
}
As a consequence of using the stream API, the procedures carried out on a collection can be much more complex than the ones illustrated in the example, namely: filtering by a selection predicate, mapping the filtered object, respectively carrying out an action on every mapped object. I have only presented the last operation. They are called aggregate operations.
I would like to make an observation on the previous code: the implementation of the comparator stands for overwriting of the equals() function, fact that can be proved by the alteration, in the code, at equal values of the price.
Besides the lambda expressions, an important feature, obviously together with the syntactical changes and the introduction of new APIs, is in my opinion the development of the JavaScript Nashorn engine. Through it, one can integrate JavaScript scripts into the classical Java code. This engine is based on the ECMAScript 262 standard. It is an engine written completely from scratch, in view of increasing the performance. Thus, it is completely different from the already existing engine, Rhino.
I will only provide a short example of using this engine, with the promise that in the future I will present more details:
import javax.script.*;
public class EvalScript {
public static void main(String[] args)
throws Exception {
// create a script engine manager
ScriptEngineManager factory =
new ScriptEngineManager();
// create a Nashorn script engine
ScriptEngine engine = factory.
getEngineByName("nashorn");
// evaluate JavaScript statement
try {
engine.eval("print("Hello, World!");");
} catch (final ScriptException se) {
se.printStackTrace();
}
}
}
By running this example, we will get Hello, World! on the console.
As a last observation, I have used Eclipse Kepler for editing and from Marketplace I brought Eclipse Java 8 Support (for Kepler SR2) JDT, PDE 1.0.0. This is only till Eclipse Luna is released (probably in May). As a Java version, I used jdk 1.8.0_05.
I hope to have aroused your interest in Java 8 and, as usually, I am expecting the discussions with those who are interested. My contact is: Silviu.Dumitrescu@accesa.eu.