Java Streams Overview

For a long time, I had a gap in my knowledge of Java streams. On a basic level, I could use them, but I did not a deep understanding of them. So, I decided to do a quick overview of Java streams.

In this article, I will deal with many everything from the fundamentals to chaining and clean-up.

Hope this helps you broaden your knowledge of Java streams.

What Are Streams?

A stream is an ordered sequence of data that…

  • Provides a common I/O model
  • Abstracts details from an underlying source or destination

Whether you use streams to take data from memory, storage, or your network, it will hide the implementation details from you. The details are abstracted away, so in every situation, you can look at it as an ordered sequence of data.

storages
  • Stream types are uni-directional

This means that if you create an instance of a Java stream, you decide whether you would like to write to it or read from it. You can’t do both at the given time on a single stream.

Read / Write

We can divide the streams into two categories:

  • Byte streams – Interacts as binary data
  • Text streams – Interacts as unicode characters

The general interaction is the same for both Java stream types

Reading With Streams

As we mentioned, each stream is used either to read from or write to.

Firstly, let us see how we can read data from Java streams.

Java streams

The base class to read binary data in Java is the InputStreamAnd the base class to read text data is called the Readerclass.

Both classes almost have the same two methods:

  •  int read()
  •  int read(byte/char[] buff)

Notice that in both scenarios, they give back an Integer value. These are interpreted values. An integer is a 32-bit container, so it will work in both cases.

The difference between the two:

  • The InputStream works with bytes, which are 8-bits.
  • The Reader works with unicode characters, which are 16-bits.

Read Bytes With InputStream

InputStream input = // create input stream
int result;
while(result = input.read() >= 0) //Indicates the end-of-stream with a return value of -1
byte byteVal = (byte)result;
// do something with byteVal
};

Read Text with Reader

Reader reader = // create reader
int result;
while(result = reader.read() >= 0)//Indicates the end-of-stream with a return value of -1
char charVal = (char)result;
// do something with charVal
};

Note that if you would like to retrieve the value, you simply need to cast the result to the appropriate type — in this case, byte or char.

Writing With Streams

To write data, there are two base classes similar to the read streams.

  •  OutputStream (for bytes)
  •  Writer (for text)
Java Text streams
To write with Java streams is more straightforward than reading them. Both classes have a few   write  methods with the  void return type.

Writing Bytes With OutputStream

To write with OutputStream, you can pass a single byte the write method, or you can pass a byte array as well.

OutputStream output // create output stream;
Byte byteVal = 100;
output.write(byteVal);
byte[] byteBuff = {0, 10, 20};
output.write(byteBuff);

Writing Characters With Writer

To write with the Writer class, you can pass a simple character, character array, or String to its  write method.

Writer writer // create output stream;
char charVal = 'c';
writer.write(charVal);
char[] charArray = {'c', 'h', 'a', 'r'};
writer.write(charArray);
String stringVal = "String";
writer.write(stringVal);

As you can see, you need much less code to write than to read.

Common Java Stream Classes

Above, I wrote about the base stream classes. Now, let us go a bit deeper and talk about the different implementations.

Common Input/OutputStream Derived Classes

Java streams
  •  ByteArrayInputStream /  ByteArrayOutputStream – Enables us to create a stream over a byte array
  •  PipedInputStream PipedOutputStream – This is much like a producer-consumer concept. A piped output stream can be connected to a piped input stream to create a communications pipe. The piped output stream is the sending end of the pipe. Typically, data is written to a PipedOutputStream object by one thread and data is read from the connected PipedInputStream by some other thread.
  •  FileInputStream /  FileOutputStream – These allow us to create streams over files.

Common Reader/Writer Derived Classes

Java Reader/ Writer streams
Above are examples of Reader/Writer stream implementations.
  •  CharArrayReader / Writer – Allows creating streams over characters
  •  StringReader / Writer – Allows creating stream over Strings
  •  PipedReader / Writer – Allows creating a stream in a Producer/Consumer relationship over text. Similarly to the PipedOutput InputStream 
  •  InputStreamReader / Writer – Allows us to create a stream over an Input OutputStream 
  •  FileReader / Writer – These are delivered from the least mentioned above. It allows us to make a stream over text files.

Stream Errors and Clean-Up

So far, we looked at the general features of streams, but we have not considered all the realities of working with them.

Stream Realities

Java streams

Let us see the two main groups here.

Clean-Up

Problems

  • Streams are backed by physical storage, which often exists outside the Java runtime, like files or network connections.
  • Hence, Java may not reliably clean up, so we need to do our own reliable clean-up. We need to close the Streams when we are done with them.

Solutions

  • Streams implement the Closeable interface, which implements one single close method. So, this is our responsibility to call it.

Let us see a simple solution:

Reader reader;
try{
reader = // create output stream;
// do something with reader;
}catch (IOException e) {
//handle exception
}finally {
if(reader != null)
reader.close();
}

The problem with the above example is that you always need to implement it. Usually, we use Streams frequently, so it should be done automatically. Let us see how we can achieve it.

Automating Clean-Up

  •  AutoClosable interface
    • One method: close
    • The base interface of the Closable interface, so every Stream supports it.
    • Provides support for try-with-resources

