Thursday, May 25, 2017

Functional Interfaces - Default and static methods

A cheat sheet is all that is needed to start using Java Lambdas. But here I will start with the design changes done in Java8 in order to accommodate Lambdas.

Most of the interfaces in the JDK have only method. (Comparator, Runnable, Callable, etc) These are Single Abstract Method interfaces. These SAM concepts are recreated in Java8 using Functional Interfaces. Since a lambda function can only provide implementation for one method, it is mandatory for your functional interface to have ONLY ONE interface

Functional Interface

Interface with only one abstract method.

Methods from the Object class do not count. i.e. The interface can also declare the abstract methods from the java.lang.Object class, but still the interface can be called as a Functional Interface. Example 

@FunctionalInterface

public interface SimpleFunctionalInterface {

  public void doWork();

  public boolean equals(Object o);

}


It can also have
- static methods 
- default methods

Note that the @FunctionalInterface is optional. It is just for convenience - the compiler can warn if it is not really a functional interface.

So what is the type of lambda expression? - Functional Interface
Is lambda expression an object? Well, it can be moved around like an object. An anonymous class is created with new. So I am explicitly asking JVM to create a new object (which is an overhead). but when I ask for a lamba, it is still recorded as an object in the JVM. But it is an object of a new kind in java8 - an object without an identity. I know this sounds complex. I will have a separate write-up on this. For now, the answer is no.

Default methods

In order to introduce lambda to Java 8, I need to add a forEach method to Iterable interface. Which will result in compilation error since all the classes that extends Iterable should provide an implementation for forEach. So I will be breaking the backward compatibility. 

Hence the default methods. A new Java8 concept to change the old interfaces without breaking the existing implementations. It provides flexibility to allow interface define implementation which will use as default in the situation where a concrete class fails to provide an implementation for that method. Meaning, they can be overridden. 

So what happens when the classes is implementing 2 interfaces with same default method signatures?

public interface InterfaceA {

    default void defaultMethod(){

        System.out.println("Interface A default method");

    }

}

public interface InterfaceB {

    default void defaultMethod(){

        System.out.println("Interface B default method");

    }

}

public class Impl implements InterfaceA, InterfaceB  {

}


So in these cases, to avoid compilation error, you have to provide your own implementation.
You can even choose to call either of the default methods like this:


public class Impl implements InterfaceA, InterfaceB {

    public void defaultMethod(){

        // existing code here..

        InterfaceA.super.defaultMethod();

    }

}

Summary:


When we extend an interface that contains a default method, we can perform following,
  • Override the default method similar to other methods we override in subclass..
  • Not override the default method and will inherit the default method.
  • Redeclare default method as abstract, which force subclass to override it.

Static Methods

The static methods in interfaces are good for providing utility methods.
Eg : isEquals in java.util.function.Predicate & identity in java.util.function.Function
We can’t define interface static method for Object class methods, we will get compiler error
as “This static method cannot hide the instance method from Object”. This is because
it’s not allowed in java, since Object is the base class for all the classes and we can’t have
one class level static method and another instance method with same signature.
These cannot be not overriden. if you think about it, it makes sense. Say I am providing a isNull
utility in my interface so that the implementations do it right, then I will prevent that
to be overridden
Now let us talk about the inheritance part a bit more. How about static methods in class?
public class SuperClass {
 public static void foo()
 {
  System.out.println("super class static");
 }
}

public class SubClass extends SuperClass{
 public static void foo()
 {
  System.out.println("sub class foo");
 }
}

public class App {
 public static void main(String[] args) {
  SuperClass.foo();
  SubClass.foo();
 }
}
This would have printed :
super class static sub class foo
What if there is no foo() in SubClass
public class SubClass extends SuperClass{
}
It still works :
super class static super class static
Now let us talk about static methods in interface
public interface SuperInterface {
 public static void foo()
 {
  System.out.println("super interface static");
 }
}
public interface SubInterface extends SuperInterface{
 public static void foo()
 {
  System.out.println("sub interface static");
 }
}

