Monday, January 31, 2022

Java Stream - Collectors.teeing() With Examples

In the Java Stream API, Collectors class implements Collector and provides many useful reduction operations like Collectors.groupingBy(), Collectors.partitioningBy(). There is also a Collectors.teeing() method added in Java 12 that takes two downstream Collectors as method argument and passes each stream element through these two downstream Collectors, there is also a third argument, a merging function that merges the results of both collectors into the final result.

It is a handy utility method for performing certain tasks where more processing is required with in a single method call.

Syntax of Collectors.teeing() method

Collector<T,?,R> teeing(Collector<? super T,?,R1> downstream1, Collector<? super T,?,R2> downstream2, BiFunction<? super R1,? super R2,R> merger)

Here parameters are-

  • downstream1- First downstream collector
  • downstream2- Second downstream collector
  • merger- Function which merges two results into a single one

Collectors.teeing() Java examples

1. If you want to get the average of numbers in a List. You can do that in a single method call by using Collectors.teeing(). First downstream Collector argument can do the job of counting elements, second Collector argument can do the job of getting the sum of elements and the merger operation can do the job of calculating average.

import java.util.List;
import java.util.stream.Collectors;

public class CollectorsTeeing {

  public static void main(String[] args) {
    List<Integer> numList = List.of(16, 27, 19, 75, 56);
    Double average = numList.stream().collect(Collectors.teeing(
        Collectors.counting(), Collectors.summingDouble(n -> n), 
        (count, sum) -> sum/count));
    System.out.println("Average of elements in the list- " + average);    

  }
}

Output

Average of elements in the list- 38.6

2. Using Collectors.teeing() method to get the employee with the maximum salary and employee with the minimum salary from the List of Employee objects.

Employee class

public class Employee {
  private String empId;
  private int age;
  private String name;
  private char gender;
  private int salary;
  Employee(String empId, int age, String name, char gender, int salary){
    this.empId = empId;
    this.age = age;
    this.name = name;
    this.gender = gender;
    this.salary = salary;
  }
  public String getEmpId() {
    return empId;
  }

  public int getAge() {
    return age;
  }

  public String getName() {
    return name;
  }

  public char getGender() {
    return gender;
  }

  public int getSalary() {
    return salary;
  }
  @Override
  public String toString() {
      return "Emp Id: " +  getEmpId() + " Name: " + getName() + " Age: " + getAge();
  }
}

Here first downstream collector gets the employee with max salary and the second downstream collector gets the employee with min salary. Merger function creates a list to store both employee objects.

public class CollectorsTeeing {

  public static void main(String[] args) {
    List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
                new Employee("E002", 35, "Shelly", 'F', 7000), 
                new Employee("E003", 24, "Mark", 'M', 9000), 
                new Employee("E004", 37, "Ritu", 'F', 11000),
                new Employee("E005", 32, "Anuj", 'M', 12000), 
        new Employee("E006", 28, "Amy", 'F', 14000)); 
    List<Optional<Employee>> list = empList.stream().collect(Collectors.teeing(
        Collectors.maxBy(Comparator.comparingInt(Employee::getSalary)), 
                Collectors.minBy(Comparator.comparingInt(Employee::getSalary)), 
                   (emp1, emp2) -> {
                      List<Optional<Employee>> e = new ArrayList<>();
                        e.add(emp1);
                        e.add(emp2);
                        return e;
                   }));
    System.out.println("Employee with max salary- " + (list.get(0).isPresent()? list.get(0).get().getName():null));
    System.out.println("Employee with min salary- " + (list.get(1).isPresent()? list.get(1).get().getName():null));  

  }
}

Output

Employee with max salary- Amy
Employee with min salary- Ram

That's all for this topic Java Stream - Collectors.teeing() With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream - Collectors.joining() With Examples
  2. Java Stream - Collectors.partitioningBy() With Examples
  3. Java Stream - Collectors.summingInt(), summingLong(), summingDouble()
  4. Java Stream - flatMap() With Examples
  5. Java Stream - Convert Stream to Set

You may also like-

  1. How to Get The Inserted ID (Generated ID) in JDBC
  2. Buffered Streams in Java IO
  3. Array in Java With Examples
  4. Java Program to Delete File And Directory Recursively
  5. Angular Reactive Form Validation Example
  6. Angular HttpClient - Set Response Type as Text
  7. Namespace And Variable Scope in Python
  8. Spring MVC Radiobutton And Radiobuttons Form Tag Example

Sunday, January 30, 2022

Heap Memory Allocation in Java

In the post JVM run-time data areas we have already got a brief idea about the memory areas used while running a Java application. In this post we’ll talk about Java Heap memory space in detail – How Heap memory is allocated, how garbage collection happens, heap memory tuning and heap memory profiling.


Heap memory allocation in Java

Heap is the JVM run-time data area where the Java objects reside. Apart from Java objects, memory for instance variables and arrays is also allocated on the heap. Heap is created on the JVM start-up and shared among all Java Virtual Machine threads.

Heap memory in Java is divided into two areas (or generations)-

  • Young Space (generation)- The young generation consists of eden and two survivor spaces. Most objects are initially allocated in eden.
  • Old Space (or Tenured generation)– When objects (which have survived garbage collection) residing in young space have reached a certain age threshold they are moved to old space.

These generations have their own memory pool allocated by the JVM.

Java heap memory generations
Heap memory areas

Why is heap memory managed in generations

Here let’s deviate a little and try to understand why memory is managed in generations and what benefit do we get out of it. In one line it can be explained as these division into generations makes garbage collection more efficient.

As you must be knowing Garbage collection in Java is an automatic storage management system that frees space in the heap by reclaiming memory for objects that are not having any reference. Note that, an object is considered garbage when it can no longer be reached from any pointer in the running program.

A very simplistic garbage collection algorithms will iterate over every reachable object. Any objects left over are considered garbage. With this algorithm the time taken is proportional to the number of live objects in the whole heap.

In order to minimize the time it takes to do garbage collection the approach taken by JVM is known as "generational collection". This approach works on the weak weak generational hypothesis, which states that most objects survive for only a short period of time.

In order to optimize for this hypothesis, memory is managed in generations. Initially objects are allocated in the young generation (Eden space) and most objects die there.

When the young generation fills up, it results in a minor collection (Minor GC) in which only the young generation is collected, that way rather than iterating over the objects in the whole heap only a small portion of the Heap (Young generation) is inspected for dead objects. If the hypothesis stated above holds true then most of the objects will die there and reclaimed with in the younger generation.

Only a small portion of the objects will survive the garbage collection in younger generation and after a certain time lapse will move to tenured generation. Eventually, the tenured generation will fill up and must be garbage collected, that will result in a major collection (Major GC), in which the entire heap is collected.