Try-With-Resources

  • Automates the clean-up of one or more resources
    • A “resource” is any type that implements  AutoClosable
  • Syntax similar to traditional try statement
  • Optionally includes catch block(s)
    • Handle try body
    • Handle close method call

Working With Try-With-Resources

Here, I provided a simple example of how we can use the automatic close of streams with try-with-resources block.

I will use it through a FileInputStream. We will talk about this specific stream later.

 try(FileInputStream input = new FileInputStream("file1.txt")) {
        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    }

With the above approach, you do not need to investigate further work to close your streams.

Summary

In this article, we talked about the fundamentals of Java streams, what are they, how they work, and how you can use them. In my next article, I will dig a bit deeper, and I will write about more advanced Stream topics like chaining, buffered streams, and how to use file systems with it. So stay tuned!

See more about streams in the official Java documentation here.

RESTful API Design Principle: Deciding Levels of Granularity

Granularity is an essential principle of REST API design. As we understand, business functions divided into many small actions are fine-grained, and business functions divided into large operations are coarse-grained.

However, discussions about what level of granularity that needs to be in APIs may vary, we will get distinct suggestions, and even end up in debates. Regardless, its best to decide based upon business functions and its use cases, as granularity decisions would undoubtedly vary on a case by case basis.

This article discusses a few points on how API designers would need to choose their RESTful service granularity levels.

Image title

Coarse-Grained and Fine-Grained APIs

In some cases, calls across the network may be expensive, so to minimize them, coarse-grained APIs may be the best fit, as each request from the client forces lot of work at the server side, and in fine-grained, many calls are required to do the same amount of work at the client side.

Example: Consider a service returns customer orders in a single call. In case of fine-grained, it returns only the customer IDs, and for each customer id, the client needs to make an additional request to get details, so n+1 calls need to be made by the clients. It may be expensive round trips regarding its performance and response times over the network.

In a few other cases, APIs should be designed at the lowest practical level of granularity, because combining them is possible and allowed in ways that they suit the customer needs.

Example: An electronic form submission may need to collect addresses as well as, say, tax information. In this case, there are two functions: one is a collection of applicant’s whereabouts, and another is a collection of tax details. Each task needs to be addressed with a distinct API and requires a separate service because an address change is logically a different event and not related to tax time reporting, i.e., why one needs to submit the tax information (again) for an address change.

Levels of Granularity

Level of granularity should satisfy the specific needs of business functions or use cases. While the goal is to minimize calls across the network and for better performance, we must understand the set of operations that API consumers require and how they would give a better idea of the “correctly-grained” APIs in our designs.

At times, it may be appropriate that the API design supports both coarse-grained as well as fine-grained to give the flexibility for the API developers to choose the right APIs for their use cases.

Guidelines

The following points may serve as some basic guidelines for the readers to decide their APIs granularity levels in their API modeling.

  • In general, consider that the services may be coarse-grained, and APIs are fine-grained.
  • Maintain a balance between the amount of response data and the number of resources required to provide that data. It will help decide the granularity.
  • The types of performed operations on the data should also be considered as part of the design when defining the granularity.
  • Read requests are normally coarse-grained. Returning all information as required to render the page; it won’t hurt as much as two separate API calls in some cases.
  • On the other hand, write requests must be fine-grained. Find out everyday operations clients needs, and provide a specific API for that use case.
  • At times, you should use medium grained, i.e., neither fine-grained or coarse-grained. An example could be as seen in the following sample where the nested resources are within two levels deep.Image title

While the above guideline may understandably lead to more API deployment units, this can cause annoyances down the line. There are patterns, especially the API Gateway, that bring a better orchestration with those numerous APIs. Orchestrating the APIs with optimized endpoints, request collapsing, and much more helps in addressing the granularity challenges.

Sidecar Design Pattern in Your Microservices Ecosystem

The sidecar design pattern is gaining popularity and wider adoption within the community. Building a microservice architecture that is highly scalable, resilient, secure, and observable is challenging. The evolution of service mesh architecture has been a game changer. It shifts the complexity associated with microservice architecture to a separate infrastructure layer and provides a lot of functionalities like load balancing, service discovery, traffic management, circuit breaking, telemetry, fault injection, and more.

Read my last post to understand the concepts behind service mesh, why it is needed for your cloud native applications, and the reasons for its popularity: The Rise of Service Mesh Architecture.

What Is a Sidecar Pattern?

Segregating the functionalities of an application into a separate process can be viewed as a Sidecar pattern. The sidecar design pattern allows you to add a number of capabilities to your application without additional configuration code for third-party components.

As a sidecar is attached to a motorcycle, similarly in software architecture a sidecar is attached to a parent application and extends/enhances its functionalities. A sidecar is loosely coupled with the main application.

Let me explain this with an example. Imagine that you have six microservices talking with each other in order to determine the cost of a package.

Each microservice needs to have functionalities like observability, monitoring, logging, configuration, circuit breakers, and more. All these functionalities are implemented inside each of these microservices using some industry standard third-party libraries.

