Saturday, March 30, 2019

Java Stream Concepts

Streams are Monads. In functional programming, a monad is a structure that represents computations defined as sequences of steps. Java Stream doesn’t store data, it operates on the source data structure (like collection and array) and produce pipelined data. On that pipelined (similar to assembly line/conveyor belt) data we can perform specific operations. Steam makes bulk processing on collections convenient and fast.

Stream operations are either intermediate or terminal. Intermediate operations return a stream so we can chain multiple intermediate operations without using semicolons. Such a chain of stream operations is also known as operation pipeline. An important characteristic of intermediate operations is laziness. Intermediate operations will only be executed when a terminal operation is present. Terminal operations are either void or return a non-stream result.

Java Stream operations use functional interfaces, that makes it a very good fit for functional programming using lambda expression. Most of those functional operations must be both non-interfering and stateless. A function is non-interfering when it does not modify the underlying data source of the stream. A function is stateless when the execution of the operation is deterministic i.e. no lambda expression depends on any mutable variables or states from the outer scope which might change during execution.

Java Streams are consumable, so there is no way to create a reference to stream for future usage. Since the data is on-demand, it’s not possible to reuse the same stream multiple times.

Processing Order
In stream, each element moves along the chain vertically i.e. to the operations are executed vertically one after another on all elements of the stream. Due to this processing order, operations like filters should be placed in beginning of the chain to reduce the number of executions.

Stream Creation
Java stream can be created from array and collections in many ways. Here are some examples:
  • Stream.of() can be used in several ways. We can create stream by providing some elements with specific values.
            Stream stream = Stream.of(1,2,3,4);
    
  • An array of Objects can used to create steam.
            Stream stream = Stream.of(new Integer[]{1,2,3,4});
    
  • Java 8 added a new stream() method to the Collection interface. So, steam can be created from any existing list or other collection.
            List myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
            Stream stream = myList.stream();
    

Intermediate Operations
Here are some common stream intermediate operations:
  • filter: filter() method takes a Predicate with some condition that is applied to filter the stream. It return a new stream that contains subset of the original stream.
            List myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
            myList.stream()
                    .filter(s -> s.startsWith("c"))
                    .forEach(System.out::println);
    
  • map: map() method takes a Function and apply it to all elements of the stream.
            List myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
            myList.stream()
                    .map(String::toUpperCase)
                    .forEach(System.out::println);
    
  • sorted: sorted() method returns a stream consisting of the elements of this stream, sorted according to natural order.
            List myList = Arrays.asList( "b1", "a1", "a2", "c2", "c1");
            myList.stream()
                    .sorted()
                    .forEach(System.out::println);
    
    The overloaded version takes a Comparator as parameter.
            List myList = Arrays.asList( "b1", "a1", "a2", "c2", "c1");
            myList.stream()
                    .sorted(Comparator.reverseOrder())
                    .forEach(System.out::println); 
    
    The Comparator can be provided as lambda expression:
        List myList = Arrays.asList( "b1", "a1", "a2", "c2", "c1");
            myList.stream()
                    .sorted((s1, s2) -> s2.compareTo(s1))
                    .forEach(System.out::println); 
    
  • flatMap: FlatMap transforms each element of the stream into a stream of other objects. So each object will be transformed into zero, one or multiple other objects backed by streams. It helps us to flatten the data structure to simplify further operations.
                Stream< List< String>> namesOriginalList = Stream.of(
                        Arrays.asList("Sajib"),
                        Arrays.asList("Salman", "Anitam"),
                        Arrays.asList("Sazzad"));
               namesOriginalList.flatMap(strList -> strList.stream())
                       .forEach(System.out::println); 
    
In real scenario, usually several intermediate operations are chained.
        List myList = Arrays.asList( "b1", "a1", "a2", "c2", "c1");
        myList.stream()
                .filter(s -> s.startsWith("c"))
                .map(String::toUpperCase)
                .sorted()
                .forEach(System.out::println);

