Thursday, August 14, 2014

stream(), map(), reduce() in Java 8

Java 8 has been around since March this year and I finally have gotten around to playing with it and in particular the functional programming aspects. 

I have seen people using these aspects through the Google Guava libraries but the huge number of nested classes messed up the code, adding a lot of clutter.

As can be seen from the below example, lambda expressions help get rid of the clutter. Further, what I really liked is that, if correctly used and I am no guru yet, it results in better code, which can tick all the boxes of the SOLID design principles.

Prior to Java 8
import java.util.ArrayList;
import java.util.List;

enum DecimalStringToBinaryMaskEnumMap {
    ZERO(0), ONE(1 << 0), TWO(1 << 1), FOUR(1 << 2), EIGHT(1 << 3), SIXTEEN(
            1 << 4);

    public static int getBinaryMaskFor(String value) {
        return DecimalStringToBinaryMaskEnumMap.valueOf(value).getBinaryValue();
    }

    public int getBinaryValue() {
        return binary;
    }

    private DecimalStringToBinaryMaskEnumMap(int binary) {
        this.binary = binary;
    }

    private int binary;
}

public class EnumMask {
    public int getMask(final List<String> decimalValues) {
        int mask = 0;
        for (final String decimalVal : decimalValues) {
            mask |= DecimalStringToBinaryMaskEnumMap.valueOf(decimalVal).getBinaryValue();
        }
        return mask;
    }

    public static void main(String[] args) {
        final List<String> decimalValues = new ArrayList<>();
        decimalValues.add("TWO");
        decimalValues.add("EIGHT");
        System.out.println(new EnumMask().getMask(decimalValues));
    }
}


Applying Java 8's functional programming idioms, we can replace the getMask function as below
public static final Function<String, Integer> stringToBinaryMaskIntegerFunction = valueString -> DecimalStringToBinaryMaskEnumMap
            .getBinaryMaskFor(valueString);

    public int getMask(final List<String> decimalValues) {
        return decimalValues.stream().
                map(stringToBinaryMaskIntegerFunction).
                reduce(0, (a,b) -> a | b);
    }

Breaking it down
* stream() - I see the result of this method to be analogous to the pipe on a UNIX shell, creating a pipeline of stages of processing. It returns a sequence of values to be consumed either in serial or parallel.
map(Function<InputType, OutputType>) - applies the function to convert the input to output and returns a stream of output values.There are other inbuilt map functions like mapToInt(), mapToLong() and mapToDouble()
*reduce() - in this case, reduces two operands into one masked value and repeatedly does this until there is only one result left. The operation needs to be associative as this could be executed in parallel.

Tuesday, October 15, 2013

String concatenation : Which do you prefer and why?

I believe blogs are a great platform for learning and sharing. I urge you to reply to this post with which method you prefer and if possible, a line or two explaining why.

Method 1: Good Plain Ol' Java
StringBuilder builder = new StringBuilder();
for(Object o : listOfObjects) { //listOfObjects is not null and not empty
      builder.append(o.toString());
      builder.append(",");
}
builder.deleteChatAt(builder.length()-1);
return builder.toString();

Method 2: Use Google Guava Libraries
return Joiner.on(",").join(listOfObjects);

My preference :
I do see the benefit of Method 2 in reduced number of lines and similarity to many dynamic programming languages like Python. However, I feel it lacks flexibility when compared to Method 1, where I can choose what I append to the resulting String.

What say you? 

Wednesday, August 7, 2013

When you use hashCode() for purposes it is not meant for

You get absurb results. The hashCode() of objects is not meant to be unique. It is a waste of time maintaining such code which uses Object.hashCode() as a key to retrieve results. Just find another way to generate those keys.

Here is the general contract for the method from the Javadoc 
"The general contract of hashCode is:
  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables. "

Focussing on the last point, we can see that hashCode() is not meant to be distinct. Two or more objects can return the same hashCode() so please don't use it as a key.

This blog suggests using the SHA to generate keys and GIT uses them or may be use UUIDs. Duh!!