How does garbage collection work on the heap

Now that you know that Heap is divided into generations and how this division helps garbage collector to run more efficiently as GC has to go through only a part of the heap space and within that less space iteration most of the objects (Remember most of the objects die young!) can be garbage collected.

Let’s see in more detail how garbage collection works across these generations and what happens when minor GC is triggered and what happens when major GC is triggered.

  • Within the young generation initially any new objects are allocated to the eden space. Both survivor spaces (S0 and S1) are initially empty.
  • A minor garbage collection is triggered when eden space is filled up. All the unreferenced objects are garbage collected and reference objects are moved to the first survivor space (S0). One survivor space is empty at any time.
  • When the minor garbage collection is triggered next time, all the unreferenced objects are garbage collected and reference objects are moved to the survivor space. Note that this time referenced objects are moved to the second survivor space (S1). There is one more step; objects from the previous minor GC on the first survivor space (S0) have their age incremented and get moved to S1. Note that one survivor space is empty at any time.
  • This process of clearing eden space, moving the referenced objects to one of the survivor spaces, incrementing the age for the surviving objects keeps on repeating with every minor GC. There is also a check for object’s age reaching a certain threshold. Objects that reach the threshold are moved from young generation to the old generation.
  • With every minor GC aged objects will be moved from young to old generation space.
  • When that movement of object fills up the tenured space that triggers a major GC in which the entire heap is collected. Major garbage collection lasts much longer than minor collections because a significantly larger number of objects are involved. Apart from garbage collecting the objects, major GC also compacts the space as it is defragmented from cleaning of the objects.

Refer Garbage Collection in Java to know more about garbage collection process and available garbage collectors in Java

VM Heap Size tuning options in Java

Heap memory in Java will have three things – live objects, dead objects and some portion of the memory which is still free. The JVM heap size determines the frequency of garbage collection and the time spent on collecting garbage.

If you set a large heap size frequency of garbage collection will be less but the time spent on collecting garbage will be more because of the large size (means having more objects to inspect). On the other hand if you do the opposite then time spent on collecting garbage will be less but frequency will increase as smaller heap will fill faster.

An acceptable heap size is application-specific and should be adjusted using the provided options after analyzing the actual time and frequency of garbage collections.

Java heap size options

  1. Task: Setting initial heap size

    Option: -Xms

    As example: -Xms40m

  2. Task: Setting maximum heap size

    Option: -Xms

    As example: -Xmx512m

    At initialization of the JVM, the entire space for the heap is reserved. The size of the space reserved can be specified with the -Xmx option. If the value provided with the -Xms parameter is smaller than the value provided with the -Xmx parameter, then all of the space that is reserved for the heap is not committed to the virtual machine. The different generationso of the heap (Young and tenured) can grow to that limit (provided with -Xmx) as and when needed.

    It is recommended that you set initial heap size (-Xms) equal to the maximum heap size (-Xmx) to minimize garbage collections.

  3. If you have not given same values for parameters -Xms and -Xmx then the virtual machine will grow or shrink the heap at each garbage collection to try to keep the proportion of free space to live objects within a specific range. The options to set this target ranges are-

  4. Task: To maintain minimum percentage heap free space

    Option: -XX:MinHeapFreeRatio=<minimum>

    As example: -XX:MinHeapFreeRatio=40

  5. Task: To maintain maximum percentage heap free space

    Option: -XX:MaxHeapFreeRatio=<maximum>

    As example: -XX:MaxHeapFreeRatio=70

    With the parameters as used in the example let's try to understand these options better. If the percent of free space in a generation falls below 40%, then the generation will be expanded to maintain 40% free space, up to the maximum allowed size of the generation. Similarly, if the free space exceeds 70%, then the generation will be contracted so that only 70% of the space is free, subject to the minimum size of the generation.

  6. After heap size setting parameters another option that affects GC performance is the proportion of the heap dedicated to the young generation. If you set the young generation to be bigger, minor collections will occur less often. But that would mean a smaller tenured generation, which will increase the frequency of major collections.

    Three options for tuning the young generation are-

  7. Task: Setting the Young generation heap size

    Option: -XX:NewSize

    It is recommended to set -XX:NewSize to be one-fourth the size of the heap size.

  8. Task: Set the maximum size of the Young Generation heap size.

    Option: -XX:MaxNewSize

  9. Task: Controlling the ratio between young and tenured generation

    Option: -XX:NewRatio

    As example if you set -XX:NewRatio=3 that would mean the ratio between the young and tenured generation is 1:3. The size of the eden + survivor spaces will be one-fourth of the total heap size.

  10. You can also tune the size of the survivor spaces, for that you can use the parameter SurvivorRatio.

  11. Task: Tune the size of the survivor spaces

    Option: -XX:SurvivorRatio

  12. As example if you set -XX:SurvivorRatio=6 that would mean the ratio between eden and a survivor space is 1:6. Which means each survivor space will be one-sixth the size of eden, thus one-eighth the size of the young generation.

Heap memory profiling

Though there are many tools available to profile the memory, I am mentioning one I have already used Java VisulalVM. It’s free and comes bundled with JDK itself. Another tool you will find in the same location is jconsole which is also a monitoring tool.

To launch you just need to go to bin directory of your installed JDK folder and launch jvisualvm from there.

On the left side pane it will show the running Java applications, just click on the one you want to inspect.

Here I am demonstrating its use with a very simple application where I have created a thread and in that thread I am creating 5000 objects of another class with some thread pause (by using sleep method) in between. For this program I changed the -Xms and -Xmx so that the heap is small.

First image shows the heap when the program is just started, that’s why you see a very little variance in the used heap.

Second image is a snapshot of the heap memory when garbage collection occurred that is why you can see a sudden dip in the used heap memory. If you see at 3:50 PM in the graph you will see a GC activity which has taken 1.3% of CPU time.

Third image also shows a GC activity. At 3:52 PM you can see a barely visible blue mark showing GC activity and a corresponding dip in the used heap memory.

So using VisualVM GUI tool you can monitor your application’s memory usage, also analyze process threads and get a thread dump. Also profile the performance of your application by analyzing CPU and memory usage.

That's all for this topic Heap Memory Allocation in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. PermGen Space Removal in Java 8
  2. Just In Time Compiler (JIT) in Java
  3. What Are JVM, JRE And JDK in Java
  4. How to Run a Shell Script From Java Program
  5. How to Pass Command Line Arguments in Eclipse

You may also like-

  1. Reflection in Java - Getting Field Information
  2. Java Object Cloning - clone() Method
  3. Java Stream API Examples
  4. Lambda Expressions in Java 8
  5. Lock Striping in Java Concurrency
  6. AtomicInteger in Java With Examples
  7. Java ReentrantReadWriteLock With Examples
  8. How HashMap Works Internally in Java