Terminal Operations
Computation on the source data is only performed when the terminal operation is initiated, and source elements are consumed only as needed. All intermediate operations are lazy, so they're not executed until a result of a processing is actually needed. Here are some common stream terminal operations:
  • count: We can use this terminal operation to count the number of items in the stream.
            List myList = Arrays.asList( "b1", "a1", "a2", "c2", "c1");
            System.out.println(myList.stream().count());
    
  • forEach: This can be used for iterating over the stream.
             List myList = Arrays.asList("b1", "a1", "a2", "c2", "c1");
                myList.stream()
                        .forEach(System.out::println);
    
    
  • collect: Collect is an extremely useful terminal operation to transform the elements of the stream into a different kind of result specially collection like List, Set or Map.
            List myList = Arrays.asList("b1", "a1", "a2", "c2", "c1");
            List filtered =myList.stream()
                    .filter(s -> s.startsWith("c"))
                    .collect(Collectors.toList());
            System.out.println(filtered);
    
    
  • findFirst: This is a short circuiting terminal operation. It Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.
            List myList = Arrays.asList("b1", "a1", "a2", "c2", "c1");
            Optional filtered = myList.stream()
                    .filter(s -> s.startsWith("c"))
                    .findFirst();
            if (filtered.isPresent()) {
                    System.out.println(filtered.get());            
            }
    

References:

Friday, March 29, 2019

Object Oriented Design Principles

The famous Head First Design Pattern book discusses 9 important Object Oriented Design principles.

Here are the summary of the those principle:
  1. Identify the aspects of your application that vary and separate them from what stays the same. Encapsulate what varies.
  2. Favor composition over inheritance.
  3. Program to an interface, not an implementation.
  4. Strive for loosely coupled designs between objects that interact.
  5. Classes should be open for extension, but closed for modification.
  6. Depend on abstractions. Do not depend on concrete classes (Dependency Inversion Principle). Guidelines to achieve dependency inversion principle:
    • No variable should hold a reference to a concrete class.
    • No class should derive from a concrete class.
    • No method should override an implemented method of any of its base classes.
  7. Principle of Least Knowledge - talk only to your immediate friends.
  8. The Hollywood principle - Don't call us, we'll call you.
  9. A class should have only one reason to change.

Observer Pattern

The Observer pattern defines a one to many dependency between objects so that when one object changes state, all of its dependent are notified and updated automatically.

Subject contains a list of observers to notify of any change in its state, so it should provide methods using which observers can register and unregister themselves. Subject also contain a method to notify all the observers of any change and either it can send the update while notifying the observer or it can provide another method to get the update.

Observer should have a method to set the object to watch and another method that will be used by Subject to notify them of any updates.

Category:
Behavioral design pattern

Example:
A good example can be found here.

Associated design principle:
Strive for loosely coupled designs between objects that interact.

Java’s built-in Observer pattern:
The java.util package has an implementation of observer pattern. The package has a Observer interface and Observable class. This is similar to Subject and Observer interface. The drawback here is Observable is a class not interface.

Here is a UML diagram taken from Head First Design pattern to show usage of java’s build-in Observer pattern:


Pros:
  • Provides a loosely coupled design between objects that interact.
    • Subject only knows that observer implement Observer interface. Nothing more.
    • There is no need to modify Subject to add or remove observers.
    • We can reuse subject and observer classes independently of each other.
  • Allows you to send data to many other objects in a very efficient manner.
  • Follows the Open/Closed Principle.

Cons:
  • Subscribers are notified in random order.

References:

Sunday, February 10, 2019

Strategy pattern

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Category:
Behavioral design pattern

The problem to solve:
Suppose we have many kinds of ducks. They can fly in many ways and can quack in many ways. The trivial way to solve it is to use inheritance. There can be interfaces like Flyable and Quackable. The concrete duck implementations can implement the Flyable and Quackable interfaces. The problem here is that several ducks can have same fly behavior or quack behavior. Code will be duplicated in such cases.

Solution:
Composition is used to solve the problem. There will be interfaces for Fly behavior and Quack behavior. Concrete implementations of Fly behavior and Quack behavior will be treated as family of algorithms. The concrete duck implementations will be composed of Fly behavior and Quack behavior interfaces.

Code Example:
Head first duck example is good. Springframework guru has shown a good example also.

UML:
The following UML diagram is from Head First Design Pattern book:


