↓ Skip to main content
Streams

Java Streams

·2 mins
Table of Contents

Stream is an new abstraction that lets one process data in a declarative way.

A stream does not store data and, in that sense, is not a data structure. It also never modifies the underlying data source.

The easiest way to learn a new API or a construct is by trying it. So here is an exercise that I tried to learn the Stream API. This is an exercise from exercism.io.

The problem is the famous grains problem doubling the number of grains on each square of the chess which has 64 squares (8x8).

I started of by keeping things simple having a LinkedHashMap that stores pre-initalized square and number of grains.

private Map<Integer, BigInteger> lHM = new LinkedHashMap<>();
private void Initialize() {
        for(int i=0; i<64; i++) {
            if (i == 0) {
                lHM.put(Integer.valueOf(1), BigInteger.ONE);
                continue;
            }
            lHM.put(i+1, lHM.get(i).multiply(BigInteger.TWO));
        }
    }

lHM defined is initalized for all the possible grain permutations for a 64 square board.

lHM.put(i+1, lHM.get(i).multiply(BigInteger.TWO));

E.g.

  • For every square > 1 we are putting Grains in the previous square * 2

This is very simple version of and had to be improved so time to use Streams.

import java.math.BigInteger;
import java.util.LinkedHashMap;
import java.util.Map;

import java.util.stream.IntStream;

/**
 * Grains on a board.
 * 1 + 2 + 6 + 18 + .......
 */
class Grains {

    BigInteger grainsOnSquare(final int square) {
        if (square < 1 || square > 64) {
            throw new IllegalArgumentException("square must be between 1 and 64");
        }
       return BigInteger.TWO.pow(square - 1);
    }

    BigInteger grainsOnBoard() {
        return IntStream.range(1, 65).mapToObj( i -> grainsOnSquare(i)).reduce(BigInteger::add).get();
    }

}

I did away with the data-structure and resorted to use simple Streams - IntStream.

For the method

grainsOnSquare

I have used pow method of BigInteger which simple calculates 2^(Square - 1)

  • 1st Square 2^0 = 1
  • 2nd Square 2^1 = 2
  • …. 4th Square 2^3 = 8

Now it is easier to read and optimised. How about the total grains here is where the streams come in handy for me as I do not have a DS storing any values.

IntStream.range(1, 65).mapToObj( i -> grainsOnSquare(i)).reduce(BigInteger::add).get();

I used the range() method to iterate between 1-64 as the second parameter is exclusive, and then for each square i I got the grainsOnSquare which was reduced using BigInteger.add and the final value is returned.

References
#

Author
Samarthya
Engineer, learner, tinkerer. This is my trophy shelf of everyday work and leisure.

Related

Writing Helm Charts

·8 mins
Helm is a dedicated package manager for Kubernetes. Although the Kubernetes objects are deployed in YAML’s there was a need to package and club them together and customise the deployment (not the K8S deployment).

Helm Charts: Packaging

·2 mins
Every software cycle includes packaging; which essentially describes how the software written is packaged and shared. For the software built for Containers Helm is a popular choice of packaging the scripts.

Deployments: K8S

·1 min
A declarative way of maintaining the desired state. Continuing my example from the last blog --- # Pod deployment apiVersion: apps/v1 kind: Deployment metadata: name: go-server-deployment spec: replicas: 2 selector: matchLabels: app: my-go-server template: metadata: labels: app: my-go-server spec: containers: - name: go-server image: samarthya/epserver:2.0 resources: limits: memory: "256Mi" cpu: "1024m" env: - name: SERVERPORT value: "9090" ports: - containerPort: 9090 # Reference - https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ In my deployment, I have two replicas configured, which can be increased to three using the command like the one below.