Saturday, January 29, 2022

Merge Sort Program in Java

In this post we’ll see how to write Merge sort program in Java. Merge sort is much more efficient than the simple sort algorithms like bubble sort and insertion sort. One drawback is that it requires an additional array along with the original array that is sorted.

How merge sort works

Merge sort works on the concept of merging two sorted arrays to create another array which is also sorted.

Now the question is how do you get sorted arrays which are merged? Since merge sort is also termed as divide and conquer algorithm so the idea is to divide the input array into two halves then each of these halves are further divided into halves and so on until you get sub-arrays with only one element which is considered a sorted array.

At that point you start merging these sub-arrays, from two single element sub-arrays you create a sorted merged array of two elements. Then two such sorted sub-arrays of two elements are merged to create a sorted array of four elements and so on until you have a sorted array of all the elements.

Since array is recursively divided into two halves so this division process can be written as a recursive method where base case becomes the point when you have sub-arrays with only one element each.

Let’s try to understand with an example where we have an input array as given below.

int[] intArr = {21, 11, 33, 70, 5, 25, 65, 55};

The process of recursive calls to divide the array into halves can be explained using the following image.

merge sort in java

At this point merge process starts which merges two sorted arrays to create another sorted array, this merging process can be explained using the following image.

merge sort program java

Merge Sort Java program

In the merge sort program there is a method mergeSortRecursive which is called recursively to divide the array.

Merge method merges the two sub-arrays to create a sorted array.

public class MergeSort {
  public static void main(String[] args) {
    int[] intArr = {47, 85, 620, 3456, -7, 10, 4500, 106, -345, 1000, 67, 80, 5500, 34, 78, 782, 4, 0, 99, 190};
    MergeSort ms = new MergeSort();
    ms.mergeSortRecursive(intArr, 0, intArr.length-1);
    System.out.println("Sorted array after merge sort- ");
    for(int num : intArr){
      System.out.print(num + " ");
    }
  }
    
  private void mergeSortRecursive(int[] intArr, int lower, int upper){
    //base case
    if (lower == upper){
      return;
    }else{
      // get mid point for division of array
      int middle = (lower + upper)/2;
      
      mergeSortRecursive(intArr, lower, middle);        
      mergeSortRecursive(intArr, middle+1, upper);
      
      merge(intArr, lower, middle, upper);
    }
  }
    
  private void merge(int[] intArr, int lower, int middle, int upper){
      /** Create two temp arrays pertaining to two halves that 
       are being merged and add elements to them  */
      int subArrayOneLength = middle - lower + 1;
      int subArrayTwoLength = upper - middle;
      int[] temp1 = new int[subArrayOneLength];
      int[] temp2 = new int[subArrayTwoLength];
      for(int i = 0; i < subArrayOneLength; i++){
        temp1[i] = intArr[lower + i];
      }
      for(int j = 0; j < subArrayTwoLength; j++){
        temp2[j] = intArr[middle + 1 + j];
      }           
      int i =0;        
      int j = 0;
      // merging process, merge two temp arrays 
      while((i < subArrayOneLength) && (j < subArrayTwoLength)){
        if(temp1[i] < temp2[j]){
          intArr[lower] = temp1[i++];
        }else{
          intArr[lower] = temp2[j++];
        }
        lower++;
      }
      // If there are more elements
      while(i < subArrayOneLength){
        intArr[lower++] = temp1[i++];
      }
      while(j < subArrayTwoLength){
        intArr[lower++] = temp2[j++];
      }
  }
}

Output

Sorted array after merge sort- 
-345 -7 0 4 10 34 47 67 78 80 85 99 106 190 620 782 1000 3456 4500 5500 

Performance of merge sort

In merge sort there is subdivision of arrays and for each sub-division there is merging. Number of levels (subdivisions of array) can be calculated as– (logN + 1)

For example log of 8 base 2 is 3, so log8 + 1 = 4

Which is same as the number of halves for the array having 8 elements– 8 4 2 1.

At each level N elements are merged which makes the time complexity of merge sort as N*(logN + 1). we can discard the 1 so the time complexity of merge sort is O(N*logN).

Merge sort is not an in place sort algorithm as extra space is required. Auxiliary space required is equal to the number of elements in the original array so the space complexity of merge sort is O(N).

That's all for this topic Merge Sort Program in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Programs Page


Related Topics

  1. Shell Sort Program in Java
  2. Radix Sort Program in Java
  3. How to Display Pyramid Patterns in Java - Part1
  4. Arrange Non-Negative Integers to Form Largest Number - Java Program
  5. Find All Permutations of a Given String Java Program

You may also like-

  1. Running Dos/Windows Commands From Java Program
  2. Find Duplicate Elements in an Array Java Program
  3. How to Display Time in AM-PM Format in Java
  4. How to Sort an ArrayList in Descending Order in Java
  5. CopyOnWriteArrayList in Java With Examples
  6. Java Reflection API Tutorial
  7. String in Java Tutorial
  8. NameNode, DataNode And Secondary NameNode in HDFS

Friday, January 28, 2022

equals() And hashCode() Methods in Java

In this post we'll see what are equals() and hashCode() methods in Java and why do we need to override these methods.


equals() and hashCode() methods in Java

In Java equals() and hashCode() methods are present in the java.lang.Object class. These two methods are used for making inferences about an object's identity or in simpler language to reach to a decision whether the two compared objects are equal or not.

The default implementation of equals() method in the Object class is a simple reference equality check.

public boolean equals(Object obj){
 return (this == obj);
}

The default implementation of hashCode() in the Object class just returns integer value of the memory address of the object.

Usage of hashCode() and equals() methods in Java

  • hashCode()- This method is used to get a unique integer value for a given object. We can see it's use with hash based collections like HashTable or HashMap where hashCode() is used to find the correct bucket location where the particular (key, value) pair is stored.

    Refer How HashMap internally works in Java to know more about it.

  • equals()- equals() method is used to determine the equality of two objects.

When do we need to override hashCode() and equals() methods

If you are using a custom object as key in a hash based collection it becomes very important to override hashCode() and equals() methods in Java.
Also in case of ORM like Hibernate when a detached instance is re-attached to a session, we need to make sure that the object is same.

In such cases we can't rely on the default implementation provided by the Object class and need to provide custom implementation of hashCode() and equals() method.

But I never had the need to override hashCode() and equals() methods

Most of the time we use HashMap when it comes to hash based collections. With in HashMap, we mostly use primitive wrapper class like Integer or String class, as key. These classes are immutable and provide their own proper implementation of hashCode() and equals() methods, thus these classes, on their own are, good hash keys.

Things become tricky when we are using any custom object as key, in that case it becomes very important to override these 2 methods to make sure that we really get the object we want.