Where to apply:
  • Use the Strategy pattern when you want to use different variants of an algorithm within an object and be able to switch from one algorithm to another during runtime.
  • Use the Strategy when you have a lot of similar classes that only differ in the way they execute some behavior.
  • Use the pattern to isolate the business logic of a class from the implementation details of algorithms that may not be as important in the context of that logic.
  • Use the pattern when your class has a massive conditional operator that switches between different variants of the same algorithm.

Associated design principles:
  • Identify the aspects of your application that vary and separate them from what stays the same. Encapsulate what varies.
  • Favor composition over inheritance.
  • Program to an interface, not an implementation.

Pros:
  • Prevents the conditional statements. (switch, if, else…)
  • The algorithms are loosely coupled with the context entity. They can be changed/replaced without changing the context entity.
  • Very easy extendable.
  • Allows hot swapping algorithms at runtime.
  • Isolates the code and data of the algorithms from the other classes.
  • Replaces inheritance with delegation/composition

Cons:
  • Clients must know existence of different strategies and a client must understand how the Strategies differ. Client must be aware of the differences between strategies to pick a proper one.
  • It increases the number of objects in the application. Increases overall code complexity by creating multiple additional classes.

References:

Saturday, February 9, 2019

Lambda Expressions Best Practices

1. Prefer standard functional interfaces
We should apply the standard functional interfaces from package java.util.function whenever applicable. There are six basic functional interfaces that we can remember for convenience. The other standard functional interfaces can be derived the basic ones easily.


* The above table is taken from book Effective Java 3rd edition

Here an example applying Predicate and Consumer:
  public static void main(String[] args) {
    List personList = Arrays.asList(
        new Person("Sajib", "Amin", 34),
        new Person("Salman", "Rishad", 34),
        new Person("Shafiul", "Hasan", 34),
        new Person("Anitam", "Das", 26),
        new Person("Khaled", "Sazzad", 26));
    
    Collections.sort(personList, (p1, p2) -> 
     p1.getLastName().compareTo(p2.getLastName()));
    printConditionally(personList, 
     p -> p.getFirstName().startsWith("S"),
        p -> System.out.println(p.getFirstName()));
  }

  private static void printConditionally(List personList, 
   Predicate predicate, Consumer consumer) {
    for (Person p : personList) {
          if (predicate.test(p)) {
              consumer.accept(p);
         }
    }
  }

2. Use the @FunctionalInterface annotation
We should annotate our custom functional interfaces with @FunctionalInterface. If we don’t annotate, other developers can accidentally add more abstract methods and break the conditions of using it as a functional interface.

3. Don’t overuse default methods in functional interfaces
We should not make excessive use of default methods in a functional interface. Excessive use can introduce situations where default method with same name will exist in two separate interfaces and another interface is trying to extend them both.
Adding too many default methods to the interface is not a very good architectural decision. It is should be viewed as a compromise, only to be used when required, for upgrading existing interfaces without breaking backward compatibility.

4. Prefer lambdas to anonymous classes
A functional interface can be implemented using an anonymous inner class. But, that should be avoided as much as possible. Lambda expression should be used in such cases. For example, here is an anonymous inner class implementation of Comparator:
    Collections.sort(wordList, new Comparator() {
          @Override
          public int compare(String s1, String s2) {
                return s1.compareTo(s2);
          }
    });

It should be replaced with lambda expression like
    Collections.sort(wordList, (s1, s2) -> s1.compareTo(s2));

5. Avoid overloading methods with functional interfaces as parameters
When functional interfaces are used as parameters in method, we should avoid overloaded use of them. Method with different name can be used to avoid collision. A good example is available here.

6. Don’t treat lambda expressions as inner classes
When we instantiate an inner class, it creates a new scope. We can overwrite local variables from the enclosing scope by instantiating new local variables with the same names. We can also use the keyword this inside our inner class as a reference to its instance.
Lambda expression does not create its own scope, it relies on the enclosing scope. We can’t overwrite variables from the enclosing scope inside the lambda’s body. In this case, the keyword this is a reference to an enclosing instance. A good example is available here.

7. Use effectively final variables
Lambda expressions can access final variables only. Accessing a non-final variable inside lambda expressions will cause the compile-time error. However, we do not need to mark the variable with final keyword. As long as the variable is assigned value only once, compiler will treat it as effectively final.