But, is this not redundant? Does it not increase the overall complexity of your application? What happens if your applications are written in different languages — how do you incorporate the third-party libraries which are generally specific to a language like .NET, Java, Python, etc.?

Benefits of Using a Sidecar Pattern:

  • Reduces the complexity in the microservice code by abstracting the common infrastructure-related functionalities to a different layer.
  • Reduces code duplication in a microservice architecture since you do not need to write configuration code inside each microservice.
  • Provide loose coupling between application code and the underlying platform.

How Does the Sidecar Pattern Work?

The service mesh layer can live in a sidecar container that runs alongside your application. Multiple copies of the same sidecar are attached alongside each of your applications.

All the incoming and outgoing network traffic from an individual service flows through the sidecar proxy. As a result, the sidecar manages the traffic flow between microservices, gathers telemetry data, and enforces policies. In a sense, the service is not aware of the network and knows only about the attached sidecar proxy. This is really the essence of how the sidecar pattern works — it abstracts away the network dependency to the sidecar.

Sidecar Design Pattern

Inside a service mesh, we have the concept of a data plane and a control plane.

  • The data plane’s responsibility is to handle the communication between the services inside the mesh and take care of the functionalities like service discovery, load balancing, traffic management, health checks, etc.
  • The control plane’s responsibility is to manage and configure the sidecar proxies to enforce policies and collect telemetry.

In the Kubernetes and Istio world, you can inject the sidecars inside a pod. Istio uses the sidecar model with Envoy as the proxy.

Envoy from Lyft is the most popular open source proxy designed for cloud native applications. Envoy runs along side every service and provides the necessary features in a platform agnostic manner. All traffic to your service flows through the Envoy proxy.
https://www.envoyproxy.io

The shift from monolith to microservices has enabled organizations to deploy applications independently and at scale. In a container and Kubernetes world, the sidecar design pattern is more compatible. The sidecars abstract away complexity from the application and handle functionalities like service discovery, traffic management, load balancing, circuit breaking, etc.

You can learn more about the sidecar pattern here:

Final Keyword and JVM Memory Impact

For a majority of developers, the keyword final is a well-known concept when we talk about composing a Java class. In general, it forbids the overriding of classes and methods, as well as changes a variable that has been already initialized. However, this is only one part (and I think the smaller part) of the final keyword definition. The other part is the connection to JVM memory, and that’s actually what this post is about!

I ‘d like to discuss this topic further by providing some examples, but if you want to really dive deeper, then I recommend Chapter 17 from Java Language Specification. Let’s dive right in!

Why Should I Bother Adding the Final Keyword?

I know that I’m not going to change the initialized value in my very small class, so why should care about this keyword; isn’t it just blowing up my concise Java source file?

NO! There is other cool stuff from the final keyword.

  • Guarantees visibility in a multi-threaded application
  • Safe initialization for objects, arrays, and collections

And please, don’t argue that you don’t use threads in your application — it is very likely that you use a framework that actually does, just under the hood.

How I Actually Reason With Object Initialization

Let’s step back a bit from the final keyword and demonstrate what object initialization might look like. It helps us understand where racing between threads may appear.

Image title

The picture above shows a small Java class and a description of how the initialization of that class could be done in reality. There is no concept of classes in a native language, which means the program needs to be expressed by instructions, one after another.

In this case, we can see that the object itself was created in the first line, and then, we populated the fields and published the reference to make it available and accessible. Everything looks fine, but there are several important considerations:

  • To make your program faster, the JVM and CPU can reorder the instructions to delay store instruction on some variable as late as possible. A very simple explanation would be: JVM and CPU can do everything with your code until the PROGRAM ORDER is satisfied. This means that the JVM can move store and read instructions but the behavior of your program must remain unchanged (we can go deeper into that in a different blog post).

So far, so good, but why am I supposed to be scared when the behavior of my program cannot be changed?

  • PROGRAM ORDER is followed only in a single thread. This means that if you run your application in a multi-threaded environment, then you have to inform the JVM that there is a possibility to complete a race condition when the JVM starts optimizing your code.
  • In a nutshell, it means that your second thread can see a partially initialized object, let’s say, because a step “publish reference (the last step from the picture) can be reordered with the field assignment “temp.y,” and then, the second thread will see a reference to the object with null value instead of the value “2.”

Let’s Introduce the Term: Safe Publication

The question is: How can we publish the shared object (a global variable) and be sure that all threads in our program will see the properly initialized object?

  • Initialize an object reference from a static initializer
    • This is a typical singleton holder pattern
    • The reason why this is safe is that because the JVM always performs object initialization on a single thread and ensures that the initialization happens before everything that uses that class (no other synchronization needed)
  • Use volatile or java.util.concurrent.atomic.Reference
  • Use locks to guard the global variable
  • Or … use the final field and never leak THIS from the constructor of the given class!

How Specification Ensures Safe Publication Using a Final Field

We already mentioned that the JVM or CPU is able to reorder everything and make your program faster. This means that we have to have some mechanism to inform the entire environment — please, don’t optimize this part.

  • JVM adds a synthetic freeze action (yes, this is an official name) before a constructor completes
    • Freeze action is added at runtime, and there is no bytecode instruction for this
  • Freeze ensures that the second thread sees null or an object reference with a fully constructed field, which was marked as final
  • On a CPU level, the freeze is implemented as a store barrier (sfence instruction on x86)
  • Other operations after the freeze are racing between two threads and must be properly synchronized

