Design a site like this with WordPress.com
Get started

LocalDate class in java

Java 8 has introduced various classes to work with date and time objects. Lets see today LocalDate class in java 8 and how can we use it in our day to day coding.

Lets look at few of the useful methods provided and understand how it works

System.out.println("My Current TimeZone >> " + ZoneOffset.systemDefault());
System.out.println("Is same as zone >>"+LocalDate.now(Clock.system(ZoneOffset.of("+05:30"))));
		
		
System.out.println(LocalDate.now());
System.out.println(LocalDate.now(Clock.systemUTC()));
System.out.println(LocalDate.now(Clock.system(ZoneOffset.of("+10"))));
System.out.println(LocalDate.now(Clock.system(ZoneOffset.of("+0530"))));

line 1, will print my current timezone

line 2, will print my current timezone converted into UTC offset.

line 3, “LocalDate.now” will print my current date in my timezone.

line 4, will print current date in UTC

line 5, will print current date in time zone offset at +10 from UTC

line 6, will print current date in time zone offset at +05:30 from UTC

Lets look at the output

My Current TimeZone >> Asia/Calcutta
Is same as  >>+05:30
2021-08-06
2021-08-06
2021-08-07
2021-08-06

If you see, the date in time zone +10 is different than in UTC timezone or with offset +5:30. It is also possible to provide negative value of offset as well to the ZoneOffset method.

The “now” methods returns an object of type LocalDate. There are various other utility methods to find month, day of month, day of week, year etc.

Lets look at one useful method

System.out.println(LocalDate.now().get(ChronoField.DAY_OF_MONTH));
System.out.println(LocalDate.now().get(ChronoField.YEAR_OF_ERA));

So if you see above, one of the method accepts a class called TemporalField. ChronoField enum has various temporal fields that can be passed to this method. Output of the above is as below

6
2021

So day of month is 6 and year is 2021. If you pass any temporal field which the LocalDate does support then it will throw “UnsupportedTemporalTypeException”

So for a date object which does not have time, if you ask for temporalfield “ChronoField.AMPM_OF_DAY” then it will throw ” UnsupportedTemporalTypeException”

There are various other utility methods to add days, months, minutes to the current LocalDate object.

Lets look at how can you convert a simple string into a LocalDate object.

LocalDate.from(DateTimeFormatter.ofPattern("yyyy-MM-dd").parse("2021-01-01"));

Here I have used “DateTimeFormatter” to the utility class as formatter and passed the expected date string to the parse method of DateTimeFormatter. This will try to convert the string to the format and return us the LocalDate Object. It will throw Parsing exception if you do not provide correct string to the parse method.

I hope this will help you in some or other way. Thank you !

Advertisement

How to setup your Java Environment from JDK Zip file?

Please follow below steps

1 Download JDK Zip file

2 Unzip File on any location on your hard disk

3 Configure environment variable

Type Environment Variable in search bar

Choose options based on your need .Most of types in secure environment like company you only have access to variable linked to your account only.

Follow below steps in sequence

4 Verify JDK version

Open Command Prompt

Type Below Command

java -version

This will look like below one

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

HashMap

HashMap is one of the most widely used collection in java. As the name suggests, it is based on the hashing function and it is a collection of key value pairs represented by map. The collection is favorite question for an interviewer and hence it is critical to understand its functioning and its working.

As already told a HashMap is a collection of key value pairs. so unlike other collections where we store only one value, in a HashMap we store 2 values against each element of the collection. One being the key and other being a value.

So the concept itself is very simple and there is very little to understand here. The collection is unordered which means the order of retrieval is not guaranteed. These are mere basic of the map.

Lets now understand how they are stored and how the hashing function is used. So when we call put function on a map with a key and value pair, the map stores this at some part of the array and array in a map is collection of node.

The collection uses the hascode function of the object being stored to determine the index of the array within the hashmap where the object will be stored. Feels a little complicated ?

lets say we are storing employee details against employee id. So in our case, employee id is the key and employee details will be the value. Lets say we are storing “A101”,EmployeeDetail[“name:Sushil”,”email: sushil@gmail.com”]

So when we call put function with key “A101” which is String object, then the hashcode function of this object will be called to generate a number and this number will be used to determine the exact location of the pair within the map.

So why really is it done this way ? I can still store a pair in list if I create a class with key and value, isn’t it ?

The answer is to make retrieval faster. Lets see how the above mentioned storage method makes retrieval faster.

So at the time of retrieval, I present the collection with the key. In our case is “A101”, In order to determine the position of the value object, hashmap will again use the hashcode function to find our where it has stored the value of the key. So the hashcode function will help determine the index within the map and it can directly go that location to find out the value as it would be the same position which will be used for storing the pair initially.

So seems ok at this moment. So we have one key and one value and we can find the location within the map for our object and get the value. So it will be faster than traversing the list and then each time trying to find if the key in the list is equal to the key presented. So HashMap will be much faster in retrieval when we are looking for a specific object in the collection.

hashcode’s are not supposed to be unique, two objects can have the same hashcode and its logically permissible. We are supposed to make them as unique as possible but it may not be possible all the time.