8. Keep lambda expressions short and self-explanatory
a) Avoid blocks of code in lambda’s body
One liner is ideal for lambda expression. Large block of code can be encapsulated inside a method in some cases.

b) Avoid specifying parameter types
Parameter types are usually omitted. (a, b) -> should be used instead of (String a, String b) ->

c) Avoid parentheses around a single parameter
For single parameter, use of parentheses is unnecessary. a -> should be used instead if (a) ->

d) Avoid return statement and braces
Braces and return statements are optional in one liner lambda expression. So, a -> a.toLowerCase() should be used instead of a -> {return a.toLowerCase()}

e) Use method references
Method reference is already discussed in previous post. It is recommended to replace lambda expression with method reference whenever it is applicable.


References:

Friday, February 1, 2019

Lamda Expressions Concepts


Lambda expression leverages functional programming in Java. Lambda expression contains the implementation of a single function within the instance of an interface. The close similarity of lambda expression is anonymous inner class implementation of an interface.

Lambda expressions implement functional interfaces. A functional interface is an interface that can contain only one abstract method. A functional interface can however contain several default methods and static methods.

Let's define one functional interface like the following:
  @FunctionalInterface
  public interface Greeting {
    public void sayGreeting(String message);
  }

Here use of annotation @FunctionalInterface is recommended since it enforces to use only one abstract method. Lets first implement it with anonymous inner class:
    Greeting greetingImpl = new Greeting() {
          @Override
          public void sayGreeting(String message) {
                System.out.println(message);
          }
    };
    greetingImpl.sayGreeting("Hello from Anonymous inner class.");

Using lambda expression for doing the same task will make the code shorter and cleaner.
    Greeting greetingLambda = message -> System.out.println(message);
    greetingLambda.sayGreeting("Hello from Lambda expression");
Lambda expression syntax:
(argument-list) -> {body}
Java lambda expression is consisted of three parts:
  • Argument-list: It can be empty or non-empty.
  • Arrow-token: It is used to link arguments-list and body of expression.
  • Body: It contains expressions and statements for lambda expression.
Type declaration can be included
MathOperation addition = (int a, int b) -> a + b;
Type declaration can be omitted
MathOperation subtraction = (a, b) -> a - b;
Lambda expression can contain return statement along with curly braces
    MathOperation multiplication = (int a, int b) -> {
          return a * b;
    };
Lambda as method argument:
We can pass both lambda expression as method arguments. For example, let’s consider a method:
  public static void callWithLambda(Greeting greeting, String message) {
    greeting.sayGreeting(message);
  }

We can call the above method like the following:
    callWithLambda(message -> System.out.println(message), 
          "Lambda argument pass test1");

Generic Functional Interfaces
Functional interfaces can be generic.
@FunctionalInterface
interface GenericInterface {
  void test(T param);
}
Lambda expression can associate with generic functional interfaces.
    GenericInterface genericInterface1 = (str) -> System.out.println(str);
    genericInterface1.test("Test generic interface with type string");
    
    GenericInterface genericInterface2 = (i) -> System.out.println(i);
    genericInterface2.test(5);
Method Reference:
There is a shortcut of using lambda expression. That is called method reference. It will make code even shorter. Double colon (::) is used as the syntax of method reference.
Greeting greetingLambda = message -> System.out.println(message);
Equivalent use of method reference
    Greeting greetingMethodReference = System.out::println;
    greetingMethodReference.sayGreeting("Hello from method reference");
Can be used as method argument also:
callWithLambda(System.out::println, "Lambda argument pass test2");
We can reference the following types of methods:
  • Static method:
    public static void defaultGeeting(String message) {
        System.out.println(message);
      }
    callWithLambda(LambdaTest::defaultGeeting, "Static method reference");
    
  • Instance method on parameter objects:
    Finder finder = (s1, s2) -> s1.indexOf(s2);
    
    By using method reference
    Finder finder = String::indexOf;
    
  • Instance method:
    StringConverter stringConverter = new StringConverter();
    
    Deserializer des = stringConverter::convertToInt;
    
  • Constructor:
    It is possible to refer a constructor of a class. We can do that by using ::new as like the following example. Here the functional interface is like
        public interface Factory {
                public String create(char[] val);
        }
    
    Using regular lambda
    Factory factory = chars -> new String(chars);
    
    Using constructor reference
    Factory factory = String::new;
    