The JVM ensures that the second thread sees the state of the final field corresponding to the freeze action — no more, no less.

Image title

First, let’s agree on how I described steps of the execution:

  • Variabletemp is the given object that we want to publish.
  • Using  nfv = temp, we expose the publication of a reference of our object.
  •  <freeze value> means the point of the execution where the JVM inserts the freeze action.

On the picture above, we can see a very simple example of what can go wrong. We’ve already mentioned exactly this case which fails because of reordering the linetemp.value = 1 after the object publication nfv = temp.

On the contrary, the example on the right side shows fully and properly exposed our object to all threads. Freeze ensures that there is no reordering, which means that the publication of our object can be executed only when our field is properly pushed to a memory where it can be shared with other threads (Main Memory, or shared via Cache Coherence).

Image title

These examples show that the final field can help us correctly expose, even collections and arrays:

  • Collections and arrays are properly exposed, even with all the values inside.
  • The values inside the collection are properly exposed even if they don’t have final fields
  • BUT if we add a new value after the construction of our object, then this item is not supposed to be exposed properly, and Thread 2 can see the collection in both possible states.

Image title

The  Composition class shows a simple fact: Even if an object with non-final fields is exposed using a final field, then the inner object itself becomes properly exposed.

Image title

This example is very tricky. Don’t count on the behavior of an implementation, always code against the specification!

OpenJDK Hotspot behaves in a way that even if only one field is marked as final, it ensures that the freeze action is added “at the end of our constructor,” and flushing the CPU write buffers ensures that all other fields become visible to other threads. It works; you can check out other examples on my GitHub (link below) with JStress and give it a shot.
Image title

ConcurrentHashMap ensures that all values added to our Map are visible immediately to threads (internally synchronized).

However, it does not mean that the field holding the map, which is not marked as final, is visible to other threads after ConcurrentUtil construction. In this case, we can see the object with null value instead of initialized  ConcurrentHashMap.

What If I Cannot Use Final Fields…

We sometimes reach the situation where we are not able to modify a class and change all of its fields to final. So, is there any other way to expose the class properly with all the non-final fields?

We can use approaches that ensure we get safe publication for free:

  • Static Initializer (Singleton Holder pattern)
  • Thread-confinement
    • Run a block of code (task, job, HTTP request, …) only on one dedicated thread
    • Frameworks with a matured and well-document thread model, e.g. Event Loops
  • Stack-confinement
    • An object is reachable only through local variables
  • ThreadLocal
    • Maintains a per-thread value

Or, we can use some synchronization tools:

  • Synchronization block (implicit lock)
  • Explicit locks, volatile

The java.util.concurrent package, which does not ensure that a non-final field itself will be properly visible, contains objects that are used by those classes and makes sure they are properly exposed and visible to other threads. The classes below passes the object from one thread to another via some internal memory barrier (e.g. unsafe, or volatile field) that means that the object, which is created and written to any structure below by Thread A and then is read by Thread B, is fully constructed even if the object contains non-final fields.

Image title

  • CAS Operations
    •  Atomic*,  *AdderAtomic*FieldUpdater
  • java.util.concurrent package
    •  SynchronizedMapConcurrentHashMap
    •  CopyOnWriteArray(List|Set) 
    •  Synchronized(List|Set) 
    •  BlockingQueueConcurrentLinkedQueue
  •  VarHandlesUnsafe?

Thank you for reading my article and please leave comments below. If you would like to be notified about new posts, then start following me on Twitter: @p_bouda.

Introduction to Lombok

Java is often criticized for being unnecessarily verbose when compared with other languages. Lombok provides a bunch of annotations that generate boilerplate code in the background, removing it from your classes, and, therefore, helping to keep your code clean. Less boilerplate means more concise code that’s easier to read and maintain. In this post, I’ll cover the Lombok features I use more regularly and show you how they can be used to produce cleaner, more concise code.

Local Variable Type Inference: val and var

Lots of languages infer the local variable type by looking at the expression on the right-hand side of the equals. Although this is now supported in Java 10+, it wasn’t previously possible without the help of Lombok. The snippet below shows how you have to explicitly specify the local type:

final Map<String, Integer> map = new HashMap<>();
map.put("Joe", 21);

In Lombok, we can shorten this by using val as follows:

val valMap = new HashMap<String, Integer>();
valMap.put("Sam", 30);

Note that under the covers, val creates a variable that is final and immutable. If you need a mutable local variable, you can use var instead.

@NotNull

It’s generally not a bad idea to null check method arguments, especially if the method forms an API being used by other devs. While these checks are straightforward, they can become verbose, especially when you have multiple arguments. As shown below, the added bloat doesn’t help readability and can become a distraction from the main purpose of the method.

public void notNullDemo(Employee employee, Account account){
    if(employee == null){
      throw new IllegalArgumentException("Employee is marked @NotNull but is null");
    }
    if(account == null){
      throw new IllegalArgumentException("Account is marked @NotNull but is null");
  }
    // do stuff
}