Let's say you are using some custom class object as a key in HashMap and that class did not override equals() and hashCode(), what will happen in that case?

In that case we would not be able to reliably retrieve the associated value using that key, unless we used the exact same class object as key in the get() method as we stored using the put() method.

Now, you may wonder why using the same instance is it possible? Because in the case we are not overriding and providing the implementation of equals() and hashCode(), Object class' equals() and hashCode() methods will be used and recall that in Object class equals() method implementation is simple reference equality check thus having the same instance may satisfy the Object class' equals() method.

Let's see an example where custom object is used but hashCode and equals are not overridden and custom implementation is not given.

class Customer {
  private int customerID;
  private String firstName;
  private String lastName;
  public Customer(int customerID, String firstName, String lastName) {
    super();
    this.customerID = customerID;
    this.firstName = firstName;
    this.lastName = lastName;
  }  
}

public class HashCodeDemo {
  public static void main(String[] args) {
    Map<Customer, String> m = new HashMap<Customer, String>();
    Customer cust = new Customer(1, "Roger", "Cox");
    m.put(cust,"Roger Cox");
    // retrieving using another instance
    System.out.println(m.get(new Customer(1, "Roger", "Cox")));
    // retrieving using same instance
    System.out.println(m.get(cust));               
  }
}

Output

null
Roger Cox

It can be seen how; when the instance is changed the value is not retrieved even when the same values for the customer object are given as key. But when we use the same instance then it is able to fetch. But that's not very convenient and in a big application we are not expected to keep the same instance and use it whenever we want to retrieve the value. So enter the equals() and hashCode() methods.

Same example with hashCode and equals implemented

class Customer {
  private int customerID;
  private String firstName;
  private String lastName;

  public Customer(int customerID, String firstName, String lastName) {
    super();
    this.customerID = customerID;
    this.firstName = firstName;
    this.lastName = lastName;
  }
      
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + customerID;
    result = prime * result
            + ((firstName == null) ? 0 :   firstName.hashCode());
    result = prime * result
            + ((lastName == null) ? 0 : lastName.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
        return false;
    Customer other = (Customer) obj;
    if (customerID != other.customerID)
      return false;
    if (firstName == null) {
      if (other.firstName != null)
        return false;
    } else if (!firstName.equals(other.firstName))
        return false;
    if (lastName == null) {
      if (other.lastName != null)
        return false;
    } else if (!lastName.equals(other.lastName))
        return false;
    return true;
  }
}
public class HashCodeDemo {
  public static void main(String[] args) {
    Map<Customer, String> m = new HashMap<Customer, String>();
    Customer cust = new Customer(1, "Roger", "Cox");
    m.put(cust,"Roger Cox");
    // retrieving using another instance
    System.out.println(m.get(new Customer(1, "Roger", "Cox")));
    // retrieving using same instance
    System.out.println(m.get(cust));               
  }
}

Output

Roger Cox
Roger Cox

Now it will use the custom implementation of equals to see if two instances of Customer class are logically equal. So in both cases, using the same instance or different instance, we are able to get the value.

To see a discussion on why 31 is recommended to be used as a multiplier in hashCode refer-
http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier

And if you are worried that you have to write so much to implement hashCode and equals, don't worry! IDEs provide an option to do that for you. In eclipse IDE that option to generate hashcode and equals method has this path source - Generate hashCode() and equals().

Rules for implementing equals() and hashCode() in Java

There are certain restrictions on the behavior of equals() and hashCode() methods in Java, which can be seen in the Javadocs for Object class- http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals(java.lang.Object)

For equals() method the JavaDocs say-

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

And the general contract of hashCode is-

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

To explain this contract a little more-

The first point says that the hashCode() method must consistently return the same integer. In case a mutable object is used as key we have to make sure that its state does not change. If a key's hashCode changes while used in a Collection get and put will give some unpredictable results.

According to the second point if 2 objects Obj1 and Obj2 are equal according to their equals() method then they must have the same hash code too. Though the vice-versa is not true that is if 2 objects have the same hash code then they do not have to be equal too.

According to the third point if 2 objects are not equal according to their equals() method they still can have the same hash code. That is known as hash collision.

That's all for this topic equals() And hashCode() Methods in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. How to Loop Through a Map in Java
  2. How ArrayList Works Internally in Java
  3. Difference Between Comparable and Comparator in Java
  4. Difference Between equals() Method And equality Operator == in Java
  5. Java Collections Interview Questions And Answers

You may also like-

  1. Fail-Fast Vs Fail-Safe Iterator in Java
  2. Marker Interface in Java
  3. Why no Multiple Inheritance in Java
  4. Lambda Expressions in Java 8
  5. Transaction Management in Java-JDBC
  6. finally Block in Java Exception Handling
  7. Check Given Strings Anagram or Not Java Program
  8. Dependency Injection in Spring Framework

Thursday, January 27, 2022

Java Stream - Collectors.joining() With Examples

If you want to join stream elements into a String you can do that using joining() method of the java.util.stream.Collectors class. It is a handy utility method to concatenate elements of an array, collection into a String.

Syntax of Collectors.joining() method

There are three overloaded Collectors.joining() method

  • Collector<CharSequence,?,String> joining()- Returns a Collector that concatenates the input elements into a String, in encounter order.
  • Collector<CharSequence,?,String> joining(CharSequence delimiter)- Returns a Collector that concatenates the input elements, separated by the specified delimiter, in encounter order.
  • Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)- Returns a Collector that concatenates the input elements, separated by the specified delimiter, with the specified prefix and suffix, in encounter order.

Collectors.joining() Java examples

1. We have an array of Strings and we want to join all the array elements to get a String. That can be quickly done using Collectors.joining() method by using the array as a Stream source and then calling the collect method. We'll also use the other two variants of joining() method in this example.

import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CollectorsJoining {
  public static void main(String[] args) {
    String[] strArr = { "Example", "to", "demonstrate", "Collectors", "joining"};
      String str1 = Stream.of(strArr).collect(Collectors.joining());
      System.out.println("Concatenated String- " + str1);
      
      // Second Variant- Passing Space as delimiter
      String str2 = Stream.of(strArr).collect(Collectors.joining(" "));
      System.out.println("Concatenated String with delimiter- " + str2);
      // Passing "-" as delimiter
      str2 = Stream.of(strArr).collect(Collectors.joining("-"));
      System.out.println("Concatenated String with delimiter- " + str2);
      
      // Third Variant- Passing delimiter, suffix and prefix
      String str3 = Stream.of(strArr).collect(Collectors.joining("|", "[", "]"));
      System.out.println("Concatenated String with delimiter and suffix, prefix- " + str3);
  }
}

Output

