Java
Java
Reactive programming is a programming style where we define a source and a consumer of data. Once
we connect the consumer to the source, the library takes care of pushing the data, generated by the
source, to the consumer.
RxJava library helps programmers to write asynchronous, concurrent, and resilient applications.
RxJava is not a native java8 feature, but it is a library which uses java8 features extensively and a good to
know feature.
Features:
Imperative programming
x=y+z
Here, the sum of y and z will be assigned to variable x. Suppose at later point, values of y or z change,
this will not automatically influence the value of x.
Reactive programming
Pull Vs Push
In functional programming, iterators are used to pull and process data synchronously.
In functional reactive programming, we push the same stream of data that we used to have in a
collection asynchronously into an observer.
Source of data
Consumer of data
Connecting consumer to source
What's ReactiveX?
ReactiveX is a collection of the best ideas from the Observer pattern, the Iterator pattern, and functional
programming.
What's RxJava?
Library that implements the concepts of ReactiveX in Java.
RxJava library provides a model to work with events generated from UI or asynchronous calls in the same
way as collections and streams in Java 8.
Example:
Once all the data is emitted by the source, RxJava signals the completion using onComplete() method on
the Subscriber. If there is any error observed during emission of data, RxJava forwards the error to
onError(Throwable e) method on the Subscriber.
Lambda Introduction
Significant feature of Java included in Java SE 8.
Before lambda, anonymous inner class was the only option to implement a method.
Ex - (lemonCount,orangeCount)->{lemonCount+orangeCount}
Parameters:
The type of the parameters can be explicitly declared or it can be inferred from the context.
When there is a single statement curly brackets are not mandatory and the return type of the
anonymous function is the same as that of the body expression.
When there is more than one statement then these must be enclosed in curly brackets (a code
block) and the return type of the anonymous function is the same as the type of the value
returned within the code block, or void if nothing is returned.
interface Citrusfruits{
System.out.println(cit.totalCitrusFruits(5,10));
interface Citrusfruits{
}
public class App{
Citrusfruits cit=(lemonCount,orangeCount)->(lemonCount+orangeCount);
System.out.println(cit.totalCitrusFruits(10,20));
@Override
}).start();
Some of the significant ones are Consumer, Supplier, Function and Predicate.
One can use lambda expressions to instantiate them and avoid using anonymous class implementation.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
for(Integer n: list) {
if(predicate.test(n)) {
}
}
Method Detail:
boolean test(T t)
Parameters:
Returns: true if the input argument matches the predicate, otherwise false
Method Detail:
void accept(T t)
Parameters:
Method Detail:
T get()
Returns:
A functional interface is valid even if the @FunctionalInterface annotation would be omitted. It is only
for informing the compiler to enforce single abstract method inside interface.
If an interface declares an abstract method overriding a method of java.lang.Object, it does not count.
e.g. Comparator is a functional interface even though it declared two more abstract methods.
Method Reference
A method reference is the simplified syntax used for a lambda expression that executes just ONE
method. Sometimes, the lambda expression is just a call to one method, for example:
To make the code more simple, you can turn that lambda expression into a method reference:
Consumer<String> c = System.out::println;
Method Reference
In a method reference, you place the object (or class) that contains the method before the :: operator
and the name of the method after it without arguments.
A method reference can't be used for any method. They can only be used to replace a single-method
lambda expression.
Ex - ContainingClass::staticMethodName
Syntax - Class::staticMethodName
Ex - containingObject::instanceMethodName
Syntax - object::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type
Ex - ContainingType::methodName
Syntax - Class::instanceMethodName
Reference to a constructor
Ex - ClassName::new
Syntax - ClassName::new
Example
class Car {
class Mechanic {
c.accept(car);
mechanic.fix(c);
}
});
execute(car, mechanic::fix);
Default Methods
Allows the interfaces to have methods with implementation without affecting the classes that
implement the interface.
Methods are defined inside the interface and tagged with default.
Modifying one interface in JDK framework breaks all classes that extends the interface. Which means
that adding any new method could break millions of lines of code.
Example:
for (T t : this) {
consumer.accept(t);
}
Abstract classes Vs Interfaces in java 8
After introduction of default methods and static methods in interface, there is a misconception that both
abstract classes and interfaces are same.
Major difference between the two is that we can create constructor in the abstract class whereas we
can't do this in interface.
Extending Interfaces
While another interface extending an interface that contains a default method, either of the below
options should be considered.
Not mention the default method at all, which lets your extended interface inherit the default method
Since java class can implement multiple interfaces and each interface can define default method with
same method signature, the inherited methods can conflict with each other.
Lets consider a Wild Animal interface and a Mammal Interface defined. Class Tiger implements both
interfaces.
System.out.println("Wild Animal");
System.out.println("Mammal");
}
public class Tiger implements WildAnimal, Mammal {
Above code will fail to compile with the error. class Tiger inherits unrelated defaults for defaultMethod()
from types Interface WildAnimal and Mammal.
Option A: Create new method in Tiger class that overrides the default implementation.
Option B: Call the default method of the specified interface using super.
System.out.println("Wild Animal");
System.out.println("Mammal");
// Option A
// Option B
WildAnimal.super.print();}}
Default Methods in Functional Interface
Since default methods are not abstract, we can add default methods to your functional interface as
many as we want.
Comparator Interface is still a valid functional interface though there are many default and static
methods introduced with one abstract method compare().
Best Practices
Streams API
Converts Collections to a Stream, processing the elements in parallel and then gathering the resulting
elements into a Collection.
Streams Vs Collections
.collect(Collectors.toList());
Short-Circuit Operations
An intermediate operation is an short-circuit one, when it produces a finite stream as a result on an infinite
input.
A terminal operation is a short-circuit one, when it terminates in finite time when processing infinite input.
Couple of short circuiting operations are anyMatch() and findFirst().
Example
Below code snippet will print the first name from the list starting with 'L'.
String firstMatchedName = memberNames.stream()
.filter((s) -> s.startsWith("L"))
.findFirst().get();
System.out.println(firstMatchedName);
Stream Operations
Stream operations are divided into intermediate and terminal operations, and are combined to form stream
pipelines.
A stream pipeline consists of a source (such as a Collection, an array, a generator function, or an I/O
channel); followed by zero or more intermediate operations such as Stream.filter or Stream.map; and a
terminal operation such as Stream.forEach or Stream.reduce.
Intermediate operations do not actually perform any filtering, but instead creates a new stream that, when
traversed, contains the elements of the initial stream that match the given predicate.
Few intermediate operations are: filter(), map() and sorted().
Example:
Below example prints member names starting with 'A'
Stateless operations, such as filter and map, retain no state from previously seen element when processing a
new element. Each element can be processed independent of operations on other elements.
Stateful operations, such as distinct and sorted, may incorporate state from previously seen elements when
processing new elements.
Terminal Operation
Terminal operations may traverse the stream to produce a result or a side-effect.
After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer
be used.
Terminal operations are eager, completing their traversal of the data source and processing of the pipeline
before returning
Few examples for terminal operation: forEach(), collect(), match(), count() and reduce()
Below example uses count() method to retrieve the count of members names starting with 'A'.
Parallel Streams
All streams operations can execute either in serial or in parallel. The stream implementations in the JDK
create serial streams unless parallelism is explicitly requested. Here is the code snippet on how to use
parallel stream.
Aggregate operations and parallel streams enable you to implement parallelism with non-thread-safe
collections provided that you do not modify the collection while you are operating on it.
New series of date and time APIs are created in the new java.time package.
java.time package
Difficult time zone handling - Developers had to write a lot of code to deal with timezone issues. The new API
has been developed keeping domain-specific design in mind.
Simple example to use the new API for Date and Time operations.
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
public class GetCurrentDateTime {
private static final DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
public static void main(String[] args) {
Date date = new Date();
System.out.println(sdf.format(date));
Calendar cal = Calendar.getInstance();
System.out.println(sdf.format(cal.getTime()));
LocalDateTime now = LocalDateTime.now();
System.out.println(dtf.format(now));
LocalDate localDate = LocalDate.now();
System.out.println(DateTimeFormatter.ofPattern("yyy/MM/dd").format(localDate));
}
}
Example 2:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
public class TestDate2 {
public static void main(String[] args) {
String now = "2017-06-13 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime formatDateTime = LocalDateTime.parse(now, formatter);
System.out.println("Before : " + now);
System.out.println("After : " + formatDateTime);
System.out.println("After : " + formatDateTime.format(formatter));
}
}
Example 3:
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
public class InstantExample1 {
public static void main(String[] argv) {
Instant instant = Instant.now();
System.out.println("Instant : " + instant);
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime : " + ldt);
}
}
import java.time.*;
import java.util.Date;
public class DateToJavaTime {
public static void main(String[] args) {
Date date = new Date();
//Convert to LocalDate
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
System.out.println(localDate.toString());
//Convert to LocalDateTime
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
}
}
Temporal Adjusters
In Java 8, predefined java.time.temporal.TemporalAdjusters can be used to adjust a date or Temporal.
Please read below example to print last day of current month and next monday date.
java.time.chrono
The supported calendar systems includes:
Hijrah calendar
Japanese calendar
Minguo calendar
import java.time.ZoneId;
import java.time.ZonedDateTime;
The output is
The compiler can then verify these annotations, for example identifying uses of null values, accidental value
modifications, and cases where data crosses a trust boundary without proper validation.
By moving some annotatable information from the Javadoc (understood only by people), and into the code
(understood by both people and analyzers), it is easier to understand intent and verify the absence of certain
errors.
Type Annotations
Type Annotations tell analyzers what to look for. Without the Type Annotations in place, these analyzers
would still be able to locate null-usage and write-modifications but would not know that they are wrong. The
result would then be false negatives (no issue reported) or false positives (incorrect issues reported).
@ReadOnly – The compiler will flag any attempt to change the object. This is similar to
Collections.unmodifiableList, but more general and verified at compile time.
@Regex – Provides compile-time verification that a String intended to be used as a regular expression is a
properly formatted regular expression.
@Tainted and @Untainted – Identity types of data that should not be used together, such as remote user
input being used in system commands, or sensitive information in log streams.
@m – Units of measure ensures that numbers used for measuring objects are used and compared correctly,
or have undergone the proper unit conversion.
Examples
@NonNull List<String> A non-null list of Strings.
@Regex String validation = "(Java|JDK) [7,8]" Compile time validation that this String is a valid regular
expression.
Custom Annotations
The Java programming language allows you to define your own custom annotations. Annotations are defined
via @interface annotation before the class name.
Through @Retention you can define if the annotation should be retained at runtime or not.
The @Target annotation lets you define where this annotation can be used, e.g., the class, fields, methods,
etc.
For example:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
public String value();
}
Let us see custom annotation with an example program
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.lang.annotation.ElementType;
@Retention( RetentionPolicy.RUNTIME )
@Target(ElementType.METHOD)
@interface Custom {
int value();
}
class CustomAnnotationsrunner{
@Custom(value = 100)
public void method1() {
System.out.println("Custom Annotation");
}
}
public class CustomAnnotations {
output :
value is : 100
Repeating Annotations
Prior to Java8, we cannot declare more than one annotation of the same type to the same location of a code.
Java8 introduces the repeating annotation by which same annotations can be repeated as much as you want
at same locations.
Repeating Annotations make it easier because there is less need for wrapper annotations
Examples
For example, doPeriodicCleanup method is executed on the last day of the month and on every Friday at
11:00 p.m. to do a clean up activity after a batch job is executed.
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
Examples (Contd..)
The previous example applies an annotation to a method.
Another example, there is a class for handling unauthorized access exceptions. You annotate the class with
one @Alert annotation for managers and another for admins:
@Alert(role="Manager")
@Alert(role="Administrator")
public class UnauthorizedAccessException extends SecurityException { ... }
Retrieving Annotations
There are 2 ways to retreive them
Accessing them via their container annotation using getDeclaredAnnotation() or getAnnotation().
Examples (contd..)
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class App {
@Retention( RetentionPolicy.RUNTIME )
public @interface Cars {
Manufacturer[] value() default{};
}
@Manufacturer( "Mercedes Benz")
@Manufacturer( "Toyota")
@Manufacturer( "BMW")
@Manufacturer( "Range Rover")
public interface Car {
}
@Repeatable(value = Cars.class )
public @interface Manufacturer {
String value();
};
Examples (contd..)
public static void main(String[] args) {
Manufacturer[] a = Car.class.getAnnotationsByType(Manufacturer.class );
System.out.println("Number of car manufacturers is "+ a.length );
System.out.println("\n-------Printing out Car Manufacturers--------");
Cars cars = Car.class.getAnnotation(Cars.class);
for(Manufacturer car: cars.value()){
System.out.println(car.value());
}
}
}
Output:
It is typically embedded into Java applications to provide scripting to end users. It is embedded in J2SE 6 as
the default Java scripting engine.
It is intended to be used in server-side applications, hence there is no built-in support for the Web browser
objects that are commonly associated with JavaScript.
Nashorn, pronounced "nass-horn," is German for "rhinoceros," and it's one of the animal names for a
German tank destroyer used in World War II.
The performance of Rhino has fallen far behind that of other JavaScript engines.
In order to improve performance, Rhino would have to be rewritten to replace its interpreter with a code
generator designed to fully utilize the JVM. Rather than undertake a major rewrite of the very old Rhino
code, we have chosen instead to start from scratch.
Nashorn - Benefits
Interoperability with Java and JavaScript libraries.
The ability to remotely debug applications using an IDE like NetBeans, Eclipse, or IntelliJ (instructions on the
Nashorn blog).
Automatic integration with Java monitoring tools, such as performance, health, and SIEM.
Nashorn - Limitations
Nashorn will only support ECMAScript-262 Edition 5.1. It will not support any features of Edition 6 or any
nonstandard features provided by other JavaScript implementations.
For Nashorn engine, JAVA 8 introduces a new command line tool, jjs to execute java script code at console.
fresco.js
Open console and use the following command to execute the script
C:\JAVA>jjs sample.js
Example
static String fun1(String name) {
System.out.format("Hi Fresco Learner, %s", name);
return "Welcome to Fresco Play";
}
Java classes can be referenced from javascript via the Java.type API extension.
Native javascript arrays are untyped. Nashorn enables you to use typed java arrays in javascript
In order to iterate over collections and arrays Nashorn introduces the for each statement. It works just like
the foreach loop in java.
Although ECMAScript 5.1 lacks the compact arrow syntax from the Java 8 lambda expressions, we can use
function literals where ever lambda expressions are accepted.
Example
This package is enhanced with aggregate operations based on newly added Lambda expressions and stream
api.
With the increasingly complexity of current applications, many developers find this low level threading
concepts difficult to implement.
The Java platform provides these capabilities that enable developers to write concurrent applications, where
different threads execute simultaneously.
Relying on synchronized to coordinate access between threads leads to performance issues that affect
application scalability
Developers need higher level constructs like semaphores and thread pools, which Java's low-level threading
capabilities don't offer.
Executor
Executors are capable of running asynchronous tasks and typically manage a pool of threads, so we don't
have to create new threads manually.
More features
Parallel Sorting - Arrays can be sorted in parallel using Arrays.parallelSort()
Method parameter reflection - To obtain the names of formal parameters of any method or constructor