0% found this document useful (0 votes)
12 views29 pages

Java

Reactive programming is a style that connects data sources and consumers, allowing libraries like RxJava to manage data flow asynchronously. It contrasts with imperative programming by automatically updating values when data changes. The document also covers lambda expressions, functional interfaces, and the Streams API introduced in Java 8, emphasizing their roles in simplifying code and enhancing functional programming capabilities.

Uploaded by

N
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
0% found this document useful (0 votes)
12 views29 pages

Java

Reactive programming is a style that connects data sources and consumers, allowing libraries like RxJava to manage data flow asynchronously. It contrasts with imperative programming by automatically updating values when data changes. The document also covers lambda expressions, functional interfaces, and the Streams API introduced in Java 8, emphasizing their roles in simplifying code and enhancing functional programming capabilities.

Uploaded by

N
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1/ 29

Reactive Programming

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:

 Responsive – React to users


 Resilient – React to failures
 Elastic/ Scalable – React to load
 Message/ Event Driven – React to events

Reactive Vs Imperative Programming

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

Value of x is updated whenever the values of y or z change.

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.

Reactive Programming deals with the below.

 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.

A library that implements functional reactive programming in various languages.

Uses "observables" to represent asynchronous data streams

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:

// defining the source


Observable<Integer> source = Observable.range(1, 5);
// defining the consumer
Subscriber<Integer> consumer = new Subscriber<Integer>() {
@Override
public void onNext(Integer number) { System.out.println(number); }
@Override
public void onError(Throwable e) { System.out.println("error"); }
@Override
public void onCompleted() { System.out.println("completed"); }
};
// connecting the consumer to source
source.subscribe(consumer);

###Source of Data (Observable)


Observable<T> represents a source. An Observable can be created using one of the many factory
methods it provides. Observable.range(int start, int count) is one of them.

###Consumer of Data (Observer)


Subscriber<T> serves as a consumer of data. RxJava uses onNext(T data) method on the Subscriber to
push the data emitted by the source, the Observable, to the consumer of data, the Subscriber.

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.

###Connecting Consumer to Source


This is established using the subscribe(consumer) method on Observable. In RxJava, the computations as
a part of Observable and Subscriber get executed only when the connection is established.
Java 8 Example- Concise version
Observable.range(1, 5).subscribe(
number -> System.out.println(number),
error -> System.out.println("error"),
() -> System.out.println("completed")
);

Lambda Introduction
 Significant feature of Java included in Java SE 8.

 Facilitates functional programming, and simplifies development.

 Provides a simplified way to represent a method interface using an expression.

 Before lambda, anonymous inner class was the only option to implement a method.

 Enables us to encapsulate a single unit of behavior and pass it to other code.

 This is accompanied by other features such as Method References, Functional Interfaces,


Streams and Default methods which uses lambda expression.

Why Lambda Expressions?

 Reduced Lines of Code

 Sequential and Parallel Execution Support

 Provide implementation of Functional interface.

Lambda Expression Syntax

(argument-list) -> {body}

Argument-list: Can be empty or non-empty as well.

Arrow-token: Used to link arguments-list and body of expression.

Body: Contains expressions and statements for lambda expression.

Ex - (lemonCount,orangeCount)->{lemonCount+orangeCount}

Parameters:

 A lambda expression can receive zero, one or more parameters.

 The type of the parameters can be explicitly declared or it can be inferred from the context.

 Parameters are enclosed in parentheses and separated by commas.

 Empty parentheses are used to represent an empty set of parameters.


 When there is a single parameter, if its type is inferred, it is not mandatory to use parentheses.

In the above example, lemonCount and orangeCount are the parameters

Lambda Expression - Body


 The body of the lambda expression can contain zero, one or more statements.

 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.

Example - Using Anonymous classes

Using anonymous class (Without Lambda Expression)

// Total no. of citrus fruits