Concatenated String- ExampletodemonstrateCollectorsjoining
Concatenated String with delimiter- Example to demonstrate Collectors joining
Concatenated String with delimiter- Example-to-demonstrate-Collectors-joining
Concatenated String with delimiter and suffix, prefix- [Example|to|demonstrate|Collectors|joining]

2. Using Collectors.joining method to concatenate elements of an ArrayList.

public class CollectorsJoining {
  public static void main(String[] args) {
    List<String> alphabetList = Arrays.asList("A", "B", "C", "D","E", "F");
      String str1 = alphabetList.stream().collect(Collectors.joining());
      System.out.println("Concatenated String- " + str1);
      
      // Second Variant- Passing Space as delimiter
      String str2 = alphabetList.stream().collect(Collectors.joining(" "));
      System.out.println("Concatenated String with delimiter- " + str2);
      // Passing "-" as delimiter
      str2 = alphabetList.stream().collect(Collectors.joining("-"));
      System.out.println("Concatenated String with delimiter- " + str2);
      
      // Third Variant- Passing delimiter, suffix and prefix
      String str3 = alphabetList.stream().collect(Collectors.joining("|", "[", "]"));
      System.out.println("Concatenated String with delimiter and suffix, prefix- " + str3);
  }
}

Output

Concatenated String- ABCDEF
Concatenated String with delimiter- A B C D E F
Concatenated String with delimiter- A-B-C-D-E-F
Concatenated String with delimiter and suffix, prefix- [A|B|C|D|E|F]

That's all for this topic Java Stream - Collectors.joining() With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream - Collectors.partitioningBy() With Examples
  2. Java Stream - findAny() With Examples
  3. Java Stream - noneMatch() With Examples
  4. Java Stream API Interview Questions And Answers

You may also like-

  1. Externalizable Interface in Java
  2. Lock Striping in Java Concurrency
  3. Switch Expressions in Java 12
  4. Java String Interview Questions And Answers
  5. Find Maximum And Minimum Numbers in a Given Matrix Java Program
  6. BeanPostProcessor in Spring Framework
  7. How to Install Node.js and NPM in Windows
  8. How to Write a Map Only Job in Hadoop MapReduce

Wednesday, January 26, 2022

TreeMap in Java With Examples

TreeMap in Java is also one of the implementation of the Map interface like HashMap and LinkedHashMap. How TreeMap differs from these other implementations is that the elements in TreeMap are sorted on keys.

The elements in TreeMap are ordered according to the natural ordering of its keys, which is the default sort ordering or a comparator can be provided at map creation time to provide custom ordering (We'll see an example a little later).


How TreeMap is implemented in Java

TreeMap class in Java implements the NavigableMap interface and extends the AbstractMap class.

TreeMap is a Red-Black tree based NavigableMap implementation. This implementation provides guaranteed log(n) time cost for the containsKey, get, put and remove operations.

Some of the important points about TreeMap in Java which are discussed in this post are as follows-

  1. TreeMap in Java is a Red-Black tree based NavigableMap implementation.
  2. TreeMap stores its elements in sorted order and sorting is done on keys. By default elements are sorted using their natural ordering.
  3. If you want to sort elments in TreeMap in any other order then you will have to provide a Comparator.
  4. TreeMap doesn’t allow null as key though other Map implementation like HashMap and LinkedHashMap do allow one key as null.
  5. Key in the TreeMap should be unique otherwise the previous stored value for the same key will be overwritten. Duplicate values are allowed though.
  6. TreeMap in Java is not synchronized so it is not thread safe. If TreeMap is accessed concurrently by multiple threads and at least one of the threads modifies the map structurally, then the TreeMap must be synchronized externally.
  7. The iterators returned by the iterator method of the collections returned by all of the TreeMap's "collection view methods" are fail-fast. If the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.

Java TreeMap Constructors

There are four constructors in the TreeMap class in Java.

  • TreeMap()- Constructs a new, empty tree map, using the natural ordering of its keys.
  • TreeMap(Comparator<? super K> comparator)- Constructs a new, empty tree map, ordered according to the given comparator.
  • TreeMap(Map<? extends K,? extends V> m)- Constructs a new tree map containing the same mappings as the given map, ordered according to the natural ordering of its keys.
  • TreeMap(SortedMap<K,? extends V> m)- Constructs a new tree map containing the same mappings and using the same ordering as the specified sorted map.

Java TreeMap creation and element insertion example

public class TreeMapDemo {
  public static void main(String[] args) {
    Map<String, String> cityTemperatureMap = new TreeMap<String, String>();
    // Storing elements
    cityTemperatureMap.put("Delhi", "24");
    cityTemperatureMap.put("Mumbai", "32");
    cityTemperatureMap.put("Chennai", "35");
    cityTemperatureMap.put("Bangalore", "22" );
    cityTemperatureMap.put("Kolkata", "28");
    cityTemperatureMap.put("Chennai", "36");

    // iterating the map
    for(Map.Entry<String, String> me : cityTemperatureMap.entrySet()){
      System.out.println(me.getKey() + " " + me.getValue());
    }
  }
}

Output

Bangalore 22
Chennai 36
Delhi 24
Kolkata 28
Mumbai 32

It can be seen that the elements in TreeMap are sorted according to the natural ordering of its keys which is ascending for String.
Also note that though Chennai is added twice but it is stored only once as trying to store the same key twice will result in overwriting of the old value with the new value (as the calculated hash will be the same for the keys). Thus the last one is displayed while iterating the values.

TreeMap doesn't allow null

Though HashMap and LinkedHashMap allow one null as key, TreeMap in Java doesn't allow null as key. Any attempt to add null in a TreeMap will result in a NullPointerException.

public class TreeMapDemo {
  public static void main(String[] args) {
    Map<String, String> cityTemperatureMap = new TreeMap<String, String>();
    // Storing elements
    cityTemperatureMap.put("Delhi", "24");
    cityTemperatureMap.put("Mumbai", "32");
    cityTemperatureMap.put("Chennai", "35");
    cityTemperatureMap.put("Bangalore", "22" );
    cityTemperatureMap.put("Kolkata", "28");
    // Null key
    cityTemperatureMap.put(null, "36");
    
    // iterating the map
    for(Map.Entry<String, String> me : cityTemperatureMap.entrySet()){
      System.out.println(me.getKey() + " " + me.getValue());
    }
  }
}

Output

Exception in thread "main" java.lang.NullPointerException
 at java.util.TreeMap.put(Unknown Source)
 at org.netjs.prog.TreeMapDemo.main(TreeMapDemo.java:17)

Sorting elements in different order in TreeMap

As already mentioned by default elements are stored in TreeMap using natural ordering. If you want to sort TreeMap is descending order (reverse order) then you need to provide your own Comparator at map creation time. Let's see an example where we sort the TreeMap of Strings in descending order of its keys.

public class TreeMapDemo {
  public static void main(String[] args) {
    Map<String, String> cityTemperatureMap = new TreeMap<String, String>(new TreeComparator());
    // Storing elements
    
    cityTemperatureMap.put("Delhi", "24");
    cityTemperatureMap.put("Mumbai", "32");
    cityTemperatureMap.put("Chennai", "35");
    cityTemperatureMap.put("Bangalore", "22" );
    cityTemperatureMap.put("Kolkata", "28");
    
    // iterating the map
    for(Map.Entry<String, String> me : cityTemperatureMap.entrySet()){
        System.out.println(me.getKey() + " " + me.getValue());
    }
  }
}

//Comparator class
class TreeComparator implements Comparator<String>{
  @Override
  public int compare(String str1, String str2) {
    return str2.compareTo(str1);
  }    
}

Output

Mumbai 32
Kolkata 28
Delhi 24
Chennai 35
Bangalore 22

Here note that a Custom Comparator is implemented with the logic to sort objects in reverse order. That Comparator is passed in the constructor of the TreeMap at map creation time .

TreeMap is not synchronized

TreeMap in Java is not thread safe. In case we need to Synchronize it, it should be synchronized externally. That can be done using the Collections.synchronizedSortedMap method.

SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));

