“Java Standard Edition 8 (Java SE 8)” is released on 18th March 2014. Along with the Java SE 8 platform, the product that implements the platform, “Java SE Development Kit 8 (JDK 8)” and “Java SE Run time Environment 8 (JRE 8)” is also released and available for download.
Java SE 8 is one of the most feature packed release in the Java history. Here let us go through the highlights of the core features of Java 8. Following list is a highlight of important features, there are other minor enhancements, security features, bug fixes are available as part of Java 8.
1) Lambda Expressions
Lambda expressions gives the ability to pass a functionality as a method argument. Lambda expression help us reduce the code clutter in using a single method class. For example, when we have to associate an action button click to a functionality, then lambda expressions will make the code look neat and compact.
2) Pipelines and Streams
Pipelines and streams enrich the Java collections framework. Sequence of aggregate operations is a pipeline. Stream is used to propagate elements from a source through a pipeline. It is a sequence of elements. Pipeline and streams will make our task easier in accessing the elements from collections and applying operations on it.
3) Date and Time API
Pre Java 8, date and time related operations are little bit cumbersome. JSR 310: Date and Time API give us a brand new package java.time package. This is a well thought package. It contains a best list of utility methods used for regular operations. This will help in handling date and time operations in an easier way.
4) Default Methods
Default methods gives the ability to add default implementation for methods in an interface. This is a rocking feature of Java 8. When we implement an interface, if we did not provide implementation for a method, then the default method will be used in that place. This will help in maintaining backward compatibility in applications, we can add a method to an interface without breaking its implementations.
5) Type Annotations
Before Java 8 Java annotations can be applied to type declarations. From this Java 8 release onwards, annotations can be applied to type use. Annotations can be applied wherever a type is used like in new instance creates, exception throws clause etc. This will help to enforce stronger type checks and using this feature we can come up with a type checking framework itself.
6) Nashorn JavaScript Engine
Nashorn is a brand new JavaScript engine provided along with the Java 8 release. Using this we can develop standalone JavaScript applications in Java. Pre Java 8, we got JDK with a JavaScript engine based on Rhino. It is a developed from scratch. It will provide better compatibility with ECMA normalized JavaScript specification and better performance than Rhino.
7) Concurrent Accumulators
java.util.concurrent.atomic package is getting additional classes as part of Java 8 release. These will help to sum values from across multiple threads.
8) Parallel operations
Iterating over a collection can be done in parallel using the aggregate operations easily. Pre Java 8 Iterators are used to parse the elements of a collection one by on explicitly. Now that can be done in parallel internally with the use of streams and aggregate operations. We can create multiple substreams and those substreams can be processed internally in parallel and then the results be combined. For this to be effective, we need to have multiple cores and data volume.
9) PermGen Space Removed
The PermGen space is removed from Java 8 and instead we have MetaSpace introduced. One of the most dreaded error, “java.lang.OutOfMemoryError: PermGen error” will no longer be seen from Java 8. Nice thing is that the MetaSpace default is unlimited and that the system memory itself becomes the memory.
10)TLS SNI
Server Name Indentification (SNI) is an extension of the TLS protocol used for identifying the certificate to serve based on the hostname specified by the client. This enables a server to have virtual host over HTTPS. The same IP address can be used for multiple hosts and their respective different security certificates.
------------------------------------------------------------------------------------------------------------
Java 8 Lambda Expressions
=========================
Lambda expressions, Functional interfaces and Stream API – these three features of Java 8 has turned Java programming into new style of programming called functional-style programming. Java is still an object-oriented programming language, but from Java 8, with the introduction of new features, most of the programming is done keeping functions in mind rather than objects
1) Definition
Java 8 Lambda Expressions can be defined as methods without names i.e anonymous functions. Like methods, they can have parameters, a body, a return type and possible list of exceptions that can be thrown. But unlike methods, neither they have names nor they are associated with any particular class.
2) Lambda Syntax
(Parameters) -> Expression
OR
(Parameters) -> { Statements }
Lambda syntax consist of three parts – list of parameters, an arrow mark and a body. The body of a lambda can be an expression or a set of statements. If it is set of statements, they must be enclosed within curly braces { }. Return type and possible list of exceptions that can be thrown are not explicitly mentioned in a lambda. They are implicitly applied.
3) Where To Use Lambda Expressions?
Lambda expressions are used where an instance of functional interface is expected. Functional interface is an interface which has only one abstract method. Functional interfaces can have any number of default methods. But, they must have only one abstract method. Comparator, Runnable AndActionListener are some examples of functional interfaces.
import java.util.function;
@FunctionalInterface
public interface Comparator
{
int compare(T o1, T o2); //Only one abstract method
}
@FunctionalInterface
public interface Runnable
{
public abstract void run(); //Only one abstract method
}
@FunctionalInterface
public interface ActionListener extends EventListener
{
public void actionPerformed(ActionEvent e); //Only One abstract method
}
Before Java 8, anonymous inner classes are used to implement functional interfaces. After Java 8, you can use lambda expressions to implement functional interfaces.
4) How To Use Lambda Expressions?
Lambda expressions are used to implement functional interfaces. Before Java 8, anonymous inner classes are used to implement functional interfaces.
------------------------------
Before Java 8:
Comparator<Student> idComparator = new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getID()-s2.getID();
}
};
After Java 8 : Implementation of Comaparator interface using lambda expressions
1
Comparator<Student> idComparator = (Student s1, Student s2) -> s1.getID()-s2.getID();
-----------------------------
Before Java 8 :
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Runnable Implementation Using Anonymous Inner Class");
}
};
After Java 8 : Implementation of Runnable interface using lambda expressions
Runnable r = () -> System.out.println("Runnable Implementation Using Lambda Expressions");
----------------------------
Before Java 8 : Implementation Of ActionListener interface using anonymous inner class
Label label = new Label();
Button button = new Button("Send");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("Sent");
}
});
After Java 8 : Implementation of ActionListener interface using lambda expressions
Label label = new Label();
Button button = new Button("Send");
button.addActionListener((ActionEvent e) -> label.setText("Sent..."));
5) Lambdas As Inline Implementation Of Functional Interfaces
From the above examples, you can notice that lambdas instantiate functional interfaces and implement their abstract method in a single line. Before Java 8, anonymous inner classes are used for this purpose. But, they create lots of verbosity i.e you end up writing more lines of code than actually needed.
6) Signature Of Lambda Expressions
The signature of lambda expressions can be derived from the signature of abstract method of functional interface.
For example,
run() method of Runnable interface accepts nothing and returns nothing. Then signature of lambda expression implementing Runnable interface will be () -> void.
actionPerformed() method of ActionListener interface takes one argument of type ActionEvent and returns void. Then signature of lambda expression for implementing ActionListener interface will be (ActionEvent) -> void.
compare() method of Comparator interface takes two arguments of type Object and returns int. Then signature of lambda expression for implementing Comparator interface will be (Object, Object) -> int.
7) Type Checking
The type of a variable or a parameter to which lambda expression is assigned or passed as an argument is called target type.
For example, if you are assigning a lambda to a Runnable type then its target type is Runnable. If you are passing a lambda to a method which takes ActionListener as an argument, then its target type is ActionListener.
Compiler uses this target type to check the type of parameters and return type of a lambda expression. For example,
1
Runnable r = () -> System.out.println("Runnable Implementation Using Lambda Expressions");
In the above code, target type of lambda expression is Runnable. Compiler uses run() method of Runnable interface to check the type of parameters and return type of lambda expression.
1
button.addActionListener((ActionEvent e) -> label.setText("Sent..."));
In the above code, target type of lambda expression is ActionListener. Compiler uses actionPerformed() method of ActionListener to check the type of parameters and return type of lambda expression.
8) Use Of Local Variables Inside Lambda Expression
You can use local variables inside a lambda expression just like anonymous inner classes provided they must be final or effectively final.
For example, the following code will show error because you are re-assigning new Label() to label.
Label label = new Label();
Button button = new Button("Send");
button.addActionListener((ActionEvent e) -> label.setText("Sent...")); //Compile Time Error
label = new Label();
9) Benefits Of Lambda Expressions
Lambda expressions let you to write more clear, concise and flexible code.
Lambda expressions removes verbosity and repetition of code.
10) Valid Lambda Expressions With Description
-------------------------------------------------------------------------------------------------
() -> System.out.println("Hello Nishant"); --- takes nothing return nothing
(int a) -> a*a --- takes int return int
(String s1,String s2) -> { --- takes 2 string and return nothing
System.out.println("Hello");
System.out.println("Nishant");
}
(double d) -> d --- takes double and return double
() -> {} --- takes nothing return nothing (it has empty body)
--------------------------------------------------------------------------------------------------
******* How To Use Java 8 Functional Interfaces In Real Time?
=============================================================
Let’s define Student class like below. We will be using this class in the subsequent examples.
class Student
{
int id;
String name;
double percentage;
String specialization;
// parameterized constructor
public Student(int id, String name, double percentage, String specialization)
{
this.id = id;
this.name = name;
this.percentage = percentage;
this.specialization = specialization;
}
// applying getters
public int getId() {
return id;
}
public String getName() {
return name;
}
public double getPercentage() {
return percentage;
}
public String getSpecialization() {
return specialization;
}
@Override
public String toString()
{
return id+"-"+name+"-"+percentage+"-"+specialization;
}
}
Now, Let's create listOfStudents be the list of 10 students.
List<Student> listOfStudents = new ArrayList<Student>();
listOfStudents.add(new Student(111, "John", 81.0, "Mathematics"));
listOfStudents.add(new Student(222, "Harsha", 79.5, "History"));
listOfStudents.add(new Student(333, "Ruth", 87.2, "Computers"));
listOfStudents.add(new Student(444, "Aroma", 63.2, "Mathematics"));
listOfStudents.add(new Student(555, "Zade", 83.5, "Computers"));
listOfStudents.add(new Student(666, "Xing", 58.5, "Geography"));
listOfStudents.add(new Student(777, "Richards", 72.6, "Banking"));
listOfStudents.add(new Student(888, "Sunil", 86.7, "History"));
listOfStudents.add(new Student(999, "Jordan", 58.6, "Finance"));
listOfStudents.add(new Student(101010, "Chris", 89.8, "Computers"));
Now, see how to use 4 important functional interfaces – Predicate, Consumer, Function and Supplier using above listOfStudents.
a) Predicate – Tests an object
Predicate represents an operation which takes an argument T and returns a boolean. Use this functional interface, if you want to define a lambda expression which performs some test on an argument and returns true or false depending upon outcome of the test.
For example,
Imagine an operation where you want only a list of “Mathematics” students from the above listOfStudents. Let’s see how to do it using Predicate.
----------------------------------------------------------------
Predicate<Student> mathematicsPredicate = (Student student) -> student.getSpecialization().equals("Mathematics");
List<Student> mathematicsStudents = new ArrayList<Student>();
for (Student student : listOfStudents)
{
if (mathematicsPredicate.test(student))
{
mathematicsStudents.add(student);
}
}
b) Consumer – Consumes an object
Consumer represents an operation which takes an argument and returns nothing. Use this functional interface If you want to compose a lambda expression which performs some operations on an object.
For example, displaying all students with their percentage.
Lambda expression implementing Consumer : Displaying all students with their percentage
---------------------------------------------------------------------------------------
Consumer<Student> percentageConsumer = (Student student) -> {
System.out.println(student.getName()+" : "+student.getPercentage());
};
for (Student student : listOfStudents)
{
percentageConsumer.accept(student);
}
c) Function – Applies to an object
Function represents an operation which takes an argument of type T and returns a result of type R. Use this functional interface if you want to extract some data from an existing data.
For example, extracting only the names from listOfStudents.
-----------------------------------------------------------
Function<Student, String> nameFunction = (Student Student) -> Student.getName();
List<String> studentNames = new ArrayList<String>();
for (Student student : listOfStudents)
{
studentNames.add(nameFunction.apply(student));
}
d) Supplier – Supplies the objects
Supplier represents an operation which takes no argument and returns the results of type R. Use this functional interface when you want to create new objects.
Lambda expression implementing Supplier : Creating a new Student
----------------------------------------------------------------
Supplier<Student> studentSupplier = () -> new Student(111111, "New Student", 92.9, "Java 8");
listOfStudents.add(studentSupplier.get());
5) Functional Interfaces Supporting Primitive Type
Java 8 has also introduced functional interfaces which support primitive types.
For example IntPredicate, DoublePredicate, LongConsumer etc… (See above table).
If an input or output is a primitive type then using these functional interfaces will enhance the performance of your code.
For example, if input to a Predicate is primitive type int then using intPredicate instead of Predicate will remove unnecessary boxing of input.
******* What is Java 8 Method References In Real Time?
======================================================
1) Definition
Java 8 method references are the shortened versions of lambda expressions calling a specific method.
Method references are the easiest way to refer a method than the lambdas calling a specific method.
Method references will enhance the readability of your code.
For example, lambda expression (Student s) -> s.getName()
which is calling a method getName() of Student class can be shortened as Student::getName using Java 8 method references.
2) Syntax
a) Method reference to static method :
ClassName::MethodName
Use this syntax when you are referring to a static method.
ex : Integer::parseInt, Math::max
b) Method reference to instance method of an existing object :
ReferenceVariable::MethodName
Use this syntax when you are referring to an instance method of already existing object.
ex : s::getName
where ‘s’ is a reference variable referring to Student object which already exist.
c) Method reference to instance method of non-existing object :
ClassName::MethodName
Use this syntax when you are referring to an instance method by passing reference variables as an argument.
ex : (Student s) -> s.getName() can be written as Student::getName
3) Constructor References
You can also refer to the constructor of a class same as method references. Syntax for referring to constructor is,
ClassName::new
Ex : Student::new
Following : javaconceptoftheday
************ What is Java 8 Interface Changes : Default Methods And Static Methods
It has been a tough task for Java API developers to add new methods to current interfaces. Because, even if you add a single abstract method to an interface, all existing implementations of that interface have to be updated with implementation of new method. What if there exist hundreds or thousands of implementations of an interface? Even worse, What if you don’t have control over all of those implementations? To overcome such overhead, new features are introduced to interfaces from Java 8. They are default methods and static methods. In this article, we will see these new Java 8 Interface Changes.
From Java 8, interfaces can also have concrete methods i.e methods with body along with abstract methods. This is the major change introduced to interfaces in Java 8 to help Java API developers to update and maintain the interfaces. The interfaces can have concrete methods either in the form of default methods or static methods.
A) Default Methods
------------------
1) Definition With Example
Default methods of an interface are the concrete methods i.e methods with body for which implementing classes need not to give implementation. They inherit default implementation. Default methods start with the modifier default.
interface InterfaceWithDefaultMethod
{
void abstractMethod(); //Abstract Method
default void defaultMethod()
{
System.out.println("It is a default method");
}
}
class AnyClass implements InterfaceWithDefaultMethod
{
@Override
public void abstractMethod()
{
System.out.println("Abstract Method implemented");
}
//No need to implement defaultMethod()
}
2) Why Default Methods?
Default methods are introduced to add extra features to current interfaces without disrupting their existing implementations.
For example, stream() is a default method which is added to Collection interface in Java 8.
If stream() would have been added as abstract method, then all classes implementing Collection interface must have implemented stream() method which may have irritated existing users.
Thanks to Java 8 default method feature, now it is a default method, all implementations of Collection interface inherit default implementation of stream() method.
3) Three Rules To Solve Diamond Problem
In Java, a class can extend only one class but can implement multiple interfaces. With the introduction of default methods, it is possible that your class inherit multiple methods with same signature. In such scenarios, to solve the conflict, Java 8 specifies 3 rules to follow.
Rule 1 : Select classes over interfaces
If your class inherit multiple methods with same signature then a method from super class is selected (Remember a class can inherit only one class).
interface InterfaceOne
{
default void anyMethod()
{
System.out.println("Hi... From Interface One");
}
}
interface InterfaceTwo extends InterfaceOne
{
@Override
default void anyMethod()
{
System.out.println("Hi... From Interface Two");
}
}
class ClassOne implements InterfaceOne, InterfaceTwo
{
@Override
public void anyMethod()
{
System.out.println("Hi... From Class One");
}
}
public class MyClass extends ClassOne implements InterfaceOne, InterfaceTwo
{
public static void main(String[] args)
{
new MyClass().anyMethod();
}
}
output : Hi... From Class One
Rule 2 : Select most specific interfaces than general interfaces.
If your class doesn’t extend any class and inherit multiple methods with same signature from multiple interfaces which belong to same hierarchy, then a method from most specific interface is selected (If interface X extends Y then X is more specific than Y).
For example, In the below program, anyMethod() from InterfaceTwo is called.
interface InterfaceOne
{
default void anyMethod()
{
System.out.println("Hi... From Interface One");
}
}
interface InterfaceTwo extends InterfaceOne
{
@Override
default void anyMethod()
{
System.out.println("Hi... From Interface Two");
}
}
public class MyClass implements InterfaceOne, InterfaceTwo
{
public static void main(String[] args)
{
new MyClass().anyMethod();
}
}
output : Hi... From Interface Two
Rule 3 : InterfaceName.super.methodName()
If your class doesn’t extend any class and inherit multiple methods with same signature from multiple interfaces which doesn’t belong to same hierarchy, then override that method and from within body explicitly call desired method as InterfaceName.super.methodName().
For example, in the below program, anyMethod() from InterfaceOne is called explicitly.
interface InterfaceOne
{
default void anyMethod()
{
System.out.println("Hi... From Interface One");
}
}
interface InterfaceTwo
{
default void anyMethod()
{
System.out.println("Hi... From Interface Two");
}
}
public class MyClass implements InterfaceOne, InterfaceTwo
{
@Override
public void anyMethod()
{
InterfaceOne.super.anyMethod();
}
public static void main(String[] args)
{
new MyClass().anyMethod();
}
}
output : Hi... From Interface One
B) Static Methods
-----------------
1) Definition With Example
From Java 8, interfaces can also have static methods. Static methods are also concrete methods but they can’t be implemented.
interface InterfaceWithDefaultAndStaticMethod
{
void abstractMethod(); //Abstract Method
default void defaultMethod()
{
System.out.println("It is a default method");
}
static void staticMethod()
{
System.out.println("It is a static method");
}
}
class AnyClass implements InterfaceWithDefaultAndStaticMethod
{
@Override
public void abstractMethod()
{
System.out.println("Abstract Method implemented");
}
//No need to implement defaultMethod()
//Can't implement staticMethod()
}
2) Why Static Methods?
Do you know? Collection and Collections.
Collection is an interface and Collections is an utility class containing only static methods which operate on Collection objects.
Java API developers have followed this pattern of supplying an utility class along with an interface to perform basic operations on such objects. But from Java 8, they have break this pattern by introducing static methods to interfaces.
With the introduction of static methods to interface, such utility classes will disappear and methods to perform basic operations will be kept as static methods in interface itself.
**************** What is the difference between Collections And Streams In Java 8
================================================================
Collections are used to store and group the data in a particular data structure like List, Set or Map. But, streams are used to perform complex data processing operations like filtering, matching, mapping etc on stored data such as arrays, collections or I/O resources. That means, collections are mainly about data and streams are mainly about operations on data.
1) The Difference
//Usage of collections
//Collections are mainly used to store the data
//Here, names are stored as List
List<String> names = new ArrayList<>();
names.add("Charlie");
names.add("Douglas");
names.add("Sundaraman");
names.add("Charlie");
names.add("Yuki");
//Usage of streams
//Streams are mainly used to perform operations on data
//like selecting only unique names
names.stream().distinct().forEach(System.out::println);
//Output :
//Charlie
//Douglas
//Sundaraman
//Yuki
2) Data Modification
You can add to or remove elements from collections. But, you can’t add to or remove elements from streams. Stream consumes a source, performs operations on it and returns a result. They don’t modify even the source also.
List<String> names = Arrays.asList("Charlie", "Douglas", "Jacob");
//Adding elements to names
names.add("Sundaraman");
names.add("Yuki");
//Removing elements from names
names.remove(2);
//getting stream of unique names
Stream<String> uniqueNames = names.stream().distinct();
//You can't add or remove elements from stream
//There are no such methods in Stream
3) External Iteration Vs Internal Iteration
The main specialty of Java 8 Streams is that you need not to worry about iteration while using streams. Streams perform iteration internally behind the scene for you. You just have to mention the operations to be performed on a source.
On the other hand, you have to do the iteration externally over collections using loops.
List<String> names = new ArrayList<>();
names.add("Charlie");
names.add("Douglas");
names.add("Sundaraman");
names.add("Charlie");
names.add("Yuki");
//External iteration of collections
for (String name : names)
{
System.out.println(name);
}
//Output :
//Charlie
//Douglas
//Sundaraman
//Charlie
//Yuki
//Internal iteration of streams. No for loops
names.stream().map(String::toUpperCase).forEach(System.out::println);
//Output :
//CHARLIE
//DOUGLAS
//SUNDARAMAN
//CHARLIE
//YUKI
4) Traversal
Streams are traversable only once. If you traverse the stream once, it is said to be consumed. To traverse it again, you have to get new stream from the source again. But, collections can be traversed multiple times.
List<Integer> numbers = Arrays.asList(4, 2, 8, 9, 5, 6, 7);
Stream<Integer> numbersGreaterThan5 = numbers.stream().filter(i -> i > 5);
//Traversing numbersGreaterThan5 stream first time
numbersGreaterThan5.forEach(System.out::println);
//Second time traversal will throw error
//Error : stream has already been operated upon or closed
numbersGreaterThan5.forEach(System.out::println);
5) Eager Construction Vs Lazy Construction
Collections are eagerly constructed i.e all the elements are computed at the beginning itself. But, streams are lazily constructed i.e intermediate operations are not evaluated until terminal operation is invoked.
List<Integer> numbers = Arrays.asList(4, 2, 8, 9, 5, 6, 7);
numbers.stream().filter(i -> i >= 5).limit(3).forEach(System.out::println);
//Here, not all numbers are evaluated.
//numbers are evaluated until 3 numbers >= 5 are found.
//Output :
//8
//9
//5
*************** What is the Difference Between Collections Vs Streams In Java :
Collections Streams
-----------------------------------------------------------------------------------------------------------------
Collections are mainly used to store and group the data. Streams are mainly used to perform operations on data.
You can add or remove elements from collections. You can’t add or remove elements from streams.
Collections have to be iterated externally. Streams are internally iterated.
Collections can be traversed multiple times. Streams are traversable only once.
Collections are eagerly constructed. Streams are lazily constructed.
Ex : List, Set, Map… Ex : filtering, mapping, matching…
-----------------------------------------------------------------------------------------------------------------
Java 8 Stream in details
========================
1) What Are Streams?
Streams can be defined as a sequences of elements from a source which support data processing operations. You can treat streams as operations on data. You will get to know as you go through this article.
2) Why Streams?
Almost every Java application use Collections API to store and process the data. Despite being the most used Java API, it is not easy to write the code for even some common data processing operations like filtering, finding, matching, sorting, mapping etc using Collections API . So, there needed Next-Gen API to process the data. So Java API designers have come with Java 8 Streams API to write more complex data processing operations with much of ease.
3) Characteristics Of Java 8 Streams
3.1) Streams are not the data structures
Streams doesn’t store the data. You can’t add or remove elements from streams. Hence, they are not the data structures. They are the just operations on data.
3.2) Stream Consumes a data source
Stream consumes a source, performs operations on it and produces the result. Source may be a collection or an array or an I/O resource. Remember, stream doesn’t modify the source.
3.3) Intermediate And Terminal Operations
Most of the stream operations return another new stream and they can be chained together to form a pipeline of operations.
The operations which return stream themselves are called intermediate operations. For example – filter(), distinct(), sorted() etc.
The operations which return other than stream are called terminal operations. count(). min(), max() are some terminal operations.
3.4) Pipeline Of Operations
A pipeline of operations consists of three things – a source, one or more intermediate operations and a terminal operation. Pipe-lining of operations let you to write database-like queries on a data source. In the below example, int array is the source, filter() and distinct() are intermediate operations and forEach() is a terminal operation.
IntStream.of(new int[] {4, 7, 1, 8, 3, 9, 7}).filter((int i) -> i > 5).distinct().forEach(System.out::println);
3.5) Internal Iteration
Collections need to be iterated explicitly. i.e you have to write the code to iterate over collections. But, all stream operations do the iteration internally behind the scene for you. You need not to worry about iteration at all while writing the code using Java 8 Streams API.
3.6) Parallel Execution
To gain the performance while processing the large amount of data, you have to process it in parallel and use multi core architectures. Java 8 Streams can be processed in parallel without writing any multi threaded code. For example, to process the collections in parallel, you just use parallelStream() method instead of stream() method.
List<String> names = new ArrayList<>();
names.add("David");
names.add("Johnson");
names.add("Samontika");
names.add("Brijesh");
names.add("John");
//Normal Execution
names.stream().filter((String name) -> name.length() > 5).skip(2).forEach(System.out::println);
//Parallel Execution
names.parallelStream().filter((String name) -> name.length() > 5).skip(2).forEach(System.out::println);
3.7) Streams are lazily populated
All elements of a stream are not populated at a time. They are lazily populated as per demand because intermediate operations are not evaluated until terminal operation is invoked.
3.8) Streams are traversable only once
You can’t traverse the streams more than once just like iterators. If you traverse the stream first time, it is said to be consumed.
List<String> nameList = Arrays.asList("Dinesh", "Ross", "Kagiso", "Steyn");
Stream<String> stream = nameList.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);
//Error : stream has already been operated upon or closed
3.9) Short Circuiting Operations
Short circuiting operations are the operations which don’t need the whole stream to be processed to produce a result. For example – findFirst(), findAny(), limit() etc.
********** What is the Differences Between Interface And Abstract Class After Java 8 :
==================================================================
1) Fields
Interface fields are public, static and final by default. Interfaces still don’t support non-static and non-final variables. Interfaces can only have public, static and final variables. On the other hand, abstract class can have static as well as non-static and final as well as non-final variables. They also support private and protected variables along with public variables.
2) Methods
After Java 8, an interface can have default and static methods along with abstract methods. Interfaces don’t support final methods. But, abstract classes support final as well as non-final methods and static as well as non-static methods along with abstract methods.
Also note that, only interfaces can have default methods. Abstract classes can’t have default methods.
3) Constructors
Interfaces can’t have constructors. Abstract classes can have any number of constructors.
4) Member’s Accessibility
All members of interfaces are public by default. Interfaces don’t support private and protected members. But, abstract classes support all type of members – private, protected and public members.
5) Multiple Inheritance
A class can extend only one abstract class, but can implement multiple interfaces. Thus, a class can inherit multiple properties from multiple sources only through interfaces, not through abstract classes.
interface anyInterface
{
int i = 10; //By default, interface fields are public, static and final
void abstractMethod(); //Interface can have abstract method
default void defaultMethod()
{
System.out.println("Interface can have default method");
}
static void staticMethod()
{
System.out.println("Interface can have static method");
}
//No constructors in an interface
//No non-static and non-final variables in an interface
//No private fields and methods in an interface
//No protected fields and methods in an interface
//No final methods in an interface
}
abstract class anyAbstractClass
{
private int a; //Abstract class can have private field
protected int b; //Abstract class can have protected field
public int c; //Abstract class can have public field
static int d; //Abstract class can have static field
final int e = 10; //Abstract class can have final field
int f; //Abstract class can have non-static and non-final field
public anyAbstractClass()
{
System.out.println("Abstract class can have constructors");
}
abstract void abstractmethod(); //Abstract class can have abstract method
private static void staticMethod()
{
System.out.println("Abstract class can have private and static method");
}
public void nonStaticMethod()
{
System.out.println("Abstract class can have public and non-static method");
}
protected void protectedMethod()
{
System.out.println("Abstract class can have protected method");
}
final void finalMethod()
{
System.out.println("Abstract class can have final method");
}
//No default method in an abstract class
}
https://javaconceptoftheday.com/java-8-streams-beginners-guide/
https://javaconceptoftheday.com/java-8-collectors-tutorial/
https://javaconceptoftheday.com/solving-real-time-queries-using-java-8-features-employee-management-system/
Java SE 8 is one of the most feature packed release in the Java history. Here let us go through the highlights of the core features of Java 8. Following list is a highlight of important features, there are other minor enhancements, security features, bug fixes are available as part of Java 8.
1) Lambda Expressions
Lambda expressions gives the ability to pass a functionality as a method argument. Lambda expression help us reduce the code clutter in using a single method class. For example, when we have to associate an action button click to a functionality, then lambda expressions will make the code look neat and compact.
2) Pipelines and Streams
Pipelines and streams enrich the Java collections framework. Sequence of aggregate operations is a pipeline. Stream is used to propagate elements from a source through a pipeline. It is a sequence of elements. Pipeline and streams will make our task easier in accessing the elements from collections and applying operations on it.
3) Date and Time API
Pre Java 8, date and time related operations are little bit cumbersome. JSR 310: Date and Time API give us a brand new package java.time package. This is a well thought package. It contains a best list of utility methods used for regular operations. This will help in handling date and time operations in an easier way.
4) Default Methods
Default methods gives the ability to add default implementation for methods in an interface. This is a rocking feature of Java 8. When we implement an interface, if we did not provide implementation for a method, then the default method will be used in that place. This will help in maintaining backward compatibility in applications, we can add a method to an interface without breaking its implementations.
5) Type Annotations
Before Java 8 Java annotations can be applied to type declarations. From this Java 8 release onwards, annotations can be applied to type use. Annotations can be applied wherever a type is used like in new instance creates, exception throws clause etc. This will help to enforce stronger type checks and using this feature we can come up with a type checking framework itself.
6) Nashorn JavaScript Engine
Nashorn is a brand new JavaScript engine provided along with the Java 8 release. Using this we can develop standalone JavaScript applications in Java. Pre Java 8, we got JDK with a JavaScript engine based on Rhino. It is a developed from scratch. It will provide better compatibility with ECMA normalized JavaScript specification and better performance than Rhino.
7) Concurrent Accumulators
java.util.concurrent.atomic package is getting additional classes as part of Java 8 release. These will help to sum values from across multiple threads.
8) Parallel operations
Iterating over a collection can be done in parallel using the aggregate operations easily. Pre Java 8 Iterators are used to parse the elements of a collection one by on explicitly. Now that can be done in parallel internally with the use of streams and aggregate operations. We can create multiple substreams and those substreams can be processed internally in parallel and then the results be combined. For this to be effective, we need to have multiple cores and data volume.
9) PermGen Space Removed
The PermGen space is removed from Java 8 and instead we have MetaSpace introduced. One of the most dreaded error, “java.lang.OutOfMemoryError: PermGen error” will no longer be seen from Java 8. Nice thing is that the MetaSpace default is unlimited and that the system memory itself becomes the memory.
10)TLS SNI
Server Name Indentification (SNI) is an extension of the TLS protocol used for identifying the certificate to serve based on the hostname specified by the client. This enables a server to have virtual host over HTTPS. The same IP address can be used for multiple hosts and their respective different security certificates.
------------------------------------------------------------------------------------------------------------
Java 8 Lambda Expressions
=========================
Lambda expressions, Functional interfaces and Stream API – these three features of Java 8 has turned Java programming into new style of programming called functional-style programming. Java is still an object-oriented programming language, but from Java 8, with the introduction of new features, most of the programming is done keeping functions in mind rather than objects
1) Definition
Java 8 Lambda Expressions can be defined as methods without names i.e anonymous functions. Like methods, they can have parameters, a body, a return type and possible list of exceptions that can be thrown. But unlike methods, neither they have names nor they are associated with any particular class.
2) Lambda Syntax
(Parameters) -> Expression
OR
(Parameters) -> { Statements }
Lambda syntax consist of three parts – list of parameters, an arrow mark and a body. The body of a lambda can be an expression or a set of statements. If it is set of statements, they must be enclosed within curly braces { }. Return type and possible list of exceptions that can be thrown are not explicitly mentioned in a lambda. They are implicitly applied.
3) Where To Use Lambda Expressions?
Lambda expressions are used where an instance of functional interface is expected. Functional interface is an interface which has only one abstract method. Functional interfaces can have any number of default methods. But, they must have only one abstract method. Comparator, Runnable AndActionListener are some examples of functional interfaces.
import java.util.function;
@FunctionalInterface
public interface Comparator
{
int compare(T o1, T o2); //Only one abstract method
}
@FunctionalInterface
public interface Runnable
{
public abstract void run(); //Only one abstract method
}
@FunctionalInterface
public interface ActionListener extends EventListener
{
public void actionPerformed(ActionEvent e); //Only One abstract method
}
Before Java 8, anonymous inner classes are used to implement functional interfaces. After Java 8, you can use lambda expressions to implement functional interfaces.
4) How To Use Lambda Expressions?
Lambda expressions are used to implement functional interfaces. Before Java 8, anonymous inner classes are used to implement functional interfaces.
------------------------------
Before Java 8:
Comparator<Student> idComparator = new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getID()-s2.getID();
}
};
After Java 8 : Implementation of Comaparator interface using lambda expressions
1
Comparator<Student> idComparator = (Student s1, Student s2) -> s1.getID()-s2.getID();
-----------------------------
Before Java 8 :
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Runnable Implementation Using Anonymous Inner Class");
}
};
After Java 8 : Implementation of Runnable interface using lambda expressions
Runnable r = () -> System.out.println("Runnable Implementation Using Lambda Expressions");
----------------------------
Before Java 8 : Implementation Of ActionListener interface using anonymous inner class
Label label = new Label();
Button button = new Button("Send");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("Sent");
}
});
After Java 8 : Implementation of ActionListener interface using lambda expressions
Label label = new Label();
Button button = new Button("Send");
button.addActionListener((ActionEvent e) -> label.setText("Sent..."));
5) Lambdas As Inline Implementation Of Functional Interfaces
From the above examples, you can notice that lambdas instantiate functional interfaces and implement their abstract method in a single line. Before Java 8, anonymous inner classes are used for this purpose. But, they create lots of verbosity i.e you end up writing more lines of code than actually needed.
6) Signature Of Lambda Expressions
The signature of lambda expressions can be derived from the signature of abstract method of functional interface.
For example,
run() method of Runnable interface accepts nothing and returns nothing. Then signature of lambda expression implementing Runnable interface will be () -> void.
actionPerformed() method of ActionListener interface takes one argument of type ActionEvent and returns void. Then signature of lambda expression for implementing ActionListener interface will be (ActionEvent) -> void.
compare() method of Comparator interface takes two arguments of type Object and returns int. Then signature of lambda expression for implementing Comparator interface will be (Object, Object) -> int.
7) Type Checking
The type of a variable or a parameter to which lambda expression is assigned or passed as an argument is called target type.
For example, if you are assigning a lambda to a Runnable type then its target type is Runnable. If you are passing a lambda to a method which takes ActionListener as an argument, then its target type is ActionListener.
Compiler uses this target type to check the type of parameters and return type of a lambda expression. For example,
1
Runnable r = () -> System.out.println("Runnable Implementation Using Lambda Expressions");
In the above code, target type of lambda expression is Runnable. Compiler uses run() method of Runnable interface to check the type of parameters and return type of lambda expression.
1
button.addActionListener((ActionEvent e) -> label.setText("Sent..."));
In the above code, target type of lambda expression is ActionListener. Compiler uses actionPerformed() method of ActionListener to check the type of parameters and return type of lambda expression.
8) Use Of Local Variables Inside Lambda Expression
You can use local variables inside a lambda expression just like anonymous inner classes provided they must be final or effectively final.
For example, the following code will show error because you are re-assigning new Label() to label.
Label label = new Label();
Button button = new Button("Send");
button.addActionListener((ActionEvent e) -> label.setText("Sent...")); //Compile Time Error
label = new Label();
9) Benefits Of Lambda Expressions
Lambda expressions let you to write more clear, concise and flexible code.
Lambda expressions removes verbosity and repetition of code.
10) Valid Lambda Expressions With Description
-------------------------------------------------------------------------------------------------
() -> System.out.println("Hello Nishant"); --- takes nothing return nothing
(int a) -> a*a --- takes int return int
(String s1,String s2) -> { --- takes 2 string and return nothing
System.out.println("Hello");
System.out.println("Nishant");
}
(double d) -> d --- takes double and return double
() -> {} --- takes nothing return nothing (it has empty body)
--------------------------------------------------------------------------------------------------
******* How To Use Java 8 Functional Interfaces In Real Time?
=============================================================
Let’s define Student class like below. We will be using this class in the subsequent examples.
class Student
{
int id;
String name;
double percentage;
String specialization;
// parameterized constructor
public Student(int id, String name, double percentage, String specialization)
{
this.id = id;
this.name = name;
this.percentage = percentage;
this.specialization = specialization;
}
// applying getters
public int getId() {
return id;
}
public String getName() {
return name;
}
public double getPercentage() {
return percentage;
}
public String getSpecialization() {
return specialization;
}
@Override
public String toString()
{
return id+"-"+name+"-"+percentage+"-"+specialization;
}
}
Now, Let's create listOfStudents be the list of 10 students.
List<Student> listOfStudents = new ArrayList<Student>();
listOfStudents.add(new Student(111, "John", 81.0, "Mathematics"));
listOfStudents.add(new Student(222, "Harsha", 79.5, "History"));
listOfStudents.add(new Student(333, "Ruth", 87.2, "Computers"));
listOfStudents.add(new Student(444, "Aroma", 63.2, "Mathematics"));
listOfStudents.add(new Student(555, "Zade", 83.5, "Computers"));
listOfStudents.add(new Student(666, "Xing", 58.5, "Geography"));
listOfStudents.add(new Student(777, "Richards", 72.6, "Banking"));
listOfStudents.add(new Student(888, "Sunil", 86.7, "History"));
listOfStudents.add(new Student(999, "Jordan", 58.6, "Finance"));
listOfStudents.add(new Student(101010, "Chris", 89.8, "Computers"));
Now, see how to use 4 important functional interfaces – Predicate, Consumer, Function and Supplier using above listOfStudents.
a) Predicate – Tests an object
Predicate represents an operation which takes an argument T and returns a boolean. Use this functional interface, if you want to define a lambda expression which performs some test on an argument and returns true or false depending upon outcome of the test.
For example,
Imagine an operation where you want only a list of “Mathematics” students from the above listOfStudents. Let’s see how to do it using Predicate.
----------------------------------------------------------------
Predicate<Student> mathematicsPredicate = (Student student) -> student.getSpecialization().equals("Mathematics");
List<Student> mathematicsStudents = new ArrayList<Student>();
for (Student student : listOfStudents)
{
if (mathematicsPredicate.test(student))
{
mathematicsStudents.add(student);
}
}
b) Consumer – Consumes an object
Consumer represents an operation which takes an argument and returns nothing. Use this functional interface If you want to compose a lambda expression which performs some operations on an object.
For example, displaying all students with their percentage.
Lambda expression implementing Consumer : Displaying all students with their percentage
---------------------------------------------------------------------------------------
Consumer<Student> percentageConsumer = (Student student) -> {
System.out.println(student.getName()+" : "+student.getPercentage());
};
for (Student student : listOfStudents)
{
percentageConsumer.accept(student);
}
c) Function – Applies to an object
Function represents an operation which takes an argument of type T and returns a result of type R. Use this functional interface if you want to extract some data from an existing data.
For example, extracting only the names from listOfStudents.
-----------------------------------------------------------
Function<Student, String> nameFunction = (Student Student) -> Student.getName();
List<String> studentNames = new ArrayList<String>();
for (Student student : listOfStudents)
{
studentNames.add(nameFunction.apply(student));
}
d) Supplier – Supplies the objects
Supplier represents an operation which takes no argument and returns the results of type R. Use this functional interface when you want to create new objects.
Lambda expression implementing Supplier : Creating a new Student
----------------------------------------------------------------
Supplier<Student> studentSupplier = () -> new Student(111111, "New Student", 92.9, "Java 8");
listOfStudents.add(studentSupplier.get());
5) Functional Interfaces Supporting Primitive Type
Java 8 has also introduced functional interfaces which support primitive types.
For example IntPredicate, DoublePredicate, LongConsumer etc… (See above table).
If an input or output is a primitive type then using these functional interfaces will enhance the performance of your code.
For example, if input to a Predicate is primitive type int then using intPredicate instead of Predicate will remove unnecessary boxing of input.
******* What is Java 8 Method References In Real Time?
======================================================
1) Definition
Java 8 method references are the shortened versions of lambda expressions calling a specific method.
Method references are the easiest way to refer a method than the lambdas calling a specific method.
Method references will enhance the readability of your code.
For example, lambda expression (Student s) -> s.getName()
which is calling a method getName() of Student class can be shortened as Student::getName using Java 8 method references.
2) Syntax
a) Method reference to static method :
ClassName::MethodName
Use this syntax when you are referring to a static method.
ex : Integer::parseInt, Math::max
b) Method reference to instance method of an existing object :
ReferenceVariable::MethodName
Use this syntax when you are referring to an instance method of already existing object.
ex : s::getName
where ‘s’ is a reference variable referring to Student object which already exist.
c) Method reference to instance method of non-existing object :
ClassName::MethodName
Use this syntax when you are referring to an instance method by passing reference variables as an argument.
ex : (Student s) -> s.getName() can be written as Student::getName
3) Constructor References
You can also refer to the constructor of a class same as method references. Syntax for referring to constructor is,
ClassName::new
Ex : Student::new
Following : javaconceptoftheday
************ What is Java 8 Interface Changes : Default Methods And Static Methods
It has been a tough task for Java API developers to add new methods to current interfaces. Because, even if you add a single abstract method to an interface, all existing implementations of that interface have to be updated with implementation of new method. What if there exist hundreds or thousands of implementations of an interface? Even worse, What if you don’t have control over all of those implementations? To overcome such overhead, new features are introduced to interfaces from Java 8. They are default methods and static methods. In this article, we will see these new Java 8 Interface Changes.
From Java 8, interfaces can also have concrete methods i.e methods with body along with abstract methods. This is the major change introduced to interfaces in Java 8 to help Java API developers to update and maintain the interfaces. The interfaces can have concrete methods either in the form of default methods or static methods.
A) Default Methods
------------------
1) Definition With Example
Default methods of an interface are the concrete methods i.e methods with body for which implementing classes need not to give implementation. They inherit default implementation. Default methods start with the modifier default.
interface InterfaceWithDefaultMethod
{
void abstractMethod(); //Abstract Method
default void defaultMethod()
{
System.out.println("It is a default method");
}
}
class AnyClass implements InterfaceWithDefaultMethod
{
@Override
public void abstractMethod()
{
System.out.println("Abstract Method implemented");
}
//No need to implement defaultMethod()
}
2) Why Default Methods?
Default methods are introduced to add extra features to current interfaces without disrupting their existing implementations.
For example, stream() is a default method which is added to Collection interface in Java 8.
If stream() would have been added as abstract method, then all classes implementing Collection interface must have implemented stream() method which may have irritated existing users.
Thanks to Java 8 default method feature, now it is a default method, all implementations of Collection interface inherit default implementation of stream() method.
3) Three Rules To Solve Diamond Problem
In Java, a class can extend only one class but can implement multiple interfaces. With the introduction of default methods, it is possible that your class inherit multiple methods with same signature. In such scenarios, to solve the conflict, Java 8 specifies 3 rules to follow.
Rule 1 : Select classes over interfaces
If your class inherit multiple methods with same signature then a method from super class is selected (Remember a class can inherit only one class).
interface InterfaceOne
{
default void anyMethod()
{
System.out.println("Hi... From Interface One");
}
}
interface InterfaceTwo extends InterfaceOne
{
@Override
default void anyMethod()
{
System.out.println("Hi... From Interface Two");
}
}
class ClassOne implements InterfaceOne, InterfaceTwo
{
@Override
public void anyMethod()
{
System.out.println("Hi... From Class One");
}
}
public class MyClass extends ClassOne implements InterfaceOne, InterfaceTwo
{
public static void main(String[] args)
{
new MyClass().anyMethod();
}
}
output : Hi... From Class One
Rule 2 : Select most specific interfaces than general interfaces.
If your class doesn’t extend any class and inherit multiple methods with same signature from multiple interfaces which belong to same hierarchy, then a method from most specific interface is selected (If interface X extends Y then X is more specific than Y).
For example, In the below program, anyMethod() from InterfaceTwo is called.
interface InterfaceOne
{
default void anyMethod()
{
System.out.println("Hi... From Interface One");
}
}
interface InterfaceTwo extends InterfaceOne
{
@Override
default void anyMethod()
{
System.out.println("Hi... From Interface Two");
}
}
public class MyClass implements InterfaceOne, InterfaceTwo
{
public static void main(String[] args)
{
new MyClass().anyMethod();
}
}
output : Hi... From Interface Two
Rule 3 : InterfaceName.super.methodName()
If your class doesn’t extend any class and inherit multiple methods with same signature from multiple interfaces which doesn’t belong to same hierarchy, then override that method and from within body explicitly call desired method as InterfaceName.super.methodName().
For example, in the below program, anyMethod() from InterfaceOne is called explicitly.
interface InterfaceOne
{
default void anyMethod()
{
System.out.println("Hi... From Interface One");
}
}
interface InterfaceTwo
{
default void anyMethod()
{
System.out.println("Hi... From Interface Two");
}
}
public class MyClass implements InterfaceOne, InterfaceTwo
{
@Override
public void anyMethod()
{
InterfaceOne.super.anyMethod();
}
public static void main(String[] args)
{
new MyClass().anyMethod();
}
}
output : Hi... From Interface One
B) Static Methods
-----------------
1) Definition With Example
From Java 8, interfaces can also have static methods. Static methods are also concrete methods but they can’t be implemented.
interface InterfaceWithDefaultAndStaticMethod
{
void abstractMethod(); //Abstract Method
default void defaultMethod()
{
System.out.println("It is a default method");
}
static void staticMethod()
{
System.out.println("It is a static method");
}
}
class AnyClass implements InterfaceWithDefaultAndStaticMethod
{
@Override
public void abstractMethod()
{
System.out.println("Abstract Method implemented");
}
//No need to implement defaultMethod()
//Can't implement staticMethod()
}
2) Why Static Methods?
Do you know? Collection and Collections.
Collection is an interface and Collections is an utility class containing only static methods which operate on Collection objects.
Java API developers have followed this pattern of supplying an utility class along with an interface to perform basic operations on such objects. But from Java 8, they have break this pattern by introducing static methods to interfaces.
With the introduction of static methods to interface, such utility classes will disappear and methods to perform basic operations will be kept as static methods in interface itself.
**************** What is the difference between Collections And Streams In Java 8
================================================================
Collections are used to store and group the data in a particular data structure like List, Set or Map. But, streams are used to perform complex data processing operations like filtering, matching, mapping etc on stored data such as arrays, collections or I/O resources. That means, collections are mainly about data and streams are mainly about operations on data.
1) The Difference
//Usage of collections
//Collections are mainly used to store the data
//Here, names are stored as List
List<String> names = new ArrayList<>();
names.add("Charlie");
names.add("Douglas");
names.add("Sundaraman");
names.add("Charlie");
names.add("Yuki");
//Usage of streams
//Streams are mainly used to perform operations on data
//like selecting only unique names
names.stream().distinct().forEach(System.out::println);
//Output :
//Charlie
//Douglas
//Sundaraman
//Yuki
2) Data Modification
You can add to or remove elements from collections. But, you can’t add to or remove elements from streams. Stream consumes a source, performs operations on it and returns a result. They don’t modify even the source also.
List<String> names = Arrays.asList("Charlie", "Douglas", "Jacob");
//Adding elements to names
names.add("Sundaraman");
names.add("Yuki");
//Removing elements from names
names.remove(2);
//getting stream of unique names
Stream<String> uniqueNames = names.stream().distinct();
//You can't add or remove elements from stream
//There are no such methods in Stream
3) External Iteration Vs Internal Iteration
The main specialty of Java 8 Streams is that you need not to worry about iteration while using streams. Streams perform iteration internally behind the scene for you. You just have to mention the operations to be performed on a source.
On the other hand, you have to do the iteration externally over collections using loops.
List<String> names = new ArrayList<>();
names.add("Charlie");
names.add("Douglas");
names.add("Sundaraman");
names.add("Charlie");
names.add("Yuki");
//External iteration of collections
for (String name : names)
{
System.out.println(name);
}
//Output :
//Charlie
//Douglas
//Sundaraman
//Charlie
//Yuki
//Internal iteration of streams. No for loops
names.stream().map(String::toUpperCase).forEach(System.out::println);
//Output :
//CHARLIE
//DOUGLAS
//SUNDARAMAN
//CHARLIE
//YUKI
4) Traversal
Streams are traversable only once. If you traverse the stream once, it is said to be consumed. To traverse it again, you have to get new stream from the source again. But, collections can be traversed multiple times.
List<Integer> numbers = Arrays.asList(4, 2, 8, 9, 5, 6, 7);
Stream<Integer> numbersGreaterThan5 = numbers.stream().filter(i -> i > 5);
//Traversing numbersGreaterThan5 stream first time
numbersGreaterThan5.forEach(System.out::println);
//Second time traversal will throw error
//Error : stream has already been operated upon or closed
numbersGreaterThan5.forEach(System.out::println);
5) Eager Construction Vs Lazy Construction
Collections are eagerly constructed i.e all the elements are computed at the beginning itself. But, streams are lazily constructed i.e intermediate operations are not evaluated until terminal operation is invoked.
List<Integer> numbers = Arrays.asList(4, 2, 8, 9, 5, 6, 7);
numbers.stream().filter(i -> i >= 5).limit(3).forEach(System.out::println);
//Here, not all numbers are evaluated.
//numbers are evaluated until 3 numbers >= 5 are found.
//Output :
//8
//9
//5
*************** What is the Difference Between Collections Vs Streams In Java :
Collections Streams
-----------------------------------------------------------------------------------------------------------------
Collections are mainly used to store and group the data. Streams are mainly used to perform operations on data.
You can add or remove elements from collections. You can’t add or remove elements from streams.
Collections have to be iterated externally. Streams are internally iterated.
Collections can be traversed multiple times. Streams are traversable only once.
Collections are eagerly constructed. Streams are lazily constructed.
Ex : List, Set, Map… Ex : filtering, mapping, matching…
-----------------------------------------------------------------------------------------------------------------
Java 8 Stream in details
========================
1) What Are Streams?
Streams can be defined as a sequences of elements from a source which support data processing operations. You can treat streams as operations on data. You will get to know as you go through this article.
2) Why Streams?
Almost every Java application use Collections API to store and process the data. Despite being the most used Java API, it is not easy to write the code for even some common data processing operations like filtering, finding, matching, sorting, mapping etc using Collections API . So, there needed Next-Gen API to process the data. So Java API designers have come with Java 8 Streams API to write more complex data processing operations with much of ease.
3) Characteristics Of Java 8 Streams
3.1) Streams are not the data structures
Streams doesn’t store the data. You can’t add or remove elements from streams. Hence, they are not the data structures. They are the just operations on data.
3.2) Stream Consumes a data source
Stream consumes a source, performs operations on it and produces the result. Source may be a collection or an array or an I/O resource. Remember, stream doesn’t modify the source.
3.3) Intermediate And Terminal Operations
Most of the stream operations return another new stream and they can be chained together to form a pipeline of operations.
The operations which return stream themselves are called intermediate operations. For example – filter(), distinct(), sorted() etc.
The operations which return other than stream are called terminal operations. count(). min(), max() are some terminal operations.
3.4) Pipeline Of Operations
A pipeline of operations consists of three things – a source, one or more intermediate operations and a terminal operation. Pipe-lining of operations let you to write database-like queries on a data source. In the below example, int array is the source, filter() and distinct() are intermediate operations and forEach() is a terminal operation.
IntStream.of(new int[] {4, 7, 1, 8, 3, 9, 7}).filter((int i) -> i > 5).distinct().forEach(System.out::println);
3.5) Internal Iteration
Collections need to be iterated explicitly. i.e you have to write the code to iterate over collections. But, all stream operations do the iteration internally behind the scene for you. You need not to worry about iteration at all while writing the code using Java 8 Streams API.
3.6) Parallel Execution
To gain the performance while processing the large amount of data, you have to process it in parallel and use multi core architectures. Java 8 Streams can be processed in parallel without writing any multi threaded code. For example, to process the collections in parallel, you just use parallelStream() method instead of stream() method.
List<String> names = new ArrayList<>();
names.add("David");
names.add("Johnson");
names.add("Samontika");
names.add("Brijesh");
names.add("John");
//Normal Execution
names.stream().filter((String name) -> name.length() > 5).skip(2).forEach(System.out::println);
//Parallel Execution
names.parallelStream().filter((String name) -> name.length() > 5).skip(2).forEach(System.out::println);
3.7) Streams are lazily populated
All elements of a stream are not populated at a time. They are lazily populated as per demand because intermediate operations are not evaluated until terminal operation is invoked.
3.8) Streams are traversable only once
You can’t traverse the streams more than once just like iterators. If you traverse the stream first time, it is said to be consumed.
List<String> nameList = Arrays.asList("Dinesh", "Ross", "Kagiso", "Steyn");
Stream<String> stream = nameList.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);
//Error : stream has already been operated upon or closed
3.9) Short Circuiting Operations
Short circuiting operations are the operations which don’t need the whole stream to be processed to produce a result. For example – findFirst(), findAny(), limit() etc.
********** What is the Differences Between Interface And Abstract Class After Java 8 :
==================================================================
1) Fields
Interface fields are public, static and final by default. Interfaces still don’t support non-static and non-final variables. Interfaces can only have public, static and final variables. On the other hand, abstract class can have static as well as non-static and final as well as non-final variables. They also support private and protected variables along with public variables.
2) Methods
After Java 8, an interface can have default and static methods along with abstract methods. Interfaces don’t support final methods. But, abstract classes support final as well as non-final methods and static as well as non-static methods along with abstract methods.
Also note that, only interfaces can have default methods. Abstract classes can’t have default methods.
3) Constructors
Interfaces can’t have constructors. Abstract classes can have any number of constructors.
4) Member’s Accessibility
All members of interfaces are public by default. Interfaces don’t support private and protected members. But, abstract classes support all type of members – private, protected and public members.
5) Multiple Inheritance
A class can extend only one abstract class, but can implement multiple interfaces. Thus, a class can inherit multiple properties from multiple sources only through interfaces, not through abstract classes.
interface anyInterface
{
int i = 10; //By default, interface fields are public, static and final
void abstractMethod(); //Interface can have abstract method
default void defaultMethod()
{
System.out.println("Interface can have default method");
}
static void staticMethod()
{
System.out.println("Interface can have static method");
}
//No constructors in an interface
//No non-static and non-final variables in an interface
//No private fields and methods in an interface
//No protected fields and methods in an interface
//No final methods in an interface
}
abstract class anyAbstractClass
{
private int a; //Abstract class can have private field
protected int b; //Abstract class can have protected field
public int c; //Abstract class can have public field
static int d; //Abstract class can have static field
final int e = 10; //Abstract class can have final field
int f; //Abstract class can have non-static and non-final field
public anyAbstractClass()
{
System.out.println("Abstract class can have constructors");
}
abstract void abstractmethod(); //Abstract class can have abstract method
private static void staticMethod()
{
System.out.println("Abstract class can have private and static method");
}
public void nonStaticMethod()
{
System.out.println("Abstract class can have public and non-static method");
}
protected void protectedMethod()
{
System.out.println("Abstract class can have protected method");
}
final void finalMethod()
{
System.out.println("Abstract class can have final method");
}
//No default method in an abstract class
}
https://javaconceptoftheday.com/java-8-streams-beginners-guide/
https://javaconceptoftheday.com/java-8-collectors-tutorial/
https://javaconceptoftheday.com/solving-real-time-queries-using-java-8-features-employee-management-system/
No comments:
Post a Comment