So what happens when we have 2 objects with same hascode ? How will the HashMap manage the storing and retrieval. Lets see.

So during storage as earlier stated it will used the hashcode function to determine the index within the map and then against that index store the pair in a list, In this case its a linked list. For illustration look at the below example

So the bucket is really the linked list which stores the elements in a list having the same hashcode. So against each index there is a linked list where the key value pairs are stored.

So if there are more than one element with the same hascode then the element is stored in the linked list.

At the time of retrieval, the hashmap will first identify the index and then traverse through the linked list to find the element matching the key using the equals method in the object.

So the equals and hascode methods are very important when storing values in the Map. Java has provided the hashcode and equals methods for the wrapper classes but if you wish to use user defined objects as key in the HashMap then you must override the equals and hashcode methods for the HashMap to work correctly.

2 different objects can have the same hashcode. If the hashcode is same, then it does not mean that both the objects are equal. However if 2 objects are equal, they must evaluate to same hashcode. This is primary rule you must keep in mind while overriding these two methods.

You must also note that you must try and create unique hashcode for each object as it would help in the performance of the map. A hashcode which returns the same integer all the time is also a correct implementation but then it will affect the performance of the HashMap as all the elements will be stored in the same bucket.

When we try and store two objects which are logically not equal but evaluate to same hascode, a hash collision is said to be occurred. This scenario must be avoided to improve the performance of the HashMap.

If you find this tutorial helpful, Please like it and comment if you are looking of any additional information on HashMaps.

HashSet

Hashset as the name suggests is an implementation of the set interface. A set does not allow duplicates in the collection. if you try to insert the same object twice, the already existing is replaced. This collection does not guarantee of the insertion order and the objects will not be returned in any particular order

A HashSet depends on the hash function of the object and is backed by a hashmap. So a hashset similar to the hashmap depends heavily on the hashcode and equals method to implement its functionality.

A HashSet is not synchronized, it means that there is no guarantee of the consistency of the objects in the HashSet if they are accessed/modified by multiple threads.

 Set<String> nameSet = new HashSet<>();
       nameSet.add(null);
       nameSet.add("Jane");
       nameSet.add("polly");
       nameSet.add("Jane");
       nameSet.add(null);
       System.out.println(nameSet);

[null, polly, Jane]

As from the example it is clear that there is no particular order in which the elements retrieved. A null is also allowed to be inserted into the collection.

The HashSet is best for search operations if the hashcode function is designed so that there are minimum hash collisions. It is also advisable to initialize the Set with capacity if you know size it before hand.

As stated earlier a HashSet is backed by a HashMap, so all the elements are added as keys in the map and all the values are defaulted to a dummy element.

Below is representation of the add method in the HashSet. The add method adds element as key in the map and value is defaulted to a dummy value.

private static final Object PRESENT = new Object();
 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
 }

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.

Linked List

LinkedList is an implementation of the List interface. As with all the list interfaces, this collection maintains the insertion order.

The LinkedList also implements a Deque interface. So a LinkedList represents a Deque and a List.

As the names suggests, this collection arranges elements similar to a linked list data structure. In a linked list data structure, each element has a previous and next reference, similarly in LinkedList, each element in the list is represented by a Node Object as below.

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

So each element is represented by the field “item” in the Node object of LinkedList class and it is the single element in the collection, whereas the field “prev” and “next” point to the Node object of previous element and the next element in the collection. Hmm, lets look at a visual representation of a linked list for a clearer picture if you have forgotten a linked list. Actually it really is a double linked list.

A Linked List Representation

so the above diagram is an example of linked list. Each element represent a node in the LinkedList. Apple being the first element in the list does not have a previous element linked to it. Every other element except the last element has previous and next element reference to navigate. The last element does not have any next element reference as it is the last element in the list.

So, how does the insertion work in case of linked list. So if I have to add an element to the list, a new “Node” object is created and the “prev” field is updated in the Node object to point to the last element in the list. So unlike an ArrayList a collection does not require a continuous allocation memory, it can create a node object anywhere and update its references.

INSERTION

So in the above diagram, we are adding “Peach” to the collection, so we just create new Node object and reference the last object in the “Prev” of the last element and the new element added becomes the last element in the collection. The LinkedList maintains the position of the first element and the last element the list.

A Deletion happens by traversing in the list and then updating the references of the prev element and the next element. Take a look at the representation below

Deletion

So we have removed the element “Lemon” by removing its references from the Previous and its next element. The dotted line represent old references. So now when we traverse, the element Lemon will never come into the picture.

Traversal is linear in case of a linked list, we cannot jump with index to a particular position as we can do with an ArrayList. Although the api provides us a way to fetch by index, but the retrieval is linear so it might take o(n) complexity to fetch an element. So compared to an ArrayList, fetching by index is slow.

InsertDeleteRetrieval
Complexityo(1)o(n/4)o(n/4)

Basic linked list example

        List<String> linkedList = new LinkedList<>();
        linkedList.add("apple");
        linkedList.add("orange");
        linkedList.add("peach");

Please refer below java doc location for detailed description of the api

https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html