TreeMap class' iterator is fail-fast

The iterators returned by TreeMap in Java are fail-fast, if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.

TreeMap iteration example

In the example we’ll get the Set view of the mapped entries using the entrySet() method. While iterating that Set we’ll try to remove an element from the TreeMap using the Map's remove() method (not the iterator's remove method) which means a structural modification and results in ConcurrentModificationException being thrown.

public class TreeMapItr {
  public static void main(String[] args) {
    Map<String, String> langMap = new TreeMap<String, String>();
    // Storing (key, value) pair to HashMap
    langMap.put("ENG", "English");
    langMap.put("NLD", "Dutch");
    langMap.put("ZHO", "Chinese");
    langMap.put("BEN", "Bengali");
    langMap.put("ZUL", "Zulu");
    langMap.put("FRE", "French");
    // Collection view of the TreeMap
    Set<Map.Entry<String, String>> langSet = langMap.entrySet();
    Iterator<Map.Entry<String, String>> itr = langSet.iterator();
    while (itr.hasNext()) {
      Map.Entry<String, String> entry = itr.next();
      System.out.println("Key is " + entry.getKey() + " Value is " + entry.getValue());    
      // removing value using TreeMap's remove method
      if(entry.getKey().equals("NLD")){
        langMap.remove(entry.getKey());
      }
    }
  }
}

Output

Key is BEN Value is Bengali
Key is ENG Value is English
Key is FRE Value is French
Key is NLD Value is Dutch
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1207)
 at java.util.TreeMap$EntryIterator.next(TreeMap.java:1243)
 at java.util.TreeMap$EntryIterator.next(TreeMap.java:1238)
 at org.netjs.examples.impl.TreeMapItr.main(TreeMapItr.java:23)

If iterator's remove method is used to remove an element from TreeMap while it is iterated then the ConcurrentModificationException is not thrown.

public class TreeMapItr {
  public static void main(String[] args) {
    Map<String, String> langMap = new TreeMap<String, String>();
    // Storing (key, value) pair to HashMap
    langMap.put("ENG", "English");
    langMap.put("NLD", "Dutch");
    langMap.put("ZHO", "Chinese");
    langMap.put("BEN", "Bengali");
    langMap.put("ZUL", "Zulu");
    langMap.put("FRE", "French");
    // Collection view of the TreeMap
    Set<Map.Entry<String, String>> langSet = langMap.entrySet();
    Iterator<Map.Entry<String, String>> itr = langSet.iterator();
    while (itr.hasNext()) {
      Map.Entry<String, String> entry = itr.next();
      // removing value using iterator's remove method
      if(entry.getKey().equals("NLD")){
        itr.remove();
      }
    }
    for(Map.Entry<String, String> lang : langMap.entrySet()) {
      System.out.println("Key- " + lang.getKey() + 
                  " Value- " + lang.getValue());
    }
  }
}

Output

Key- BEN Value- Bengali
Key- ENG Value- English
Key- FRE Value- French
Key- ZHO Value- Chinese
Key- ZUL Value- Zulu

As you can see element from TreeMap is removed when iterator's remove() metod is used and ConcurrentModificationException is not thrown.

Reference: https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/TreeMap.html

That's all for this topic TreeMap in Java With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. How HashMap Works Internally in Java
  2. How to Sort Elements in Different Order in TreeSet
  3. How to Loop Through a Map in Java
  4. HashMap Vs LinkedHashMap Vs TreeMap in Java
  5. Java Collections Interview Questions And Answers

You may also like-

  1. Abstraction in Java
  2. Type Casting in Java With Conversion Examples
  3. EnumSet in Java
  4. How to Remove Duplicate Elements From an ArrayList in Java
  5. Race Condition in Java Multi-Threading
  6. Java ThreadLocal Class With Examples
  7. Functional Interface Annotation in Java
  8. Spring Setter Based Dependency Injection

Tuesday, January 25, 2022

Java Stream - Collectors.partitioningBy() With Examples

If you want to partition stream elements into two groups as per the given condition you can do that using partitioningBy() method of the java.util.stream.Collectors class.

Collectors.partitioningBy() method in Java

Collectors.partitioningBy() method partitions the input elements according to the passed Predicate argument and organizes them into a Map<Boolean, List<T>>. As you can notice the key in the Map is of type Boolean because the two keys used are “false” and “true” to map the input elements that doesn't pass the condition or pass it respectively.

There are two overloaded partitioningBy() method with Syntax as given below-

  • Collector<T,?,Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)- Partitions the stream elements according to the passed Predicate.
  • Collector<T,?,Map<Boolean,D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T,A,D> downstream)- In this variant there is a Second argument of type Collector which reduces the values in each partition and organizes them into a Map<Boolean, D> whose values are the result of the downstream reduction.

Collectors.partitioningBy() Java examples

1. In this Collectors.partitioningBy() example we'll use it to partition a list of integers to return a map of even and odd numbers.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CollectorsPartitioning {

  public static void main(String[] args) {
    List<Integer> listOfNumbers = Arrays.asList(5,9,14,19,47,56,72,89,90,18);
      Map<Boolean, List<Integer>> numbers = listOfNumbers.stream()
                                 .collect(Collectors.partitioningBy(n -> n%2 == 0));
      // When key false - returns list with odd numbers
      System.out.println("Odd Numbers- " + numbers.get(false));
      // When key true - returns list with even numbers
      System.out.println("Even Numbers- " + numbers.get(true));
  }
}