Ideally, you want the null check — without all the noise. That’s where the @NotNull comes into play. By marking your parameters with @NotNull,  Lombok generates a null check for that parameter on your behalf. Your method suddenly becomes much cleaner, but without losing those defensive null checks.

public void notNullDemo(@NotNull Employee employee, @NotNull Account account){
      // just do stuff
}

By default, Lombok will throw a NullPointerException, but if you want, you can configure Lombok to throw an IllegalArgumentException. I personally prefer the IllegalArgumentException as I think its a better fit if you go to the bother of checking the arguments.

Cleaner Data Classes

Data classes are an area where Lombok can really help reduce boilerplate code. Before we look at the options, let’s consider what kinds of boilerplate we typically have to deal with. A data class typically includes one or all of the following:

  • A constructor (without or with arguments)
  • Getter methods for private member variables
  • Setter methods for private nonfinal member variables
  • toStringmethod to help with logging
  • equals and hashCode (dealing with equality/collections)

The above can be generated by your IDE, so the issue isn’t with the time taken to write them. The problem is that a simple class with a handful of member variables can quickly become very verbose. Let’s see how Lombok can help to reduce clutter by helping with each of the above.

@Getter and @Setter

Consider the Car class below. When we generate getters and setters, we end up with nearly 50 lines of code to describe a class with 5 member variables.

public class Car {
  private String make;
  private String model;
  private String bodyType;
  private int yearOfManufacture;
  private int cubicCapacity;
  public String getMake() {
    return make;
  }
  public void setMake(String make) {
    this.make = make;
  }
  public String getModel() {
    return model;
  }
  public void setModel(String model) {
    this.model = model;
  }
  public String getBodyType() {
    return bodyType;
  }
  public void setBodyType(String bodyType) {
    this.bodyType = bodyType;
  }
  public int getYearOfManufacture() {
    return yearOfManufacture;
  }
  public void setYearOfManufacture(int yearOfManufacture) {
    this.yearOfManufacture = yearOfManufacture;
  }
  public int getCubicCapacity() {
    return cubicCapacity;
  }
  public void setCubicCapacity(int cubicCapacity) {
    this.cubicCapacity = cubicCapacity;
  }
}

Lombok can help by generating the getter and setter boilerplate on your behalf. By annotating each member variable with @Getter and @Setter, you end up with an equivalent class that looks like this:

public class Car {
  @Getter @Setter
  private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;
}

Note that you can only use @Setter on non-final member variables. Using it on final member variables will result in a compilation error.

@AllArgsConstructor

Data classes commonly include a constructor that takes a parameter for each member variable. An IDE generated constructor for the Car class is shown below:

public class Car {
  @Getter @Setter
  private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;
  public Car(String make, String model, String bodyType, int yearOfManufacture, int cubicCapacity) {
    super();
    this.make = make;
    this.model = model;
    this.bodyType = bodyType;
    this.yearOfManufacture = yearOfManufacture;
    this.cubicCapacity = cubicCapacity;
  }
}

We can achieve the same thing using the @AllArgsConstructor annotation. Like @Getter and  @Setter@AllArgsConstructor reduces boilerplate and keeps the class cleaner and more concise.

@AllArgsConstructor
public class Car {
  @Getter @Setter
  private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;
}

There are other options for generating constructors. @RequiredArgsConstructor will create a constructor with one argument per final member variable and @NoArgsConstructor will create a constructor with no arguments.

@ToString

It’s good practice to override the toString method on your data classes to help with logging. An IDE-generated toString method for the Car class looks like this:

@AllArgsConstructor
public class Car {
  @Getter @Setter
  private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;
  @Override
  public String toString() {
    return "Car [make=" + make + ", model=" + model + ", bodyType=" + bodyType + ", yearOfManufacture="
        + yearOfManufacture + ", cubicCapacity=" + cubicCapacity + "]";
  }
}

We can do away with this by using the @ToString annotation as follows:

@ToString
@AllArgsConstructor
public class Car {
  @Getter @Setter
  private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;

By default, Lombok generates a toString method that includes all member variables. This behavior can be overridden to exclude certain member variables the exclude attribute  @ToString(exclude={"someField"}, "someOtherField"}) .

@EqualsAndHashCode

If you’re doing any kind of object comparison with your data classes, you’ll need to override the equals and hashCode methods. Object equality is something you’ll define based on some business rules. For example, in my Car class, I might consider two objects equal if they have the same make, model, and body type. If I use the IDE to generate an equals method that checks the make, model, and body type, it will look something like this:

@Override
public boolean equals(Object obj) {
  if (this == obj)
    return true;
  if (obj == null)
    return false;
  if (getClass() != obj.getClass())
    return false;
  Car other = (Car) obj;
  if (bodyType == null) {
    if (other.bodyType != null)
      return false;
  } else if (!bodyType.equals(other.bodyType))
    return false;
  if (make == null) {
    if (other.make != null)
      return false;
  } else if (!make.equals(other.make))
    return false;
  if (model == null) {
    if (other.model != null)
      return false;
  } else if (!model.equals(other.model))
    return false;
  return true;
}