interface Citrusfruits{

int totalCitrusFruits(int lemonCount,int orangeCount);

public class App{

public static void main(String[] args) {

Citrusfruits cit=new Citrusfruits(){

public int totalCitrusFruits(int lemonCount,int orangeCount){

return (lemonCount+orangeCount); }};

System.out.println(cit.totalCitrusFruits(5,10));

Example - Using Lambda Expressions

// Total no. of citrus fruits

interface Citrusfruits{

int totalCitrusFruits(int lemonCount,int orangeCount);

}
public class App{

public static void main(String[] args) {

Citrusfruits cit=(lemonCount,orangeCount)->(lemonCount+orangeCount);

System.out.println(cit.totalCitrusFruits(10,20));

Implementing Runnable using Lambda expression

//Without Lambda Expression

new Thread(new Runnable() {

@Override

public void run() {

System.out.println("Implementation without Lambda Expressions");

}).start();

//With Lambda Expression

new Thread( () -> System.out.println("Implementation with Lambda Expression") ).start();

What is Functional Interface?

 An interface with exactly one abstract method is called Functional Interface.

 @FunctionalInterface annotation is added to mark it as functional interface

 They have a single functionality to exhibit

 There are many functional interfaces defined in java.util.function package

 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.

Below example uses predicate functional interface.

import java.util.Arrays;

import java.util.List;

import java.util.function.Predicate;

public class App {

public static void main(String args[]){

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

System.out.println("Print even numbers:");

eval(list, n-> n%2 == 0 );

public static void eval(List<Integer> list, Predicate<Integer> predicate) {

for(Integer n: list) {

if(predicate.test(n)) {

System.out.println(n + " ");

}
}

Predicate - Functional Interface

public interface Predicate<T>

Method Detail:

boolean test(T t)

Evaluates this predicate on the given argument.

Parameters:

t - the input argument

Returns: true if the input argument matches the predicate, otherwise false

Consumer - Functional Interface

public interface Consumer<T>

Method Detail:

void accept(T t)

Accepts a single argument and does not return any value.

Parameters:

T - the type of the input to the operation

Supplier - Functional Interface

public interface Supplier<T>

Method Detail:

T get()

Accepts no arguments but it returns a value.

Returns:

T - the type of results supplied by this Supplier.


Only one abstract method is allowed in any functional interface

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:

Consumer<String> c = s -> System.out.println(s);

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.

Ex: mechanic::fix - mechanic is the object and fix is the method.

A method reference can't be used for any method. They can only be used to replace a single-method
lambda expression.

Method References - Types

Reference to a static method

Ex - ContainingClass::staticMethodName

Syntax - Class::staticMethodName

Reference to an instance method of a particular object

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

Reference to an instance method of a particular object

class Car {

private int id;

private String color;

class Mechanic {

public void fix(Car c) {

System.out.println("Fixing car " + c.getId());

public void execute(Car car, Consumer<Car> c) {

c.accept(car);

final Mechanic mechanic = new Mechanic();

Car car = new Car();

// Using an anonymous class

execute(car, new Consumer<Car>() {

public void accept(Car c) {

mechanic.fix(c);

}
});

// Using a lambda expression

execute(car, c -> mechanic.fix(c));

// Using a method reference

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.

Default methods are non-abstract methods.

For creating a default method in java interface, we need

to use default keyword with the method signature.

default void <<method_name>>(){

Why Default methods?

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.

Reengineering the JDK framework is very complex.

Example:

Default method forEach() added to Iterable interface

public interface Iterable<T> {

public default void forEach(Consumer<? super T> consumer) {

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

Re declare the default method, which makes it abstract

Redefine the default method, which overrides it

Multiple Inheritance Ambiguity

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.

Multiple Interface Ambiguity (contd 1...)

public interface WildAnimal{

default void print(){

System.out.println("Wild Animal");

public interface Mammal{

default void print(){

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.

There are 2 ways to resolve this

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.

public interface WildAnimal{

default void print(){

System.out.println("Wild Animal");

public interface Mammal{

default void print(){

System.out.println("Mammal");

Multiple Inheritance Ambiguity (contd 3...)

// Option A

public class Tiger implements WildAnimal, Mammal {

public void print(){

System.out.println("Wild Animal - Mammal"); }}

// Option B

public class Tiger implements WildAnimal, Mammal {

public void print(){

WildAnimal.super.print();}}
Default Methods in Functional Interface

Conceptually, a functional interface has exactly one abstract method.

Since default methods have an implementation, they are not abstract.

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

 Prefer Standard Functional Interfaces than creating new functional interfaces

 Use the @FunctionalInterface Annotation

 Don’t Overuse Default Methods in Functional Interfaces

 Instantiate Functional Interfaces with Lambda Expressions

 Avoid overloading methods with functional Interface as parameters

 Do not treat lambda expressions as Inner class

 Keep lambda expressions short and self explanatory

 Use Effectively final variable

 Protect object variables from mutation

Streams API

Supports functional-style operations on streams of elements on a collections.

Converts Collections to a Stream, processing the elements in parallel and then gathering the resulting
elements into a Collection.

Designed for Bulk Data Operations on Collections.

Streams Vs Collections

 Streams differ from collections in below ways:


 Stream does not store elements. It simply transmits elements from a source such as a data structure,
an array, or an I/O channel, through a pipeline of computational operations.
 Stream is functional in nature. Operations performed on a stream does not modify it's source.
 Many stream operations, such as filtering, mapping, or duplicate removal, can be implemented lazily
 The elements of a stream are only visited once during the life of a stream. Like an Iterator, a new
stream must be generated to revisit the same elements of the source.
 While collections have a finite size, streams need not.
 Do not support indexed access
 Parallelizable

External and Internal Iteration


Traditional way of iterating through a collection (External Iteration)

List<String> names =newArrayList<>();


for(Student student : students){
if(student.getName().startsWith("A")){
names.add(student.getName());
}
}
Using java 8 Stream API (Internal Iteration)

List<string> names = students.stream().map(Student::getName).filter(name->name.startsWith("A"))

.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'

memberNames.stream().filter((s) -> s.startsWith("A"))


.forEach(System.out::println);

Intermediate Operations - Types


Intermediate operations are further divided as
 stateless operations
 stateful operations

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'.

long totalMatched = memberNames.stream()


.filter((s) -> s.startsWith("A"))
.count();

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.

double average = roster


.parallelStream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.mapToInt(Person::getAge)
.average()
.getAsDouble();

Challenges using Parallel stream


Collections are not thread-safe, which means that multiple threads cannot manipulate a collection without
introducing thread interference or memory consistency errors.

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.

Following are some of the important classes introduced in java.time package −

Local − Simplified date-time API with no complexity of timezone handling.

Zoned − Specialized date-time API to deal with various timezones.

java.time package

Click here to know list of classes under this package.

Why new API for Date & Time?


Not thread safe - java.util.Date is not thread safe, thus developers have to deal with concurrency issue while
using date. The new date-time API is immutable and does not have setter methods.
Poor design - Default Date starts from 1900, month starts from 1, and day starts from 0, so no uniformity.
The old API had less direct methods for date operations. The new API provides numerous utility methods for
such operations.

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:

Convert string to local date time

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:

Convert instant to localDateTime

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);
}
}

Convert Date to LocalDate and LocalDateTime

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);
}
}

//1. Convert Date -> Instant

Instant instant = date.toInstant();

System.out.println("instant : " + instant);

//2. Instant + system default time zone + toLocalDate() = LocalDate

LocalDate localDate = instant.atZone(defaultZoneId).toLocalDate();

System.out.println("localDate : " + localDate);


//3. Instant + system default time zone + toLocalDateTime() = LocalDateTime

LocalDateTime localDateTime = instant.atZone(defaultZoneId).toLocalDateTime();

System.out.println("localDateTime : " + localDateTime);

//4. Instant + system default time zone = ZonedDateTime

ZonedDateTime zonedDateTime = instant.atZone(defaultZoneId);

System.out.println("zonedDateTime : " + zonedDateTime);

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.

LocalDate with1 = localDate.with(TemporalAdjusters.lastDayOfMonth());

System.out.println("lastDayOfMonth : " + with1);

LocalDate with2 = localDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));

System.out.println("next monday : " + with2);

java.time.chrono
The supported calendar systems includes:

Hijrah calendar

Japanese calendar

Minguo calendar

Thai Buddhist calendar


Simple code snippet to print today's date in list of calenders available.

Set<Chronology> chronos = Chronology.getAvailableChronologies();

for (Chronology chrono : chronos) {

ChronoLocalDate date = chrono.dateNow();

System.out.printf(" %20s: %s%n", chrono.getId(), date.toString());

ZonedDateTime withZoneSameInstant() method


The java.time.ZonedDateTime.withZoneSameInstant(ZoneId zone) method returns a copy of the date-time
with a different time-zone, retaining the instant.

Following is the declaration for java.time.ZonedDateTime.withZoneSameInstant(ZoneId zone) method.

public ZonedDateTime withZoneSameInstant(ZoneId zone)

The following example program shows the usage of java.time.ZonedDateTime.withZoneSameInstant(ZoneId


zone) method.

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZoneMethod {

public static void main(String[] args) {


ZonedDateTime date = ZonedDateTime.parse("2020-08-28T19:10:38.492+05:30[Asia/Kolkata]");
ZonedDateTime result = date.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println(result);
}
}

The output is

The same instant fot the given zone Asia/Tokyo is : 2020-08-28T22:40:38.492+09:00[Asia/Tokyo]


Type Annotations
With java 8, annotations can also be applied to any type use.

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).

List of Type Annotations


@NonNull – The compiler can determine cases where a code path might receive a null value, without ever
having to debug a NullPointerException.

@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.

List<@NonNull String> A list of non-null Strings.

@Regex String validation = "(Java|JDK) [7,8]" Compile time validation that this String is a valid regular
expression.

private String getInput(String parameterName){


final String retval = @Tainted request.getParameter(parameterName);
return retval;
}
The object assigned to retval is tainted and not for use in sensitive operations.
private void runCommand(@Untainted String… commands){
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
}
Each command must be untainted. For example, the previously tainted String must be validated before being
passed in here.

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.

The @interface element is used to declare an annotation.

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 {

public static void main(String[] args) throws Exception {


CustomAnnotationsrunner runner = new CustomAnnotationsrunner();
Method methods = runner.getClass().getMethod("method1");
Custom annotation = methods.getAnnotation(Custom.class);
System.out.println("value is : "+ annotation.value());
}
}

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().

Accessing them via the getAnnotationsByType() or getDeclaredAnnotationsByType()

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:

Number of car manufacturers is 4


------Printing out Car Manufacturers--------
Mercedes Benz
Toyota
BMW
Range Rover
Rhino
Rhino is an open-source implementation of JavaScript written entirely in Java.

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.

Rhino converts JavaScript scripts into classes.

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.

Replaces old Rhino engine

Nashorn uses invokedynamics feature, introduced in Java 7 to improve performance


Why Nashorn?
According to Jim Laskey of Oracle, the principal developer of Nashorn:

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.

Scripts do not need to be compiled.

Fast execution and multi-threading of JavaScript running in Java’s JRE.

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.

Nashorn will not include a browser plug-in API.


Nashorn will not include support for DOM/CSS or any related libraries (such as jQuery, Prototype, or Dojo).

Nashorn will not include direct debugging support.


Javascript execution
Nashorn javascript engine can either be used programmatically from java programs or by utilizing the
command line tool jjs, which is located in $JAVA_HOME/bin

###From Command prompt

For Nashorn engine, JAVA 8 introduces a new command line tool, jjs to execute java script code at console.

Execution - Command prompt - Example


Create and save fresco.js in c: > JAVA folder.

fresco.js

print('Welcome to Fresco world!');

Open console and use the following command to execute the script

C:\JAVA>jjs sample.js

Execution within Java code


public class App {
public static void main(String args[]){
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
String name = "Fresco";
Integer result = null;
try{
nashorn.eval("print('" + name + "')");
result = (Integer) nashorn.eval("10+10+10");
}catch(ScriptException e){
System.out.println("Error executing script: "+ e.getMessage());
}
System.out.println("Total Courses :"+result.toString());
}
}

Nashorn Java API


Invoking Java Methods from Javascript

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.

var MyJavaClass = Java.type('package_name.Class_name');


var result = MyJavaClass.fun1('John');
print(result);
Script Object Mirror
When passing native javascript objects to java you can utilize the class ScriptObjectMirror which is actually a
java representation of the underlying javascript object.

Nashorn java API


####Typed Arrays

Native javascript arrays are untyped. Nashorn enables you to use typed java arrays in javascript

Please refer below code snippet

var IntArray = Java.type("int[]");


var array = new IntArray(5);
array[0] = 5;
array[1] = 4;
array[2] = 3;
array[3] = 2;
array[4] = 1;
The int[] array behaves like a real java int array. But additionally Nashorn performs implicit type conversions
under the hood when we're trying to add non-integer values to the array.

Nashorn Java API


####Collections

In order to iterate over collections and arrays Nashorn introduces the for each statement. It works just like
the foreach loop in java.

Please refer to code snippet below

var ArrayList = Java.type('java.util.ArrayList');


var list = new ArrayList();
list.add('tomato');
list.add('onion');
list.add('potato');
for each (var el in list) print(el);

Nashorn Java API


####Lambda expressions and Streams

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

var list2 = new java.util.ArrayList();


list2.add("Mahesh");
list2.add("David");
list2.add("Mahesh Ram");
list2.add("Murugan");
list2.stream().filter(function(el) {
return el.startsWith("Mahesh");
})
.sorted()
.forEach(function(el) {
print(el);
});

Java Concurrency Utilities


java.util.concurrent : Utility classes used in concurrent programming.

This package is enhanced with aggregate operations based on newly added Lambda expressions and stream
api.

Why Concurrent util Package ?

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.

Standard Java threading difficulties


Usage of Java low level threading concepts (synchronized, volatile, wait(), notify(), and notifyAll()) may lead
to threading hazards like deadlock and thread starvation that hard to detect and debug.

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.

Simple Example on how to use executers:

ExecutorService executor = Executors.newSingleThreadExecutor();


executor.submit(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("Hello " + threadName);
});

More features
Parallel Sorting - Arrays can be sorted in parallel using Arrays.parallelSort()

Inbuilt encoder and decoder for Base64 encoding

Unsigned integers are supported in the new API

Improved Type Inference

Method parameter reflection - To obtain the names of formal parameters of any method or constructor

Optional type - To reduce Null pointer Exceptions

Permgem replaced with new Metaspace

You might also like