Output

Odd Numbers- [5, 9, 19, 47, 89]
Even Numbers- [14, 56, 72, 90, 18]

2. Partition a List of Employee into those who earn more than 8000 and those who don’t using Collectors.partitioningBy() method.

Employee Class

public class Employee {
  private String empId;
  private int age;
  private String name;
  private char gender;
  private int salary;
  Employee(String empId, int age, String name, char gender, int salary){
    this.empId = empId;
    this.age = age;
    this.name = name;
    this.gender = gender;
    this.salary = salary;
  }
  public String getEmpId() {
    return empId;
  }

  public int getAge() {
    return age;
  }

  public String getName() {
    return name;
  }

  public char getGender() {
    return gender;
  }

  public int getSalary() {
    return salary;
  }
  @Override
  public String toString() {
      return "Emp Id: " +  getEmpId() + " Name: " + getName() + " Age: " + getAge();
  }
}
public class CollectorsPartitioning {

  public static void main(String[] args) {
    List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
                new Employee("E002", 35, "Shelly", 'F', 8000), 
                new Employee("E003", 24, "Mark", 'M', 9000), 
                new Employee("E004", 37, "Ritu", 'F', 11000),
                new Employee("E005", 32, "Anuj", 'M', 6000), 
        new Employee("E006", 28, "Amy", 'F', 14000));
      Map<Boolean, List<Employee>> numbers = empList.stream()
                                 .collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
      // When key false - employee with salary <= 8000
      System.out.println("Employees with Salary less than 8000- " + numbers.get(false));
      // When key true - employee with salary > 8000
      System.out.println("Employees with Salary greater than 8000- " + numbers.get(true));
  }
}

Output

Employees with Salary less than 8000- [Emp Id: E001 Name: Ram Age: 40, Emp Id: E002 Name: Shelly Age: 35, Emp Id: E005 Name: Anuj Age: 32]
Employees with Salary greater than 8000- [Emp Id: E003 Name: Mark Age: 24, Emp Id: E004 Name: Ritu Age: 37, Emp Id: E006 Name: Amy Age: 28]

3. In the second example we got the Employees partitioned into groups as per the condition salary greater than 8000 or not. Suppose you want the count of employees in each partitioned group, in that scenario you can use the Collectors.partitioningBy() method with two arguments and pass the second argument which is a counting Collector in this case.

public class CollectorsPartitioning {

  public static void main(String[] args) {
    List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
                new Employee("E002", 35, "Shelly", 'F', 8000), 
                new Employee("E003", 24, "Mark", 'M', 9000), 
                new Employee("E004", 37, "Ritu", 'F', 11000),
                new Employee("E005", 32, "Anuj", 'M', 6000), 
        new Employee("E006", 28, "Amy", 'F', 14000));
      Map<Boolean, Long> numbers = empList.stream()
                                 .collect(Collectors.partitioningBy(e -> e.getSalary() > 8000, Collectors.counting()));
      // When key false - employee with salary <= 8000
      System.out.println("Count of employees with Salary less than 8000- " + numbers.get(false));
      // When key true - employee with salary > 8000
      System.out.println("Count of employees with Salary greater than 8000- " + numbers.get(true));
  }
}

Output

Count of employees with Salary less than 8000- 3
Count of employees with Salary greater than 8000- 3

That's all for this topic Java Stream - Collectors.partitioningBy() With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream - Collectors.groupingBy() With Examples
  2. Java Stream - Collectors.joining() With Examples
  3. Java Stream - noneMatch() With Examples
  4. Java Stream - skip() With Examples
  5. Java Stream - sorted() With Examples

You may also like-

  1. Transient Keyword in Java With Examples
  2. Executor And ExecutorService in Java With Examples
  3. Java Nested Class And Inner Class
  4. Java Exception Handling Interview Questions And Answers
  5. Deque Implementation in Java Using Doubly Linked List
  6. Lazy Initialization in Spring Using lazy-init And @Lazy Annotation
  7. Angular Two-Way Data Binding With Examples
  8. Using Combiner in Hadoop MapReduce to Improve Performance

Monday, January 24, 2022

Java Stream - noneMatch() With Examples

In JavaStream API there is a method allMatch() which is used to check if all the elements in the Stream match the given condition. There is also a noneMatch() method in Java Stream API to check whether no elements of this stream match the provided predicate.

Syntax of noneMatch() method

boolean noneMatch(Predicate<? super T> predicate)

Here predicate is a parameter of type Predicate functional interface that provides the condition to be applied to elements of this stream.

Method returns true if no elements of the stream match the provided predicate, otherwise false. If Stream is empty then also true is returned.

noneMatch is a short-circuiting terminal operation. It’s a terminal operation means the stream pipeline is considered consumed after allMatch() operation, and can no longer be used. It is also short-circuiting which means when presented with infinite input, it may terminate in finite time.

noneMatch() Java examples

1. In this example we’ll use noneMatch() to quickly verify if all the elements in the List are less than 50. If we use noneMatch with the conditon to check if any element is greater than 50 then it should return true for our requirement (all elements less than 50).

import java.util.Arrays;
import java.util.List;

public class NoneMatchStream {
  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(30, 40, 22, 45, 27, 49, 47);
      boolean result = numList.stream().noneMatch(n -> n > 50);
      System.out.println(result);
  }
}

Output

true
2. In this example we’ll have a Stream of Employee objects where we want to check if none of the employee has salary less than 8000.

Employee class

public class Employee {
  private String empId;
  private int age;
  private String name;
  private char gender;
  private int salary;
  Employee(String empId, int age, String name, char gender, int salary){
    this.empId = empId;
    this.age = age;
    this.name = name;
    this.gender = gender;
    this.salary = salary;
  }
  public String getEmpId() {
    return empId;
  }

  public int getAge() {
    return age;
  }

  public String getName() {
    return name;
  }

  public char getGender() {
    return gender;
  }

  public int getSalary() {
    return salary;
  }
  @Override
  public String toString() {
    return "Emp Id: " +  getEmpId() + " Name: " + getName() + " Age: " + getAge();
  }
}
public class NoneMatchStream {
  public static void main(String[] args) {
    List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
                new Employee("E002", 35, "Shelly", 'F', 7000), 
                new Employee("E003", 24, "Mark", 'M', 9000), 
                new Employee("E004", 37, "Ritu", 'F', 11000),
                new Employee("E005", 32, "Anuj", 'M', 12000), 
        new Employee("E006", 28, "Amy", 'F', 14000)); 
    boolean result = empList.stream().noneMatch(e -> e.getSalary() < 8000);
    System.out.println(result);
  }
}

Output

false

Result is false as not there are employees with salary less than 8000.

