Design a site like this with WordPress.com
Get started

How to setup your Java Environment from installer(exe)?

Please follow below steps

1 Download JDK from below URL

https://www.oracle.com/in/java/technologies/javase-downloads.html

2 Download it as EXE file

3 Install JDK on your local machine by following steps mentioned in installer

4 Verify JDK version

Open Command Prompt

Type Below Command

java -version

This will look like below one

Advertisement

Java8 Streams – Convert List to Map

A lot of times we are required to convert one collection into another. It could be from list to set , set to map or otherwise. Before java introduced streams and functional programming, for doing such a transformation of collection was possible but then we had write a lot more code than we have to today with Java8 features.

Lets look at a simple example and transform a list to a map.

Lets say we have list of employee’s each having a name and id attribute. Our requirement is to convert the list into a map where key in the map is the “id” attribute of the employee and value is the employee object.

List<Employee> lstEmplyees = new ArrayList<>();
        lstEmplyees.add(new Employee(6606,"dipak"));
        lstEmplyees.add(new Employee(1212,"tony"));
        lstEmplyees.add(new Employee(779,"chetan"));

        Map<Integer,Employee> map =lstEmplyees.stream()
                                        .collect(Collectors.toMap(Employee::getId,Employee::get));
        System.out.println(map);

The above code creates a list 3 employee objects and then converts it into a map with help of streams.

Once you stream the collection, it provides us back with a stream of values in the list and then we can apply collect method to transform it into map. The collect method takes in Collector parameter, several of the implementations are already present in the “Collectors” class. For our use case we use Collectors.toMap. The toMap function takes two functions as input, first being the key mapper and second is the value mapper.

So as we know when we stream a collection, we are fed with stream of the objects inside the collection, one at a time.
In map function, we pass a function to identify the key from the employee object in our case. So for us it is the id attribute, so we return back the id attribute and the second parameter is the value function which return the value we want to associate with the streamed object.

Here is a simplified version of the above code

    List<Employee> lstEmplyees = new ArrayList<>();
        lstEmplyees.add(new Employee(6606,"dipak"));
        lstEmplyees.add(new Employee(1212,"tony"));
        lstEmplyees.add(new Employee(779,"chetan"));

        Function<Employee,Integer> keyMapper = (Employee employee) -> employee.getId();
        Function<Employee,Employee> valueMapper=  Function.identity();  // equvivaled to (Employee employee) -> employee;

        Map<Integer,Employee> map =lstEmplyees.stream()
                                        .collect(Collectors.toMap(keyMapper,valueMapper));
        System.out.println(map);

The above code works fine for just about any collection to convert to map. However, the above code will throw exception when there are duplicates in the collection. We haven’t told java what to do when there is a duplicate key. There is a third parameter that we can pass to tell java what do in case there is duplicate key.

The third parameter is the of the type – BinaryOperator which means it takes in 2 parameters of the same type and returns value of same type

Lets update our code to handle duplicates, in case of duplicates we want the new value to overwrite the old value.

List<Employee> lstEmplyees = new ArrayList<>();
        lstEmplyees.add(new Employee(6606,"dipak"));
        lstEmplyees.add(new Employee(1212,"tony"));
        lstEmplyees.add(new Employee(779,"chetan"));
        lstEmplyees.add(new Employee(779,"chetan1"));

        Function<Employee,Integer> keyMapper = (Employee employee) -> employee.getId();
        Function<Employee,Employee> valueMapper=  Function.identity();  // equvivaled to (Employee employee) -> employee;
        BinaryOperator<Employee> merge = (Employee oldVal,Employee newVal) -> newVal;

        Map<Integer,Employee> map =lstEmplyees.stream()
                                        .collect(Collectors.toMap(keyMapper,valueMapper));

Interesting to note here is that the merge function has parameter “Employee” instead of “Id attribute”. Its because the merge function is asking us to select the value to choose when there are duplicate keys.

There is one more variant of the “toMap” function. In the fourth parameter you can pass the map in which you would want to add the values.

Access Modifiers

Java provides with various access modifiers to class, methods, variables, constructors to set access level and control who can access which variables or class or methods.

The Access levels are divided into below categories

  • Public >> Access to everyone
  • Private >> Access to enclosing class
  • Protected >> Access to all subclass and within the package
  • default >> Access to all classes within the package

Lets see how these modifiers affect the its functionality when applied to different key aspects of JAVA