The equivalent hashCode implementation looks like this:

@Override
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((bodyType == null) ? 0 : bodyType.hashCode());
  result = prime * result + ((make == null) ? 0 : make.hashCode());
  result = prime * result + ((model == null) ? 0 : model.hashCode());
  return result;
}

Although the IDE takes care of the heavy lifting, we still end up with considerable boilerplate code in the class. Lombok allows us to achieve the same thing using the @EqualsAndHashCode class annotation as shown below.

@ToString
@AllArgsConstructor
@EqualsAndHashCode(exclude = { "yearOfManufacture", "cubicCapacity" })
public class Car {
  @Getter @Setter
  private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;
}

By default, @EqualsAndHashCode  will create equals and hashCode methods that include all member variables. The exclude option can be used to tell Lombok to exclude certain member variables. In the code snippet above, I’ve excluded yearOfManufacture and cubicCapacity from the generated equals and hashCode methods.

@Data

If you want to keep your data classes as lean as possible, you can make use of the @Data  annotation. @Data is a shortcut for @Getter,  @Setter,  @ToString@EqualsAndHashCode, and  @RequiredArgsConstructor.

@ToString
@RequiredArgsConstructor
@EqualsAndHashCode(exclude = { "yearOfManufacture", "cubicCapacity" })
public class Car {
  @Getter @Setter  
private String make;
  @Getter @Setter
  private String model;
  @Getter @Setter
  private String bodyType;
  @Getter @Setter
  private int yearOfManufacture;
  @Getter @Setter
  private int cubicCapacity;  
}

By using @Data, we can reduce the class above to the following:

@Data
public class Car {
  private String make;
  private String model;
  private String bodyType;
  private int yearOfManufacture;
  private int cubicCapacity;  
}

Object Creation With @Builder

The builder design pattern describes a flexible approach to the creation of objects. Lombok helps you implement this pattern with minimal effort. Let’s look at an example using the simple Car class. Suppose we want to be able to create a variety of Car objects, but we want flexibility in terms of the attributes that we set at creation time.

@AllArgsConstructor
public class Car {
  private String make;
  private String model;
  private String bodyType;
  private int yearOfManufacture;
  private int cubicCapacity;  
  private List<LocalDate> serviceDate;
}

Let’s say we want to create a Car, but we only want to set the make and model. Using a standard all argument constructor on Car means that we’d supply only make and model and set the other arguments as null.

Car2 car = new Car2("Ford", "Mustang", null, null, null, null);

This works but it’s not ideal that we have to pass null for the arguments we’re not interested in. We could get around this by creating a constructor that takes only make and model. This is a reasonable solution but its not very flexible. What if we have lots of different permutations of fields that we might use to create a new Car? We’d end up with a bunch of different constructors representing all the possible ways we could instantiate a Car.

A clean, flexible way to solve this problem is with the builder pattern. Lombok helps you implement the builder pattern via the @Builder annotation. When you annotate the Car class with @Builder, Lombok does the following:

  • Adds a private constructor to Car
  • Creates a static CarBuilder class
  • Creates a setter style method on CarBuilder for each member variable in Car
  • Adds a build method on CarBuilder that creates a new instance of @Car.

Each setter style method on CarBuilder returns an instance of itself (CarBuilder). This allows you to chain method calls and provides you with a nice fluent API for object creation. Let’s see it in action.

Car muscleCar = Car.builder().make("Ford")
                             .model("mustang")
                             .bodyType("coupe")
                             .build();

Creating a Car with just make and model is now much cleaner than before. We simply call the generated builder method on Car to get an instance of CarBuilder, then call whatever setter style methods we’re interested in. Finally, we call a build to create a new instance of Car.

Another handy annotation worth mentioning is@Singular. By default, Lombok creates a standard setter style method for collections that takes a collection argument. In the example below, we create a new Car and set a list of service dates.

Car muscleCar = Car.builder().make("Ford")
                   .model("mustang")
                   .serviceDate(Arrays.asList(LocalDate.of(2016, 5, 4)))
                   .build();

Adding @Singularto collection member variables give you an extra method that allows you to add a single item to the collection.

@Builder
public class Car {
  private String make;
  private String model;
  private String bodyType;
  private int yearOfManufacture;
  private int cubicCapacity;  
  @Singular
  private List<LocalDate> serviceDate;
}

We can now add a single service date as follows:

Car muscleCar3 = Car.builder()
                    .make("Ford")
                    .model("mustang")
                    .serviceDate(LocalDate.of(2016, 5, 4))
                    .build();

This is a nice convenience method that helps keep our code clean when dealing with collections during object creation.

Logging

Another great Lombok feature is loggers. Without Lombok, to instantiate a standard SLF4J logger, you typically have something like this:

public class SomeService {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
  public void doStuff(){
    log.debug("doing stuff....");
  }
}

These loggers are clunky and add unnecessary clutter to every class that requires logging. Thankfully, Lombok provides an annotation that creates the logger for you. All you have to do is add the annotation to the class and you’re good to go.