public class App {
 public static void main(String[] args) {
  SuperInterface.foo();
  SubInterface.foo();
 }
} 
Prints :
super interface static sub interface static
What if there is not foo in SubInterface? 
public interface SubInterface extends SuperInterface{
}

public class App {
 public static void main(String[] args) {
  SuperInterface.foo();
  SubInterface.foo(); -> compilation error }
}
Similarly, the following will work fine. Both class and interface can have static methods with same names, and neither overrides other
public class SomeClass implements SuperInterface{
 public static void foo()
 {
  SuperInterface.foo();
 }
}
public class App {
 public static void main(String[] args) {
  SomeClass.foo();
 }
}
but the moment you remove foo from SomeClass, it will result in compilation error
public class SomeClass implements SuperInterface{
}

public class App {
 public static void main(String[] args) {
  SomeClass.foo(); -> compilation error }
}
So why default can be inherited and static cannot? These are my favorite answer from stackoverflow.
1) A static method is a method that's associated with the class in which it's defined, rather than with any object created from that class. Every instance of the class shares the static methods of the class. Java 8 also lets static methods be defined in interfaces where they can assist default methods.
When you implement an interface that contains a static method, the static method is still part of the interface and not part of the implementing class. For this reason, you cannot prefix the method with the class name. Instead, you must prefix the method with the interface name
2) Static methods in interfaces could create a diamond of death if they were being inherited. So, calling a static method from the appropriate interface is good enough compared to the risk of calling it from a concrete class that may implement multiple interfaces that contain static methods of the same name.
Why are static methods any different?
Static methods are just functions unrelated to the objects. Instead of placing them in utility abstract classes (like calling Collections.sort() ) we move those functions (static methods) to their appropriate interfaces. They could be bound to the inherited objects like the default methods do, but that is not their job. Static methods provide functionality which is unrelated to the instances of the class.
Example:
interface Floatable {

    default void float() {
        // implementation
    }

    static boolean checkIfItCanFloat(Object fl) {
         // some physics here
    } 
}

class Duck implements Floatable { }
So, the point is that a Duck may float but the function that checks if an Object really floats is not something that a Duck can do. It is an irrelevant functionallity that we could pass to our Floatable interface instead of having it sit inside some utility class.

References :

Thursday, May 18, 2017

Parameterized Junit test

I have used the Parameterized Junit test in places where you need to test a method with huge combinations of input. Imagine a truth table logic in place.
Form the truth table -> let's take 2 inputs for simplicity sake.
A
B
Expected
1
1
1
1
0
1
0
1
1
0
0
0

Say if the method is,
Method(param1, param2)
Now if I have to go with the conventional junit test cases, I would have to name my methods like,
  • testMethodForParam1TrueParam2False()
  • testMethodForParam1TrueParam2True()
  • testMethodForParam1FalseParam2True()
  • testMethodForParam1FalseParam2False()