PublicPrivateProtectedDefault (No modifier)
ClassAcesss to everyoneNANAAccess to classes within package
VariableAcess to everyoneAccess to enclosing class membersAccess within package and subclassAccess to classes within package
MethodAcess to everyoneAccess to enclosing class membersAccess within package and subclassAccess to classes within package
ConstructorAcess to everyoneAccess to enclosing class membersAccess within package and subclassAccess to classes within package


There is another keyword “final” which can be applied to a Class, Variable, Method. Although it does not determine the access but it has great significance.

When applied to a class it means, the class cannot be subclassed, i.e. extending a class marked final is not possible. A small example is described below. The keyword can be placed before or after the access modifier.

public final class Car {
}

The final keyword when applied to method of a class, makes the method final and does not allow the subclasses to be override.

And the final keyword when applied to a variable implies that the variable cannot be reassigned to a new instance once it is assigned a value.

Constructor

A Constructor is used to initialize an object. A constructer is nothing but a special function within a class which has same name as that of the class and does not return any value.

DEFAULT CONSTRUCTOR/NO ARG CONSTRUCTOR

public class car {

   car(){
      //initializing code
   }
}

The above code snippet creates a class car and has a constructer method which will initialize the class to form an instance. A constructer with no parameters is called default constructor. You can create only one no-arg constructor in a class. If you do not create a default constructor then Java will create one for you implicitly. There will be slight change in the behavior but we will come back to it later.

PARAMETERIZED CONSTRUCTOR

public class car {
   String make;
   String model;
   car(String make,String model){
      this.make = make;
      this.model = model;
   }
}

The above code snippet is an example of a parameterized constructor. As the name suggests, it is a constructor with parameters. If you have created a parameterized constructor then Java will not create a default constructor for you. This is where the behavior changes for the implicit default constructor. You can create multiple parameterized constructors in a class, however no two parameterized constructors can have same signature. By signature here I mean that no two constructors can have same type of parameter in same order.

Below code will result into a compilation error because the signature for both constructors are same.

public class car {

   car(String make, String model){
      //initializing code
   }

  car(String model, String Make){
      //initializing code
   }
}

Class and Object

Java is an object oriented programming language, each program is represented in terms of object. So an object is any real world object for e.g. a Car, Computer, Apple etc.

To understand it better, lets say we are given a program to read file from the system from a given specified location. So how do we represent a file and how do we represent its behavior ? Like a file is supposed to read, write or possible delete ? how do we represent all of this ?

In an OOP (Object oriented programming) we would represent a File and its behavior in a class. For e.g.

class File {
String fileName;

File(String fileName){
this.fileName = fileName;
}

public void read(){
 ...
}

public void write() {
 ..
}

}

So a class represents everything a file object can do. So in our example, a file can read and write.

So if we have to read a file, we have to create an instance of the file object, like below.

File myfile = new File("sample.txt")
myfile.read();

So now we have created a new instance of the File class which is represented by variable “myfile”. The variable “myfile” uniquely represents the file “sample.txt” and when we can call read/write method on the “myfile” instance and it will execute the code inside the methods read()/write() of the file class.

So the green box represents “Class” and all the yellow boxes represent “Object/Instances” of the class “File”. We can have as many objects of the class File as we want.

ArrayList

Arraylist is an implementation of the list interface and it is a very widely used collection. ArrayList maintains the collection in the insertion order.

As the name suggest, the objects are arranged in an array. An array is a continuous allocation of memory where objects are stored.

The difference being, an arraylist is growable, i.e. the size of ArrayList is dynamic. It grows as we add elements to the ArrayList, With an Array we have to pre decide the size of the array but in case of ArrayList we do not have to set size beforehand.

As stated earlier, an ArrayList is growable, however we must be cautious in using ArrayList for large arrays. An ArrayList is initialized with a pre-decided size and once we add elements to list which grows beyond the list default size, java creates a new ArrayList with higher capacity and add the existing elements to the new array.

So if we know already the size of the list, it is preferable and more performant to initialize an ArrayList with an initial capacity

Below is an example of an empty ArrayList.

List<String> myList = new ArrayList<>();

Below is an example of an ArrayList with initial capacity of 100.

List<String> myList = new ArrayList<100>();

A collection is judged for insert, delete, retrieval performance. Some collections perform better in some areas over other. So before selection any collection, measure below parameter against your scenario at hand.

