January 11, 2019

Implementing java.util.function.DoubleConsumer in java, and using random numbers to test it.

Java provides a lot of Functional Interface , some are generic , can be used by all the data-types, whereas some are specialised for primitive types.

Reasons, that I can think of are,

  1. they are a providing interfaces, which are going to be used most often
  2. second, they are providing some compiler magic to optimize these interfaces.
  3.  third reason that, I can think of is, It does not need to unbox Double to double. From a Wrapper to a primitive type

Means Wrapper class is not used in the method parameter, that’s why, you won’t see any performance hit, because no boxing and unboxing happening in here.

DoubleConsumer is a specialised version of java.util.function.Consumer. It accepts an input of type double. It has one abstract function and one default function.

We can implement DoubleConsumer in terms of Consumer interface, too.

Like this.

Consumer<Double> lessThan = (dblValue) -> System.out.println(dblValue < 10);

But, there is an issue here. If you are using this function a lot of times. Then Unboxing from Double to double, the performance penalty is going to hit in your face.

List of methods that comes with this awesomeness.

  1. void accept(double value) :- it takes a double value and does not return anything.
  2. DoubleConsumer andThen(DoubleConsumer after) :- It creates a new DoubleConsumer, which executes two DoubleConsumer in sequence.

For the implementation of these methods, we are going to use lambda expressions. Because, this is how we should be coding in java-8 and above.

So, we are going to create lambdas, which will print a message. The message will tell us that the double value is less than or equal to or greater than a particular value;

And that particular value is defined as final, it is not necessary to define it as final, it will work if a value is effectively final too.
But, declaring final makes, it more readable and less tricky. You don’t have to check indices in your head to find the reason for it. I am saving your cognitive resources. 🙂

final double testDoubleValue = 10;

So, our lambdas will be running comparison against 10. 🙂

LessThan Lambda

DoubleConsumer lessThan = (dblValue) -> out.println(dblValue + " is less Than testDoubleValue " + (dblValue < testDoubleValue));

EqualTo Lambda

DoubleConsumer equalTo = (dblValue) ->  out.println(dblValue + " is equal to testDoubleValue " + (dblValue == testDoubleValue));

GreaterThan Lambda

DoubleConsumer greaterThan = (dblValue) ->   out.println(dblValue + " is greater than testDoubleValue " + (dblValue > testDoubleValue));

From here onwards, we are going to use function composition to creater new lambdas.

LessThanEqualTo Lambda

DoubleConsumer lessThanEqualTo = lessThan.andThen(equalTo);

LessThanGreaterThan Lambda

DoubleConsumer lessThanGreaterThan = lessThan.andThen(greaterThan);

LessThanEqualToGreaterThan Lambda

DoubleConsumer lessThanAndEqualToAndGreaterThan = lessThan.andThen(equalTo).andThen(greaterThan);

To test all the above lambdas, we have created a utility function, which is a variadic function. That means it can take more than one argument for a single parameter.

static void run(DoubleConsumer... dblConsumers) {                                                                                                                                                        
   for(DoubleConsumer consumer : dblConsumers) {                                                                                                                                                        
       consumer .accept(Math.random() * 15);                                                                                                                                                            
      out.println();                                                                                                                                                                                   
   }                                                                                                                                                                                                    
}

The above function takes a variable number of implementations for DoubleConsumer. We should also note a point here, we are actually passing functions as argument to other functions.

The lambdas can be passed around.

So, our this function will loop over all the lambdas in the array and call the accept method with a variable number passed to it.

consumer .accept(Math.random() * 15);

We are multiplying by 15, because the test value is our lambdas is 10. So, I want random numbers between 1-15.
If you look at the output, below. You can observe that, the random number passed to composed function, is passed on to the individual function. And this process happens in sequence. The random value does not change
from one lamba to another lambda, within a composed function.

Ok engineers, happy coding. I will keep adding more to this text.

Full Code 

import java.util.function.DoubleConsumer;                                                                                                                                                                    
import static java.lang.System.out;                                                                                                                                                                          
public class DoubleConsumerTest {                                                                                                                                                                            
    public static void main(String ... args) {                                                                                                                                                               
        final double testDoubleValue = 10;                                                                                                                                                                   
        DoubleConsumer lessThan = (dblValue) -> out.println(dblValue + " is less Than testDoubleValue " + (dblValue < testDoubleValue));                                                                     
        DoubleConsumer equalTo = (dblValue) ->  out.println(dblValue + " is equal to testDoubleValue " + (dblValue == testDoubleValue));                                                                     
        DoubleConsumer greaterThan = (dblValue) ->   out.println(dblValue + " is greater than testDoubleValue " + (dblValue > testDoubleValue));                                                             
                                                                                                                                                                                                             
        DoubleConsumer lessThanEqualTo = lessThan.andThen(equalTo);                                                                                                                                          
        DoubleConsumer lessThanGreaterThan = lessThan.andThen(greaterThan);                                                                                                                                  
        DoubleConsumer lessThanAndEqualToAndGreaterThan = lessThan.andThen(equalTo).andThen(greaterThan);                                                                                                               
                                                                                                                                                                                                             
        run(lessThan, equalTo, greaterThan, lessThanEqualTo, lessThanGreaterThan, lessThanAndEqualToAndGreaterThan);                                                                                                    
    }                                                                                                                                                                                                        
                                                                                                                                                                                                             
    static void run(DoubleConsumer... dblConsumers) {                                                                                                                                                        
        for(DoubleConsumer consumer : dblConsumers) {                                                                                                                                                        
            consumer .accept(Math.random() * 15);                                                                                                                                                            
            out.println();                                                                                                                                                                                   
        }                                                                                                                                                                                                    
    }                                                                                                                                                                                                        
}

Output

6.370191511066608 is less Than 10 true

10.386662480422233 is equal to 10 false

8.363848634433765 is greater than 10 false

0.9814255397917293 is less Than 10 true
0.9814255397917293 is equal to 10 false

0.9873687251610019 is less Than 10 true
0.9873687251610019 is greater than 10 false

3.992694523729556 is less Than 10 true
3.992694523729556 is equal to 10 false
3.992694523729556 is greater than 10 false