@Slf4j
public class SomeService {
  public void doStuff(){
    log.debug("doing stuff....");
  }
}

I’ve used the @SLF4J annotation here, but Lombok will generate loggers for most common Java logging frameworks. For more logger options, see the documentation.

Lombok Gives You Control

One of the things I really like about Lombok is that it’s unintrusive. If you decide that you want to provide your own method implementation when using the likes of @Getter,  @Setter, or  @ToString, your method will always take precedence over Lombok. This is nice because it allows you to use Lombok most of the time, but still take control when you need to.

Write Less, Do More

I’ve used Lombok on pretty much every project I’ve worked on for the past 4 or 5 years. I like it because it reduces clutter and you end up with cleaner, more concise code that’s easier to read. It won’t necessarily save you a lot of time, as most of the code it generates can be auto-generated by your IDE. With that said, I think the benefits of cleaner code more than justify adding it to your Java stack.

Further Reading

I’ve covered the Lombok features that I use regularly, but there are a bunch more that I haven’t touched on. If you like what you’ve seen so far and want to find out more, head on over and have a look at the Lombok docs.

Java 8 Functional Interfaces – When & How To Use Them?

Functional interfaces, lambda expressions and Stream API – these three features of Java 8 has turned Java programming into new style of programming called functional-style programming. Java is still an object-oriented programming language, but from Java 8, with the introduction of new features, most of the programming is done keeping functions in mind rather than objects. In this article, we will see Java 8 functional interfaces, @FunctionalInterface annotation, java.util.function package and how to use new Java 8 functional interfaces to compose lambda expressions with some simple examples.

Java 8 Functional Interfaces

1) Definition

Functional interfaces are the interfaces which has exactly one abstract method. They may have any number of default methods but must have only one abstract method. Functional interfaces provide only one functionality to implement.

There were functional interfaces exist before Java 8. It is not like that they are the whole new concept introduced only in Java 8. RunnableActionListenerCallable and Comaprator are some old functional interfaces which exist even before Java 8.

The new set of functional interfaces are introduced in Java 8 to make programmer’s job easy while writing lambda expressions. Your lambda expression must implement any one of these functional interfaces. These new functional interfaces are organised under java.util.function package.

2) @FunctionalInterface Annotation

@FunctionalInterface annotation is introduced in Java 8 to represent functional interfaces. Although, it is not compulsory to write functional interface using this annotation. But, if you are using @FunctionalInterface annotation then your interface should contain only one abstract method. If you try to write more than one abstract method, compiler will show the error.

3) java.util.function package

All Java 8 functional interfaces are organised in java.util.function package. Each functional interface in this package represents an operation that can be performed by the lambda expression.

Below table shows the list of all Java 8 functional interfaces along with their abstract method, which operation they represent and when to use them?

Java 8 functional interfaces

4) How To Use Java 8 Functional Interfaces In Real Time?

Let’s define Student class like below. We will be using this class in the subsequent examples.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Student
{
    int id;
    
    String name;
    
    double percentage;
    
    String specialization;
    
    public Student(int id, String name, double percentage, String specialization)
    {
        this.id = id;
        
        this.name = name;
        
        this.percentage = percentage;
        
        this.specialization = specialization;
    }
    
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public double getPercentage() {
        return percentage;
    }
    public String getSpecialization() {
        return specialization;
    }
    @Override
    public String toString()
    {
        return id+"-"+name+"-"+percentage+"-"+specialization;
    }
}

Let listOfStudents be the list of 10 students.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
List<Student> listOfStudents = new ArrayList<Student>();
        
listOfStudents.add(new Student(111, "John", 81.0, "Mathematics"));
        
listOfStudents.add(new Student(222, "Harsha", 79.5, "History"));
        
listOfStudents.add(new Student(333, "Ruth", 87.2, "Computers"));
        
listOfStudents.add(new Student(444, "Aroma", 63.2, "Mathematics"));
        
listOfStudents.add(new Student(555, "Zade", 83.5, "Computers"));
        
listOfStudents.add(new Student(666, "Xing", 58.5, "Geography"));
        
listOfStudents.add(new Student(777, "Richards", 72.6, "Banking"));
        
listOfStudents.add(new Student(888, "Sunil", 86.7, "History"));
        
listOfStudents.add(new Student(999, "Jordan", 58.6, "Finance"));
        
listOfStudents.add(new Student(101010, "Chris", 89.8, "Computers"));

Let’s see how to use 4 important functional interfaces – PredicateConsumerFunction and Supplier using above listOfStudents.

a) Predicate – Tests an object

Predicate represents an operation which takes an argument T and returns a boolean. Use this functional interface, if you want to define a lambda expression which performs some test on an argument and returns true or false depending upon outcome of the test.

For example,

Imagine an operation where you want only a list of “Mathematics” students from the above listOfStudents. Let’s see how to do it using Predicate.

Lambda expression implementing Predicate : Checking specialization of a Student

1
2
3
4
5
6
7
8
9
10
11
Predicate<Student> mathematicsPredicate = (Student student) -> student.getSpecialization().equals("Mathematics");
        
List<Student> mathematicsStudents = new ArrayList<Student>();
        