InsertDeleteRetrieval
Complexity o(1) – o(n)o(n)o(1)

As you can see, retrieval is really fast with ArrayList in all the scenarios.
Insert are fast when the list has spare capacity to add elements else it will have to copy the entire array to a new array to increase the capacity and then add the element, this process increases the insertion complexity to o(n).
Whereas Delete has the complexity of o(n).

Please comment if you would like to know more on ArrayList.

List

A List is data structure where objects are stored in insertion order, It means that the objects inserted into a list maintain its position in the collection. So a list can be defined as collection of objects where objects are stored in the insertion order.

With a list implementation, it is possible to add/remove/set an object using the index.

E.g. Consider below representation of list

The Objects in the list can be accessed using their indices. so, if I want to fetch banana which is at the second position in the list, I can just fetch it from the list using the index number “list.get(2)”. As said earlier, the position is maintained in a list implementations, so the banana was the third object in the list at the time of insertion, will be the same at the time of extraction.

Here the important thing to note in any list implementaion is that all list’s maintain order of insertion.

In Java, there are primarily 2 types of list implementation
1) ArrayList 2) LinkedList

Both the above collections have their own usage purposes, I will talk about it in the next tutorial.

Please take a look at the list interface in the java sources to have a better understanding.



Publish Build Scans

You can publish your build and details that will provide with you with the insights of what happened when you ran the build. The build are published to a centralized server.

How to publish

When you run the gradle build, pass the parameter –scan with the build. This will deploy the build to the centralized server.

When requested, accept the terms by typing “yes”

The build will also display a url where you can see details as below of your build. Follow the instructions to view details

Null Pointer Exception

Null Pointer Exception or NPE is one of the most common exception that anyone of us have encountered as a development engineer.

It is usually thrown when we try to access a method on a reference variable for which a value is evaluated to null.

for e.g

Employee e = getEmployee(123);
e.getEmployeeName();

The above code can throw a NPE. The above code assumes that the “getEmployee” method will always return a value but it may happen that it wont and return null;

In such a case the code at line 2 throws NPE as we are trying to access “getEmployeeName()” on a null value.

Mind you, the NPE is a runtime exception and the compiler will not complain that you have not handled a null check.

How to Resolve

In most cases a simple null check resolves the problem. Like in the above example an If condition will avoid NPE

Employee e = getEmployee(123);
if(e!=null)
e.getEmployeeName();

A code should be written to identify such conditions and handle them wherever necessary. As NPE is a runtime exception, if the code is not handled for null object access, the program might very well terminate abruptly for a small null check.

Java Gradle Dependency management

One of the key feature of the build is managing the dependencies in the project. If we have to use a third party library, we declare that library in the build file i.e. build.gradle and then expect the build tool to download the library and put in the classpath of our project for consumption.

Let say we want to use google guava in our project, so we add the below dependency in the build.gradle file.

compile group: 'com.google.guava', name: 'guava', version: '29.0-jre'

The above line will put the guava library in our project classpath and make the library available for us to use.

Dependency scope basically tells the gradle tool of our intention of when we want the library to be available. Lets go through one – by one.

  • Implementation
    It is used to declare dependencies that we don’t want to expose to consumers compile time. So it means that if we do not want the dependencies in our project to be exposed to the consumers of our project, we declare the dependency as implementation. The is the default scope and is an improvement over the compile scope. The compile scope is deprecated and will no longer be available in latest build scrips. So this scope avoids pollution of the transitive dependencies which will happen otherwise with compile scope.

  • api
    Use the api configuration do declare dependencies that are part of our API, i.e. for dependencies that we explicitly want to expose to our consumers. So if you want the dependency to be the part of the api for the consumers, then you declare the dependency as api.

  • compileOnly
    As the name suggests the dependencies which are supposed to be available only at compile time, such dependencies are marked compileOnly. E.g. of such a dependency is lombok. The lombok library is not required at runtime as it creates the required class files at compile time based on the annotations.

  • runtimeOnly
    Dependencies available only at the runtime are declared runtime dependencies.

testImplementation / testCompileOnly / testRuntimeOnly
testImplementation dependencies are only available during compilation and runtime of tests.

testCompileOnly dependencies are only available during compilation of tests and not at runtime.

testRuntimeOnly dependencies are only available during runtime of tests and not at compile time.