That's all for this topic Java Stream - noneMatch() With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream - anyMatch() With Examples
  2. Java Stream - Convert Stream to Array
  3. Java Stream - findAny() With Examples
  4. Java Stream API Interview Questions And Answers

You may also like-

  1. Just In Time Compiler (JIT) in Java
  2. How to Loop Through a Map in Java
  3. break Statement in Java With Examples
  4. matches() method in Java String
  5. How to Reverse a Linked List in Java
  6. Spring MVC Dropdown Example Using Select, Option And Options Tag
  7. Spring NamedParameterJdbcTemplate Select Query Example
  8. Using Combiner in Hadoop MapReduce to Improve Performance

Saturday, January 22, 2022

Write to a File in Java

In this post we'll see different ways to write to a file in Java. Examples given here to write to a file in Java are based on the following options-

  • BufferedOutputStream- BufferedOutputStream is a wrapper class over the OutputStream class and it adds buffering capability to the output stream. See example.
  • BufferedWriter- Writes text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings. See example.
  • Files Class methods- Java 7 onward Files class can be used for writing to a file in Java using Files.write() method. There is also a newBufferedWriter method in the Files class that can be used to write to a file. See example.

Refer How to append to a file in Java to see how to append to an already existing file.

Java program to write to a file using BufferedOutputStream

Though Java provides classes like FileOutputStream and FileWriter to write files using byte stream and character stream respectively but using them directly will slow down the I/O operation considerably. It is always advisable to use BufferedOutputStream or BufferedWriter to write to a file in Java because that will provide buffering to the output streams and won't cause a call to the underlying system for each byte written. Buffered output streams write data to a buffer, and the native output API is called only when the buffer is full, making I/O operation more efficient.

It is same as reading file using BufferedReader where again you get the advantage of using buffered I/O streams. In case of Buffered input streams data is read from a memory area known as a buffer which makes reading more efficient.

The write method of the BufferedOuputStream takes either a byte array or an int as an argument thus you have to call getBytes() on any String that is passed to the write method. Here one thing to note is– If your file contains character data, the best approach is to use character streams like BufferedWriter. Byte streams should only be used for the most primitive I/O.

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileWriteDemo {
 public static void main(String[] args) {
  writeFileContent("G:\\test.txt");
 }
 
 private static void writeFileContent(String fileName){
  BufferedOutputStream bs = null;
  try {
   bs = new BufferedOutputStream(new FileOutputStream(fileName));
   bs.write("Writing one line".getBytes());
   // For windows, only \n for linux
   bs.write("\r\n".getBytes());
   bs.write("Writing second line".getBytes());
   
  } catch (IOException ioExp) {
   // TODO Auto-generated catch block
   ioExp.printStackTrace();
  }finally{
   if(bs != null){
    try {
     bs.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }
}

Java program to write to a file using BufferedWriter

BufferedWriter class has two constructors for specifying the buffer size or using the default size while writing to a file.

  • BufferedWriter(Writer out)- Creates a buffered character-output stream that uses a default-sized output buffer.
  • BufferedWriter(Writer out, int sz)- Creates a new buffered character-output stream that uses an output buffer of the given size.
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FileWrite {
 public static void main(String[] args) {
  writeFileContent("G:\\test1.txt");
 }
 
 private static void writeFileContent(String fileName){
  //BufferedWriter bw = null;
  // Using try-with-resources here 
  try(BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
   //bw = new BufferedWriter(new FileWriter(fileName));
   bw.write("Writing one line");
   bw.newLine();
   bw.write("Writing second line");
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Note that in this program try-with-resources is used to automatically manage resources. It is available from Java 7 and above.

Java program to write a file using Files class methods

In Java 7 Files class is added which provides write() method to write to a file in Java. There is also a newBufferedWriter method that can be used to write to a file. There are 2 overloaded versions of write method, note that one of them is added in Java 8.

  • public static Path write(Path path, byte[] bytes,OpenOption... options) throws IOException– Write bytes to a file specified by the path. Options varargs specifies whether new file is created for writing or bytes are appended to an already existing file. If no options are present then this method works as if the  CREATE, TRUNCATE_EXISTING, and WRITE options are present.
  • public static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options) throws IOException- Write lines of text to a file. Each line is a char sequence and is written to the file in sequence with each line terminated by the platform's line separator, as defined by the system propertyline.separator. Characters are encoded into bytes using the specified charset.

Using Files.write() method to write to a file

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileWrite8 {
 public static void main(String[] args) {
  String content = "This is the line to be added.\nThis is another line.";
  try {
   Files.write(Paths.get("G://test.txt"), content.getBytes());
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Here note that String is converted to Byte array and also there is no option parameter which means creating the file if it doesn't exist, or initially truncating an existing regular-file to a size of 0 if it exists.

Using Files.newBufferedWriter method

You can also use Files.newBufferedWriter() method to write to a file in Java.

There are 2 overloaded versions of newBufferedWriter method, note that one of them is added in Java 8.

  • public static BufferedWriter newBufferedWriter(Path path, OpenOption... options) throws IOException - Opens or creates a file for writing, returning a BufferedWriter to write text to the file in an efficient manner. Options parameter specifies whether new file is created for writing or bytes are appended to an already existing file. If no options are present then this method works as if the CREATE,  TRUNCATE_EXISTING, and WRITE options are present.
  • public static BufferedWriter newBufferedWriter(Path path, Charset cs,OpenOption... options) throws IOException - Opens or creates a file for writing, returning a BufferedWriter that may be used to write text to the file in an efficient manner. Here path is the path to the file, cs is the charset to use for encoding and options parameter specifies how the file is opened.
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileWrite8 {
 public static void main(String[] args) {
  Path path = Paths.get("G://test.txt");
  try (BufferedWriter writer = Files.newBufferedWriter(path)) {
      writer.write("Hello World");
      writer.newLine();
      writer.write("Hello again");
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Here note that no option parameter is given which means creating the file if it doesn't exist, or initially truncating an existing regular-file to a size of 0 if it exists.

That's all for this topic Write to a File in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Programs Page


Related Topics

  1. Reading Delimited File in Java Using Scanner
  2. How to Append to a File in Java
  3. How to Read File From The Last Line in Java
  4. Zipping Files in Java
  5. Try-With-Resources in Java Exception Handling

You may also like-

  1. Arrange Non-Negative Integers to Form Largest Number - Java Program
  2. Getting All The Schemas in a DB - Java Program
  3. Print Odd-Even Numbers Using Threads And wait-notify
  4. How to Convert Date And Time Between Different Time-Zones in Java
  5. Polymorphism in Java
  6. Difference Between Comparable and Comparator in Java
  7. Just In Time Compiler (JIT) in Java
  8. Different Bean Scopes in Spring