References:

Saturday, January 26, 2019

SOLID Principles (part 2)

3. Liskov Substitution Principle: “Derived classes must be substitutable for their base classes. Objects should be replaceable with instances of their subtypes without altering the correctness of that program.” LSP is all about well designed inheritance.
  • An overridden method of a subclass needs to accept the same input parameter values as the method of the superclass. That means we can implement less restrictive validation rules, but we are not allowed to enforce stricter ones in our subclass. Otherwise, any code that calls this method on an object of the superclass might cause an exception, if it gets called with an object of the subclass.
  • Similar rules apply to the return value of the method. The return value of a method of the subclass needs to comply with the same rules as the return value of the method of the superclass. We can only decide to apply even stricter rules by returning a specific subclass of the defined return value, or by returning a subset of the valid return values of the superclass.
  • No new exceptions can be thrown by the subtype unless they are part of the existing exception hierarchy.
  • We should also ensure that Clients should not know which specific subtype they are calling, nor should they need to know that. The client should behave the same regardless of the subtype instance that it is given.
  • New derived classes just extend without replacing the functionality of old classes.
One example of LSP can be found here .

There are situations where we can not apply LSP or subclassing. 3D Board game example of Head First’s ‘Object Oriented Analysis and Design’ book is good example of such case. When subclassing cannot be used, we have several other options to solve the problem:
  • Delegation: When we handover the responsibility of a particular task to another class or method (Using concrete class).
  • Composition: Allows us to use behavior from a family of other classes and to change that behavior at runtime (Using interface or abstraction). In composition, the object composed of the other behaviors owns those behaviors. When the object is destroyed, so are all of its behavior. The behaviors do not exist outside of the composition itself.
  • Aggregation: When one class is used as part of another class, but still exists outside of that other class. We we want the benefits of composition, but we are using behavior from an object that exist outside of our project, we use aggregation.

4. Interface Segregation Principle: “Clients should not be forced to depend upon interfaces that they do not use.”

Instead of one fat interface, many small interfaces are preferred based on groups of methods with each one serving one sub-module.

Similar to the Single Responsibility Principle, the goal of the Interface Segregation Principle is to reduce the side effects and frequency of required changes by splitting the software into multiple, independent parts.

One example of ISP can be found here .

5. Dependency Inversion Principle: “Depend on abstractions, not on concretions.”
  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend on details. Details should depend on abstractions.
  • An important detail of this definition is, that high-level and low-level modules depend on the abstraction. the high-level module depends on the abstraction, and the low-level depends on the same abstraction.

One example of DIP can be found here .

References:

Friday, January 25, 2019

SOLID Principles (part 1)

SOLID, an acronym for five design principles, was first introduced by Michael Feathers. The principles are a subset of many principles promoted by Robert C. Martin (“Uncle Bob”).

SOLID Acronym
  • Single Responsibility Principle (SRP)
  • Open closed Principle (OSP)
  • Liskov substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)

1. Single Responsibility Principle: “A class should have one, and only one, reason to change.”

Every module/class should have the responsibility over a single portion of the functionality provided by the overall system/software, and that responsibility should be entirely encapsulated by the class.

When new requirements will be introduced, the code has to undergo some changes, meaning that the classes have to be modified. The more responsibilities a class will have, the more change requests it will get. And it will be harder to implement those changes.

In Single Responsibility Principle, each class and module should focus on a single task at a time. Everything in the class should be related to that single purpose. There can be many members in the class as long as they related to the single responsibility.

One example of SRP can be found here.

2. Open/Closed Principle: “Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”

There are many ways we can apply OCP. The easiest way to apply OCP is to inherit the original class and implement the new functionality on that new derived class.

But, inheritance can introduce tight coupling if the subclasses depend on implementation details of their parent class. That’s why Robert C. Martin and others redefined OCP to the Polymorphic OCP. It uses interfaces instead of superclasses to allow different implementations which you can easily substitute without changing the code that uses them. The interfaces are closed for modifications, and you can provide new implementations to extend the functionality of your software.

One example of OCP can be found here .


References: