June 21, 2021
These blogs will help you learn Java Programming & Concepts in a simple and effective way. If you have no prior knowledge in Java, you won’t face any difficulty. If you are experienced java developer, this blog will help you brush up the concepts.
Functional programming is an alternative to object-oriented programming that is centered around pure functions. Functional applications avoid the shared state, and tend to be more concise and predictable than those using object-oriented code. In a pure mathematical sense a pure function is:
Using this functional programming style can produce cleaner, readable OO code with fewer problems. So, how can we harness functional programming from Java and what all is added?
In Java 8, the java.util.Function<T, R> Interface was introduced. It can store a function which takes one argument and returns an object. The Generic T is the type of the argument and R the type of the object you return. For example:
public static Integer calculate(Function<Integer, Integer> function, Integer value) {
return function.apply(value);
}
Functional interface are inteface with single abstract method. They can have only one functionality to exhibit. From Java 8 lambda expressions can be used to represent the instance of a functional interface. Runnable, Comparator,Comparable are some of the examples of functional interfaces.
class Test
{
public static void main(String args[])
{
new Thread(new Runnable()
{
@Override
public void run()
{
System.out.println(“Hello”);
}
}).start();
}
}
Using lambda expression to functional interface:
class Test
{
public static void main(String args[])
{
new Thread(()->
{System.out.println(“Hello lambda”);}).start();
}
}
Interfaces always had public static final fields, from Java 8 they can have default methods. Before Java 8, we had to create anonymous inner class objects or implement these interfaces. The basic idea of a default method is: it is an interface method with a default implementation, and a derived class can provide a more specific implementation.
So why not keep using Abstract class?
Abstract classes are still a way to introduce state, or implement the core Object methods, its coupled with state. Default methods in interface are for pure behavior.
An example of default method is nullLast method in Comparator interface.
Comparator<Obj> newComparator = Comparator.nullLast(oldComparator);
As Lambda expressions are introduced. It was quite difficult to add support of lambda expressions in existing collection interfaces. To add a support of Lambda expressions, they need to rewrite all interfaces of collection framework which introduced concept of Default Methods in interfaces.
So, supporting functional programming, the Interfaces are stateless and it can have multiple static default methods.
synchronized
on interface methodsSynchronization is the capability to control the access of multiple threads to shared resources. Synchronized static methods have a lock on the class ”Class” so when a thread enters a synchronized static method, the class itself gets locked by the thread monitor and no other thread can enter any static synchronized methods on that class. This is unlike instance methods, as multiple threads can access “same synchronized instance methods” as same time for different instances.
For example, Run method of runnable class can be synchronized, If u make run method synchronized then the lock on runnable object will be occupied before executing the run method.
Synchronization is about locking. Locking is about coordinating shared access to mutable state. Each object should have a synchronization policy that determines which locks guard which state variables. Many objects use as their synchronization policy the Java Monitor Pattern, in which an object’s state is guarded by its intrinsic lock.
But interfaces do not own the state of the objects into which they are mixed in. Subclasses may override methods that are declared synchronized in super classes, effectively removing synchronization. This would give you the false sense of confidence that you have done something about thread safety, and no error message tells you that you’re assuming the wrong synchronization policy.
We all hate nulls and null checks. It sucks that for every arugument we have to check whether it is null or not.
In Java 8, java.util.Optional
Integer i = 5;
Optional<Integer> optionalInteger = Optional.of(i);
The Optional class doesn’t have any public constructor. To create an optional, we use Optional.of(object) if the object is never, ever null OR Optional.ofNullable(object) for nullable objects.
Lambda expressions are readable and expressive way to code the processing of lists or collections. It’s a method without a declaration, i.e., access modifier, return value declaration, and name. It saves you the effort of declaring and writing a separate method to the containing class.
Lambdas are often:
They enable you to treat functionality as a method argument, or code as data.
MathOperation addition = (int a, int b) -> a + b;
addition(a,b);
Streams are a wonderful new way to work with data collections. Almost every Stream method returns the Stream again, so developers can continue to work with it. Streams have the ability to filter, map, and reduce while being traversed.
Streams are also immutable and a one-time-use Object. Once it has been traversed, it cannot be traversed again. Every time developers manipulate it, they create a new Stream. The way it it supports functional programming is if developers convert a Data Structure into a Stream and work on it, the original data structure won’t be changed. So absence of memory aka no side effects!
Check the examples for various utilization of Streams:
Simple Stream
public void convertObjects() {
Stream<String> objectStream = Stream.of(“Hello”, “World”);
}
Arrays to Stream
public void convertStuff() {
String[] array = {“hello”, “world”};
Stream<String> arrayStream = Arrays.stream(array);
}
Concat multiple Lists into Stream
public void concatList() {
List<Integer> list1 = Arrays.asList(1, 2, 3);
List<Integer> list2 = Arrays.asList(4, 5, 6);
Stream.of(list1, list2) //Stream<List<Integer>>
.flatMap(List::stream) //Stream<Integer>
.forEach(System.out::println); // 1 2 3 4 5 6
}
Usage of Filter for conditions in Stream
public void filterNull() {
Stream.of(2, 1, null, 3).filter(Objects::nonNull).map(num -> num)
// without filter, you would’ve got a NullPointerExeception
.forEach(System.out::println);
}
Usage of Collectors to convert Stream to List
public void showCollect() {
List<Integer> filtered = Stream.of(0, 1, 2, 3).filter(num -> num).collect(Collectors.toList());
}
Performing reducing tasks
public void showReduceSum() {
int[] array = {23,43,56,97,32};
Arrays.stream(array).reduce((x,y) -> x+y).ifPresent(s -> System.out.println(s));
}
Sorting data in Stream
public void showSort() {
Stream.of(3, 2, 4, 0).sorted((c1, c2) -> c1 — c2).forEach(System.out::println); // 0 2 3 4
}
Apart from proper utilization of all the above supports to write cleaner and readable functional programming code, there are few small things like avoiding usage of global variables in functions, keeping final variables, using functions as parameters and writing functions that only depends on its parameters.
Reactive programming is all about data flows. The data flows emitted by one component will propagate to another component. Event buses, click events, twitter feeds are similar asynchronous event stream or data stream. Observable Class and Observer Interface is a good example of reactive paradigm. To summarize reactive programming is all about creating architecture that supports: Event driven or message driven (asynchronous), Scalable, Reslient and Responsive.
Java 9 introduced a Flow API and common interfaces for the Reactive Programming, providing a step by step way to implement the reactive programming.The Flow APIs has covered the communication aspect (request, slow down, drop, block, etc.) enabling us to adopt Reactive Programming, not needing additional libraries such as RxJava or Project Reactor, amongst others. The Flow has four nested interfaces:
public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
}
@FunctionalInterface
public static interface Publisher<T> {
public void subscribe(Subscriber<? super T> subscriber);
}
public static interface Subscriber<T> {
public void onSubscribe(Subscription subscription);
public void onNext(T item);
public void onError(Throwable throwable);
public void onComplete();
}
public static interface Subscription {
public void request(long n);
public void cancel();
}
The below example will clearly example the flow and various interfaces methods and its usage.
In a simple reactive flow, we have a Publisher publishing messages, and a simple Subscriber consuming messages as they arrive — one at the time.The Publisher publishes a stream of data that the Subscriber is asynchronously subscribed to.
Check the example, SubmissionPublisher class implements Publisher, the Publisher has one method subscribe(), for subscribers to receive events published by it, and SubmissionPublisher’s submit method produces the items.
public class FlowMain {
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
MySubscriber<String> subscriber1 = new MySubscriber<>(“One”);
MySubscriber<String> subscriber2 = new MySubscriber<>(“Two”);
publisher.subscribe(subscriber1);
publisher.subscribe(subscriber2);
publisher.submit(“Hello”);
publisher.submit(“Universe”);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publisher.close();
}
}
Lets discuss the interface methods of subscriber:
So lets see the Implementation of Subscriber:
public class MySubscriber<T> implements Subscriber<T> {
private Subscription subscription;
private String name;
public MySubscriber(String name) {
this.name = name;
}
@Override
public void onComplete() {
System.out.println(name + “: Completed”);
}
@Override
public void onError(Throwable t) {
System.out.println(name + “: Weird... its an error”);
t.printStackTrace();
}
@Override
public void onNext(T msg) {
System.out.println(name + “: “ + msg.toString() + “ received a message”);
subscription.request(1);
}
@Override
public void onSubscribe(Subscription subscription) {
System.out.println(name + “: onSubscribe”);
this.subscription = subscription;
subscription.request(1);
}
}
The question might araise, we already had Observable Class and Observer Interace in Java. So, why this is introduced and how is it different?
One of the main difference is in Publisher-Subscriber pattern, the publisher and subscriber don’t know each other, the communication is through queues or brokers. So, the are loosely coupled. In Observer pattern, the observer knows all subjects. The Publisher/Subscriber pattern is mostly implemented in an asynchronous way and can be used across multiple applications or microservices whereas observer pattern is very synchronous.