Sure it looks readable now. But consider the same for a 3 X 3 matrix. It becomes ugly.
Wouldn't it better to actually have this truth table in the start of the test case and feed it to just one test?
This is exactly what Parameterized Junit solves.
There are various blogs and sources to refer the syntax of such test.
But when you want to use it in an integration test, you need to keep the following in mind.
  1. As long as your data is static, you have nothing to worry about. Say, your service which contains the method, is initialized in @BeforeClass and in your @Parameterized.Parameters the data you feed is coming from a static method in that service. Then you will get NPE. Because @Parameters is called before @BeforeClass. To tackle this, have your initialization in a simple static block. But then, you need to make the test class final. @BeforeClass will apply to all the inherited classes, static block will not.
    package com.foo;
    
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertNotNull;
    
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Date;
    import java.util.List;
    import java.util.Optional;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    
    
    @RunWith(Parameterized.class)
    public final class ServiceTest {
     private static Service service;
    
     private Integer param1;
     private Integer param2;
     private Integer expectedResult;
     private String caseName;
    
     static {
     setUpClass();
     }
    
     public static void setUpClass() {
     service = (Service) CustomContextLoader.getBean("service");
     }
    
     public ServiceTest(String caseName, Integer param1, Integer param2, Integer expectedResult) {
     this.caseName = caseName;
     this.param1 = param1;
     this.param2 = param2;
     this.expectedResult = expectedResult;
     }
    
     @Parameterized.Parameters
     public static Iterable<Object[]> testData()
     {
     return Arrays.asList(new Object[][]{
     { "case 1 : 1 1 = 1", 1, 1, 1},
     { "case 2 : 1 0 = 1", 1, 0, 1},
     { "case 3 : 0 1 = 1", 0, 1, 1},
     { "case 4 : 0 0 = 0", 0, 0, 0},
     });
    
     }
    
     @Before
     public void setup() {
     System.out.println("@Before");
     }
    
     @Test
     public void testMethod() {
     Integer result = service.orMethod(this.param1, this.param2);
     assertEquals(this.caseName+" failed", this.expectedResult, result);
     }
    
    }
    Remember the order of execution
    Static block
    @Parameter
    @BeforeClass
    @Before
    @Test
    For my case, I had to bootstrap some data (think of inserting some rule and referencing that throughout your test case using an ID. In such case I need to insert the rule and get the ID before I can setup the data) before I can set test data. Hence it was important for the service to be initialized before it hit the @Parameters method. I could not use @BeforeClass because it gets executed after @Parameters. Hence I had to resort to static method.
  2. Add a description for each test data you setup in the @Parameters. and add this to the assertion string. This will help identify which dataset is failing. Because, since this is parameterized test, the test results would be printed something like this:
    com.foo.ServiceTest > testMethod[0] PASSED
    com.foo.ServiceTest > testMethod[1] PASSED
    com.foo.ServiceTest > testMethod[2] FAILED
    java.lang.AssertionError
    com.foo.ServiceTest > testMethod[3] PASSED
    Now if you have setup a caseName with the testData, you will spend less time debugging the issue.
    com.foo.ServiceTest > testMethod[0] PASSED
    com.foo.ServiceTest > testMethod[1] PASSED
    com.foo.ServiceTest > testMethod[2] FAILED
    java.lang.AssertionError : case 3 : 0 1 = 1 failed
    com.foo.ServiceTest > testMethod[3] PASSED
    Also note that the parameterized junit test runs like there are separate @Test methods for all of those data sets. Means it will continue running all the tests even if one fails. It is not fail-fast.

KeySet And UnsupportedOperationException

package com.foo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Test;

public class SomeTest {
 @Test
 public void test() {
 Map<String, Set<String>> movieToActorsName = new HashMap<>();
 Set<String> actors = new HashSet<>();
 actors.add("Dan");
 actors.add("Emma");
 movieToActorsName.put("HP", actors);
 Map<String, Set<String>> someMap = new HashMap<>();
 someMap.put("Movies", new HashSet<>(movieToActorsName.keySet()));
 someMap.values().stream().forEach(s -> {
 s.add("dummy");
 });
 someMap = new HashMap<>();
 someMap.put("Movies", movieToActorsName.keySet());
 someMap.values().stream().forEach(s -> {
 s.add("dummy"); // UnsupporrtedOperationException. Because keySet() is immutable.
 });
 }
}
Keyset is basically just a view of the keys in the map. So If you call remove() on the keyset, it will actually remove the entry for that key in the map.
I found this common where people directly take keySet of a map into a placeholder, which will be modified in the later part of the code. The following is wrong.
placeHolderMap.put(id, referenceMap.keySet());
And this is right.
placeHolderMap.put(id, new HashSet<>(referenceMap.keySet()));
or
placeHolderMap.put(id, referenceMap.keySet().stream().collect(Collectors.toSet()));