for (Student student : listOfStudents)
{
    if (mathematicsPredicate.test(student))
    {
        mathematicsStudents.add(student);
    }
}

b) Consumer – Consumes an object

Consumer represents an operation which takes an argument and returns nothing. Use this functional interface If you want to compose a lambda expression which performs some operations on an object.

For example, displaying all students with their percentage.

Lambda expression implementing Consumer : Displaying all students with their percentage

1
2
3
4
5
6
7
8
Consumer<Student> percentageConsumer = (Student student) -> {
        System.out.println(student.getName()+" : "+student.getPercentage());
    };
        
for (Student student : listOfStudents)
{
    percentageConsumer.accept(student);
}

c) Function – Applies to an object

Function represents an operation which takes an argument of type T and returns a result of type R. Use this functional interface if you want to extract some data from an existing data.

For example, extracting only the names from listOfStudents.

Lambda expression implementing Function : Extracting only the names of all students

1
2
3
4
5
6
7
8
Function<Student, String> nameFunction = (Student Student) -> Student.getName();
        
List<String> studentNames = new ArrayList<String>();
        
for (Student student : listOfStudents)
{
    studentNames.add(nameFunction.apply(student));
}

d) Supplier – Supplies the objects

Supplier represents an operation which takes no argument and returns the results of type R. Use this functional interface when you want to create new objects.

Lambda expression implementing Supplier : Creating a new Student

1
2
3
Supplier<Student> studentSupplier = () -> new Student(111111, "New Student", 92.9, "Java 8");
        
listOfStudents.add(studentSupplier.get());

5) Functional Interfaces Supporting Primitive Type

Java 8 has also introduced functional interfaces which support primitive types. For example IntPredicateDoublePredicateLongConsumer etc… (See above table).

If an input or output is a primitive type then using these functional interfaces will enhance the performance of your code. For example, if input to a Predicate is primitive type intthen using intPredicate instead of Predicate will remove unnecessary boxing of input.

Thread Livelock

A livelock is a recursive situation where two or more threads would keep repeating a particular code logic. The intended logic is typically giving opportunity to the other threads to proceed in favor of ‘this’ thread.

A real-world example of livelock occurs when two people meet in a narrow corridor, and each tries to be polite by moving aside to let the other pass, but they end up swaying from side to side without making any progress because they both repeatedly move the same way at the same time.
From Oracle reference docs:

 A thread often acts in response to the action of another thread. If the other thread’s action is also a response to the action of another thread, then livelock may result. As with deadlock, livelocked threads are unable to make further progress. However, the threads are not blocked – they are simply too busy responding to each other to resume work.

For example consider a situation where two threads want to access a shared common resource via a Worker object but when they see that other Worker (invoked on another thread) is also ‘active’, they attempt to hand over the resource to other worker and wait for it to finish. If initially we make both workers active they will suffer from livelock.
main

The Common Resource Class

public class CommonResource {
    private Worker owner;

    public CommonResource (Worker d) {
        owner = d;
    }

    public Worker getOwner () {
        return owner;
    }

    public synchronized void setOwner (Worker d) {
        owner = d;
    }
}

The Worker Class

public class Worker {
    private String name;
    private boolean active;

    public Worker (String name, boolean active) {
        this.name = name;
        this.active = active;
    }

    public String getName () {
        return name;
    }

    public boolean isActive () {
        return active;
    }

    public synchronized void work (CommonResource commonResource, Worker otherWorker) {
        while (active) {
            // wait for the resource to become available.
            if (commonResource.getOwner() != this) {
                try {
                    wait(10);
                } catch (InterruptedException e) {
                   //ignore
                }
                continue;
            }

            // If other worker is also active let it do it's work first
            if (otherWorker.isActive()) {
                System.out.println(getName() +
                            " : handover the resource to the worker " +
                                                       otherWorker.getName());
                commonResource.setOwner(otherWorker);
                continue;
            }

            //now use the commonResource
            System.out.println(getName() + ": working on the common resource");
            active = false;
            commonResource.setOwner(otherWorker);
        }
    }
}

The main class

public class Livelock {

    public static void main (String[] args) {
        final Worker worker1 = new Worker("Worker 1 ", true);
        final Worker worker2 = new Worker("Worker 2", true);

        final CommonResource s = new CommonResource(worker1);

        new Thread(() -> {
            worker1.work(s, worker2);
        }).start();

        new Thread(() -> {
            worker2.work(s, worker1);
        }).start();
    }
}

Output:

There will be never ending recursion of the following output:

Worker 1  : handing over the resource to the worker: Worker 2
Worker 2 : handing over the resource to the worker: Worker 1
Worker 1  : handing over the resource to the worker: Worker 2
Worker 2 : handing over the resource to the worker: Worker 1
Worker 1  : handing over the resource to the worker: Worker 2
Worker 2 : handing over the resource to the worker: Worker 1
    ........

Avoiding Livelock

In above example we can fix the issue by processing the common resource sequentially rather than in different threads simultaneously.

Just like deadlock, there’s no general guideline to avoid livelock, but we have to be careful in scenarios where we change the state of common objects also being used by other threads, for example in above scenario. the Worker object.