Thursday, January 26, 2023

Java TemporalAdjusters Class With Examples

The java.time.temporal.TemporalAdjusters class is part of new date and time API added in Java 8 which provides common and useful TemporalAdjusters. TemporalAdjusters class in Java has many static methods for modifying temporal objects i.e. methods for adjustments of date and time.

You have to understand two interfaces Temporal and TemporalAdjuster to understand the whole concept of temporal objects.

java.time.temporal.Temporal interface

Temporal is a framework-level interface defining read-write access to a temporal object, such as a date, time, offset or some combination of these.

This is the base interface type for date, time and offset objects that are complete enough to be manipulated using plus and minus thus it provides access to date/time/offset information.

Some of the classes in new date and time API that implements Temporal interface are given below-

  • Instant
  • LocalDate
  • LocalDateTime
  • LocalTime
  • OffsetDateTime
  • OffsetTime
  • ZonedDateTime

So objects of these classes are of type Temporal and static methods of TemporalAdjusters class can modify these temporal objects.

java.time.temporal.TemporalAdjuster interface

TemporalAdjuster is a functional interface providing strategy for adjusting a temporal object. This interface has a single abstract method adjustInto() which adjusts the specified temporal object.

For example-

temporal = thisAdjuster.adjustInto(temporal);

But the recommended way is to use temporal = temporal.with(thisAdjuster); method rather than directly using the adjustInto() method.

java.time.temporal.TemporalAdjusters class

TemporalAdjusters class has many convenient methods that return a TemporalAdjuster. Some of the methods are listed below-

  • TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)- Returns the day-of-week in month adjuster, which returns a new date with the ordinal day-of-week based on the month.
  • TemporalAdjuster firstDayOfMonth()- Returns the "first day of month" adjuster, which returns a new date set to the first day of the current month.
  • TemporalAdjuster firstDayOfNextMonth()- Returns the "first day of next month" adjuster, which returns a new date set to the first day of the next month.
  • TemporalAdjuster firstDayOfYear()- Returns the "first day of year" adjuster, which returns a new date set to the first day of the current year.
  • TemporalAdjuster lastDayOfMonth()- Returns the "last day of month" adjuster, which returns a new date set to the last day of the current month.
  • TemporalAdjuster lastDayOfYear()- Returns the "last day of year" adjuster, which returns a new date set to the last day of the current year.

Java TemporalAdjusters Examples

1. Finding the first or last day of the month for a LocalDateTime object.

LocalDateTime ldt = LocalDateTime.now();
System.out.println("Current date time- " + ldt);
System.out.println("First day of the month- " + ldt.with(TemporalAdjusters.firstDayOfMonth()));
System.out.println("Last day of the month - " + ldt.with(TemporalAdjusters.lastDayOfMonth()));
Output
Current date time- 2019-11-20T10:39:26.583287900
First day of the month- 2019-11-01T10:39:26.583287900
Last day of the month – 2019-11-30T10:39:26.583287900

2. Finding the day of week in the month for a LocalDate object. In the example code first Sunday of the given month and the previous Sunday is calculated.

LocalDate ld = LocalDate.now();
System.out.println("Current Date - " + ld);
System.out.println("First Sunday of the month - " + ld.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.SUNDAY)));
System.out.println("Previous Sunday - " + ld.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)));
Output
Current Date - 2019-11-20
First Sunday of the month - 2019-11-03
Previous Sunday – 2019-11-17

Custom TemporalAdjuster examples

You can implement your own TemporalAdjuster to cater to specific requirement. Suppose you want to get the last working day of the month.

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;

public class WorkingDayAdjuster implements TemporalAdjuster {
  @Override
  public Temporal adjustInto(Temporal temporal) {
    LocalDateTime ldt = LocalDateTime.from(temporal);
    ldt = ldt.with(TemporalAdjusters.lastDayOfMonth());
    if(ldt.getDayOfWeek() == DayOfWeek.SATURDAY || ldt.getDayOfWeek() == DayOfWeek.SUNDAY) {
      ldt = ldt.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
    }
    return temporal.with(ldt);
  }
}
public class WorkingDay {
  public static void main(String[] args) {
    LocalDateTime ldt = LocalDateTime.now();
    System.out.println("Current Date - " + ldt);
    System.out.println("Last working day of the month - " + ldt.with(new WorkingDayAdjuster()));
  }
}
Output
Current Date - 2019-11-20T11:10:48.365786300
Last working day of the month - 2019-11-29T11:10:48.365786300

That's all for the topic Java TemporalAdjusters Class With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Reflection – Class Fields

Using Java Reflection you can get information about the class fields and get and set field values at run time. In Java Reflection API there is a class java.lang.reflect.Field that has methods for accessing field's type, field’s modifier and setting and getting values of a field.

Getting Field instance

First thing is to get the instance of Field class for that you will have to use methods of the java.lang.Class as that class is the entry point for all reflection operations.

There are 4 methods for getting field instance-

  1. getField(String name)- Returns a Field object representing the public member field of the class or interface.
  2. getFields()- Returns an array containing Field objects reflecting all the accessible public fields of the class or interface.
  3. getDeclaredField(String name)- Returns a Field object that reflects the specified declared field (even private) of the class or interface represented by this Class object.
  4. getDeclaredFields()- Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.

Getting information about class fields – Java example

This example shows how to get information like type, modifier of individual/all fields of a class. Methods of the Field class used are-

  • getType() method of the Field class returns the declared type for the field.
  • getModifiers() method of the field class returns the modifiers for the field as an integer.
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Set;

public class FieldReflectionDemo {
  public String str = "Reflection";
  private int i;
  public boolean flag = false;
  public Set<String> citySet;
    
  public static void main(String[] args) {
    try {
      FieldReflectionDemo obj = new FieldReflectionDemo();
      Class<?> c = obj.getClass();
      // get specific field
      Field f = c.getField("str");
      // getting field type
      Class<?> type = f.getType();
      // getting field modifiers
      int mod = f.getModifiers();
      System.out.println("Field name - " + f.getName()); 
      System.out.println("Field type - " + type.getName());
      System.out.println("Field modifiers - " + Modifier.toString(mod));
      System.out.println("--- Getting all fields ---");
      Field[] fields = c.getDeclaredFields();
      for(Field field : fields) {
        System.out.println("Field name - " + field.getName()); 
        System.out.println("Field type - " + field.getType());
        System.out.println("Field modifiers - " + Modifier.toString(field.getModifiers()));
      }        
    } catch (NoSuchFieldException | SecurityException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
Field name - str
Field type - java.lang.String
Field modifiers - public
--- Getting all fields ---
Field name - str
Field type - class java.lang.String
Field modifiers - public
Field name - i
Field type - int
Field modifiers - private
Field name - flag
Field type - boolean
Field modifiers - public
Field name - citySet
Field type - interface java.util.Set
Field modifiers - public

Getting and setting values

For getting value there is get(Object obj) method which returns the value of the field represented by this Field, on the specified object.

For Setting value there is set(Object obj, Object value) method which sets the field represented by this Field object on the specified object argument to the specified new value.

import java.lang.reflect.Field;
import java.util.Set;

public class FieldReflectionDemo {
  public String str = "Reflection";
  private int i;
  public boolean flag = false;
  public Set<String> citySet;
    
  public static void main(String[] args) {
    try {
      FieldReflectionDemo obj = new FieldReflectionDemo();
      Class<?> c = obj.getClass();
      // get specific field
      Field f = c.getField("str");
      // show value - get method
      System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj));
      // set new value
      f.set(obj, "New Value");
      System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj));        
    } catch (IllegalAccessException | NoSuchFieldException | SecurityException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
Field name- str Value- Reflection
Field name- str Value- New Value

Getting and setting value of a private field

You can even set value of a private field using Reflection. For that you need to set the accessible as true using setAccesssible() method.

In the example we have a class Access with one private int field i. In FieldReflectionDemo class we’ll access this field using reflection and set a value to it. If you don’t set the accessible flag using setAccesssible() method it will throw IllegalAccessException as shown below.

class Access{
  private int i;
}

public class FieldReflectionDemo {
  public String str = "Reflection";
  public boolean flag = false;
  public Set<String> citySet;
    
  public static void main(String[] args) {
    try {
      Access obj = new Access();
      Class<?> c = obj.getClass();
      // get specific field
      Field f = c.getDeclaredField("i");
      // show value - get method
      System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj));
      // set new value
      f.set(obj, 7);
      System.out.println("Field name- " + f.getName() + " Value- " + f.get(obj));       
    } catch (IllegalAccessException | NoSuchFieldException | SecurityException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
Output
java.lang.IllegalAccessException: class com.knpcode.programs.FieldReflectionDemo cannot access a member of class com.knpcode.programs.Access with modifiers "private"

Run again after making this change and you will be able to access even the private fields.

Field f = c.getDeclaredField("i");
f.setAccessible(true);
Output
Field name- i Value- 0
Field name- i Value- 7

Reference: https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/reflect/Field.html

That's all for the topic Java Reflection – Class Fields. If something is missing or you have something to share about the topic please write a comment.


You may also like

Tuesday, January 24, 2023

Java Generics- Generic Class, Interface And Method

Generics in Java was introduced in Java 5 to provide strict type checking at compile time.

Type parameters in Java Generics

Generics in Java enables you to write generic classes, interfaces and methods that can work with different data types. It is possible because you specify type parameters when defining classes, interfaces and methods. Type parameter can be any class or interface like Integer, String, custom class or interface.

For example in Collection API ArrayList class is written as-

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{

..
..
}

Here E is a type parameter which is enclosed in angle brackets (<>). Since a type parameter is specified- ArrayList<E> that means ArrayList class is a generic class where E is the type of elements in this List. With this generic class definition ArrayList can work with different data types. You will have to specify the actual type while initializing the ArrayList.

//List that stores Integers
List<Integer> nList = new ArrayList<Integer>();
nList.add(1);
nList.add(2);
nList.add(3);

// List that stores Strings
List<String> sList = new ArrayList<String>();
sList.add("A");
sList.add("B");
sList.add("C");

// List that stores objects of type Employee
List<Employee> eList = new ArrayList<Employee>();
Employee emp1 = new Employee("Jean", "HR", 6000);
eList.add(emp1);

Why Generics is required

You may argue that there is already an Object class in Java that can be used to refer any class object making it a good candidate to be used as a generic parameter. For example in the following class there is a method that has Object type as a parameter so you can pass any type to this method.

public class Test {
  public static void main(String[] args) throws IOException {
    Test t = new Test();
    t.display(1);
    t.display("Hello");
    t.display(5.67);
  }

  public void display(Object o) {
    System.out.println("passed argument is- " + o);
    System.out.println("passed argument's type is- " + o.getClass().getTypeName());
  }
}
Output
passed argument is- 1
passed argument's type is- java.lang.Integer
passed argument is- Hello
passed argument's type is- java.lang.String
passed argument is- 5.67
passed argument's type is- java.lang.Double

As you can see by using Object as parameter I can have a generic method that can work with any type so why Generics is required. Answer is Generics in Java bring type safety to your code. We’ll discuss that feature in next section.

Benefits of Java Generics

1. Strict type checks at compile time

Generics provide strict type checks at compile time so any type violation will give error as compile time itself rather than java.lang.ClassCastException thrown at run time.

For example you have initialized a List as a non-generic List and your intention is to store strings in it. Since it is not Generic which means all its elements will be stored as objects of Object class. If you add an Integer to this List by mistake there won't be any compile time error as Integer is also of type Object.

At the time of retrieving element from the List you will have to explicitly cast it to the type and that time it will throw ClassCastException when it encounters Integer.

public class Test {
  public static void main(String[] args) throws IOException {
    // Not generic
    List sList = new ArrayList();
    sList.add("A");
    sList.add("B");
    // Adding Integer
    sList.add(1);
    sList.add("C");
    
    Iterator itr = sList.iterator();
    while(itr.hasNext()){
      // Casting to string when retrieving
      String str = (String)itr.next();
      System.out.println("" + str);
    }
  }
}
Output
A
B
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
	at com.knpcode.programs.Test.main(Test.java:27)

With Generics you can specify the type of elements that can be stored in the List thus providing type safety. If you try to add element of any other type to this List you will get error at compile time itself.

public class Test {
  public static void main(String[] args) throws IOException {
    // Generic List
    List<String> sList = new ArrayList<String>();
    sList.add("A");
    sList.add("B");
    // Not allowed, Error at compile time if 
    // Integer is added 
    //sList.add(1);
    sList.add("C");
    
    Iterator<String> itr = sList.iterator();
    while(itr.hasNext()){
      String str = itr.next();
      System.out.println("" + str);
    }
  }
}

2. Explicit casting not required

Since type is specified with Generics and it is ensured that you can store elements only of the specified type so explicit casting is not required when retrieving elements.

In the above code when using a non-generic List, type casting is required.

Iterator itr = sList.iterator();
while(itr.hasNext()){
  // Casting to string when retrieving
  String str = (String)itr.next();
  System.out.println("" + str);
}

With a generic List type casting is not required.

Iterator<String> itr = sList.iterator();
while(itr.hasNext()){
  String str = itr.next();
  System.out.println("" + str);
}

3. Implement generic algorithms

By using generics, programmers can implement generic algorithms that work on different types, easier to read and are type safe too. Here is a simple Generic class example that can set and get value of any type.

public class Test<T> {
  T obj;
  public T getObj() {
    return obj;
  }
  public void setObj(T obj) {
    this.obj = obj;
  } 

  public static void main(String[] args) throws IOException {
    // With Integer type
    Test<Integer> intParam = new Test<Integer>();
    intParam.setObj(7);
    int value = intParam.getObj();
    System.out.println("Integer value- " + value);
    
    // With String type
    Test<String> strParam = new Test<String>();
    strParam.setObj("Test Value");
    String str = strParam.getObj();
    System.out.println("String value- " + str);
    
    // With Double type
    Test<Double> doubleParam = new Test<Double>();
    doubleParam.setObj(23.45);
    double dblValue = doubleParam.getObj();
    System.out.println("Double value- " + dblValue);
  }
}
Integer value- 7
String value- Test Value
Double value- 23.45

See How to write a generic Bubble Sort in Java in this post- Generic Bubble Sort Java Program

Type Parameter Naming Conventions in Java Generics

By convention, type parameter names are single, uppercase letters. The most commonly used type parameter names are:

  • T - Type
  • V - Value
  • E - Element
  • K - Key
  • N - Number
  • S,U,V etc. - 2nd, 3rd, 4th types

Generic Class

With the introduction of Generics done let’s see how we can create a Generic class in Java.

A generic class is defined with the following format:

class name<T1, T2, ..., Tn> { /* ... */ }

After the class name there is a type parameter section, delimited by angle brackets (<>). It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.

Generic class creation Java example

In this example we'll create a generic class with two type parameters and use it with different data types.

class GenericClass<K, V> {
  private K key;
  private V value;
  public GenericClass(K key, V value) {
    this.key = key;
    this.value = value;
  }
  public K getKey(){
    return key;
  }
  public V getValue(){
    return value;
  }
}

public class GenericDemo{
  public static void main(String[] args) {
    GenericClass<String, String> g1 = new GenericClass<>("Test", "Value");
    System.out.println("Key- " + g1.getKey());
    System.out.println("Value- " + g1.getValue());

    GenericClass<Integer, Integer> g2 = new GenericClass<>(1, 2);
    System.out.println("Key- " + g2.getKey());
    System.out.println("Value- " + g2.getValue());
    
    GenericClass<Integer, String> g3 = new GenericClass<>(1, "One");
    System.out.println("Key- " + g3.getKey());
    System.out.println("Value- " + g3.getValue());
  }    
}
Output
Key- Test
Value- Value
Key- 1
Value- 2
Key- 1
Value- One

Generic Interface

A Generic interface is created just like Generic class.

interface name<T1, T2, ..., Tn> { /* ... */ }

Some of the rules that are to be followed while implementing a Generic Interface are as given below

  1. If generic type parameter is used with the interface then the class that implements a generic interface has to be a generic class with the same type parameter.
    public class GenericClass<E> implements GenericInterface<E>
    
  2. If you provide a data type with the Interface then you can use a normal class.
    public class NormalClass implements GenericInterface<Integer>
    
  3. A Generic class can have other parameters too apart from the type parameter it has to use because if implementing a generic interface.
    public class GenericClass<K, V, E> implements GenericInterface<E>
    

Generic Method

Any method in Generic class can specify the type parameters of the class and free to add type parameters of its own too. You can have a generic method in a non-generic class too.

Generic Method Java example

Here we’ll have a generic method in a non-generic class.

class TestClass {
  // Generic method
  public <T> void displayArrayElements(T[] arr){
    System.out.println("Elements in Array- " + Arrays.toString(arr));
  }
}

public class GenericDemo{
  public static void main(String[] args) {
    TestClass obj = new TestClass();
    Integer[] intArray = {1, 2, 3, 4, 5, 6, 7};
    Double[] doubleArray = {1.2, 2.3, 3.4, 4.5, 5.6};
    String[] strArray = {"A", "B", "C", "D"};
    obj.displayArrayElements(intArray);
    obj.displayArrayElements(doubleArray);
    obj.displayArrayElements(strArray);
  }    
}
Output
Elements in Array- [1, 2, 3, 4, 5, 6, 7]
Elements in Array- [1.2, 2.3, 3.4, 4.5, 5.6]
Elements in Array- [A, B, C, D]

As you can see if you are writing a generic method with its own type parameters then you need to declare type parameters after the access modifier.

public <T> void displayArrayElements(T[] arr)

You can also specify the actual data type in angular brackets when calling a generic method. Though Java can automatically infer type based on the type of the method arguments so doing that is not mandatory.

obj.displayArrayElements(intArray);
Or this
obj.<Integer>displayArrayElements(intArray);

The Diamond Operator

Java 7 onward it is not mandatory to specify the type arguments required to invoke the constructor of a generic class, you can pass an empty set of type arguments (<>) as long as the compiler can determine, or infer, the type arguments from the context. This pair of angle brackets, <>, is informally called the diamond.

For example, If you have a Generic class defined as given below

public class Test<T> {
  ..
  ..
}

Then you can create its instance like this Java 7 onward.

Test<Integer> obj = new Test<>();

No need to specify Integer on the right hand side, just pass the empty angle brackets <>, type will be inferred automatically.

That's all for the topic Java Generics- Generic Class, Interface And Method. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Generics - Bounded Type Parameters

When you create a generic class or generic method the type parameters can be replaced by any class type but in some scenario you may want to restrict the types that can be used as type arguments in a parameterized type. That can be done using bounded type parameters in Java generics.

Why bounded type parameter needed in Java Generics

Let’s try to understand it with an example when you may need to use bounded parameters. For example, you have a generic class with a method that operates on numbers might only want to accept instances of Number or its subclasses.

First let’s see what happens if you don’t use bounded type parameters. As an example we’ll have a generic class with a method average() that returns the average of an array of numbers. You have defined a generic class so that you can pass array of any type integer, double, float.

public class BoundedType<T> {
  T[] numbers;
  BoundedType(T[] numbers){
    this.numbers = numbers;
  }

  public double average(){
    double sum = 0.0;
    for(int i = 0; i < numbers.length; i++){
      // Compile time error here
      sum += numbers[i].doubleValue();
    }
    double avg = sum/numbers.length;
    return avg;
  }
}

For calculating average suppose you have written a generic class as given above where you have used doubleValue() method to get number of type double for each number in the array. That should work well with any Number type as doubleValue() method is in Number class and it is the super class for all wrapper classes. But you will get compile time error at this line

sum += numbers[i].doubleValue();

Though your intention is to use this generic class always for numbers but there is no way for compiler to know that. For compiler BoundedType<T> means T can later be replaced by any type so there must be some mechanism for compiler to know that type parameter will be restricted to arguments of type Number. That’s where you use Bounded parameters in Java generics.

How to declare bounded type parameters

To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by a super class (upper bound)

<T extends parentclass>

This specifies that T can only be replaced by parentclass, or any child class of parentclass. So, parentclass acts as an upper bound here.

Bounded type parameter example

If we take the same example as above then you can use Number as the upper bound for the type parameter to get rid of the compile time error. With that compiler knows that the type used for the type parameter is going to be a Number or any of its subclass.

public class BoundedType<T extends Number> {
  T[] numbers;
  BoundedType(T[] numbers){
    this.numbers = numbers;
  }
  
  public double average(){
    double sum = 0.0;
    for(int i = 0; i < numbers.length; i++){
      // Compile time error here
      sum += numbers[i].doubleValue();
    }
    double avg = sum/numbers.length;
    return avg;
  }
  
  public static void main(String[] args) {
    Integer[] numArr = {3,4,5};
    BoundedType<Integer> obj = new BoundedType<Integer>(numArr);
    System.out.println("Average is: " + obj.average());
  }
}

Multiple Bounds in Java generics

Type parameter can have multiple bounds too.

<T extends A1 & A2 & A3>

A type variable with multiple bounds is a subtype of all the types listed in the bound. Note that in case of multiple bounds only one of the bounds can be a class others have to be interfaces. If one of the bounds is a class, it must be specified first. For example:

Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }

class D <T extends A & B & C> { /* ... */ }

Bounded type parameters with generic methods in Java

In the above example bounded parameter is used at a class level but you can have generic methods with bounded type parameters too. Consider a scenario where you have a method to count the number of elements in an array greater than a specified element and you have written it as given below.

public static <T> int countElements(T[] numbers, T element) {
  int count = 0;
  for (T e : numbers)
    if (e > element)  // compiler error
      ++count;
  return count;
}

You get compiler error at this line-

if (e > element)

because the greater than operator (>) applies only to primitive types such as short, int, double, long, float, byte, and char. You cannot use the > operator to compare objects.

You will have to use a type parameter bounded by the Comparable<T> interface to compile the code.

public static <T extends Comparable<T>> int countElements(T[] numbers, T element) {
  int count = 0;
  for (T e : numbers)
    if (e.compareTo(element) > 0)  // compiler error
      ++count;
  return count;
}

That's all for the topic Java Generics - Bounded Type Parameters. If something is missing or you have something to share about the topic please write a comment.


You may also like

Sunday, January 22, 2023

Java Generics - WildCards

While writing generic code you can also use a question mark (?) as type which represents an unknown type and known as wildcard in Java generics.

WildCard in Java generics and class relationship

You can use wildcards to create a relationship between generic classes or interfaces.

In case of non-generic classes

class A { /* ... */ }
class B extends A { /* ... */ }

You can assign reference of child class to parent class.

B b = new B();
A a = b;

But the same assignment does not apply to generic types.

List<B> lb = new ArrayList<>();
List<A> la = lb;   // compile-time error

So, List<B> is not the subtype of List<A> even if A is the parent class.

You can also understand it using the list of integers (List<Integer>) and list of numbers (List<Number>) where Number is the parent class of Integer but List<Integer> is not a subtype of List<Number> in fact, these two types are not related. The common parent of List<Number> and List<Integer> is List<?>. List of unknown type that could be a List<Integer>, List<A>, List<String> and so on.

Using this knowledge of common parent of two generic classes we’ll see how to create a bounded relationship between two generic classes (or interfaces) using three types of wildcards.

Types of wildcards in Java Generics

Based on the limit you want to impose on the relationship between two generic classes there are three types of wildcards.

  • Upper bounded wildcards
  • Lower bounded wildcards
  • Unbounded wildcards

Upper bounded wildcards

To declare an upper-bounded wildcard, use the wildcard character ('?'), followed by the extends keyword, followed by the type that acts as upper bound. Upper bound wildcard matches the upper bound type or any of its subclasses.

For example List<? extends Number> matches a list of type Number or any of its subclasses i.e. List<Integer>, List<Double>, List<Number>.

Upper bounded wildcard Java example

Suppose you want to write a method that can add all the elements of the passed list. Since you have to add the elements so List should have elements of type Integer, Float, Double since Number is the super class for all these wrapper classes so you can create an upper bound using Number class.

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

public class WildCard {
  public static void main(String[] args) {
    List<Integer> li = Arrays.asList(1, 2, 3, 4);
    System.out.println("sum = " + addListElements(li));
    //List<Double>
    List<Double> ld = Arrays.asList(1.1, 2.2, 3.3, 4.4);
    System.out.println("sum = " + addListElements(ld));
  }
    
  public static double addListElements(List<? extends Number> list){
    double s = 0.0;
    for (Number n : list) {
      s += n.doubleValue();
    }
    return s;
  }
}
Output
sum = 10.0
sum = 11.0

Lower bounded wildcards

A lower bounded wildcard is expressed using the wildcard character ('?'), following by the super keyword, followed by its lower bound. For example

<? super A>

A lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type. For example you want to write a method that works on lists of Integer and the supertypes of Integer, such as Integer, Number, and Object then you would specify a lower bounded wildcard like this-

List<? super Integer>

Lower bounded wildcards Java example

Suppose you want to write a method that can insert integers to the end of a list and that can be a List of Object, List of Number or List of Integer then you can create a lower bound using Integer class.

import java.util.ArrayList;
import java.util.List;

public class WildCard {
  public static void main(String[] args) {
    // with List<Object>
    List<Object> lo = new ArrayList<Object>();
    insertNumbers(lo);
    
    // with List<Number>
    List<Number> ln = new ArrayList<Number>();
    insertNumbers(ln);
    
    // with List<Integer>
    List<Integer> li = new ArrayList<Integer>();
    insertNumbers(li);
  }
    
  public static void insertNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
      list.add(i);
    }
    System.out.println("Elements in List- " + list);
  }
}
Output
Elements in List- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Elements in List- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Elements in List- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Unbounded wildcards in Java generics

The unbounded wildcard type is specified using the wildcard character (?).

For example, List<?> represents a list of unknown type.

Unbounded wildcard Java example

Suppose you want to write a method that can print elements of a List of any type then you should use List<?> as method argument. Using List<Object> won’t work as List<Integer>, List<String>, List<Double> are not subtypes of List<Object>.

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

public class WildCard {
  public static void main(String[] args) {
    // With List<Integer>
    List<Integer> li = Arrays.asList(5, 6, 7);
    printListElements(li);
    // With List<Double>
    List<Double> ld = Arrays.asList(1.2, 3.8, 8.2);
    printListElements(ld);
  }
    
  public static void printListElements(List<?> list){
    for (Object e : list){
      System.out.print(e + " ");
    }
    System.out.println();
  }
}
Output
5 6 7 
1.2 3.8 8.2 
That's all for the topic Java Generics - WildCards. If something is missing or you have something to share about the topic please write a comment.
You may also like

Friday, January 6, 2023

LocalDateTime in Java With Examples

The java.time.LocalDateTime class is part of new date and time API added in Java 8 that represents a date-time in the ISO-8601 calendar system, such as 2019-10-03T11:15:35, it represents a date-time, often viewed as year-month-day-hour-minute-second. LocalDateTime class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock.

LocalDateTime class is immutable thus thread-safe. Since it is marked as final so can't be extended. In this post we’ll see some examples demonstrating usage of Java LocalDateTime class.

Creating instances of LocalDateTime

LocalDateTime class in Java doesn't have any public constructors to obtain an instance, you will use a factory method to get an instance.

1. Using now() method you can obtain the current date-time from the system clock in the default time-zone.

LocalDateTime dateTime = LocalDateTime.now();
System.out.println(dateTime); //2019-10-30T10:29:37.082914100

2. Using of() method you can create an instance of LocalDateTime by passing both year, month, day and hour, minute, second values.

There is also an of() method to create an instance of LocalDateTime by passing both LocalDate and LocalTime instances.

  • of(LocalDate date, LocalTime time)
LocalDateTime dateTime = LocalDateTime.of(2019, 10, 28, 11, 59, 59);
System.out.println(dateTime); //2019-10-28T11:59:59

LocalDateTime for specific time-zone

You can also obtain the current date-time from the system clock in the specified time-zone by passing the zone id.

ZoneId zone1 = ZoneId.of("America/Los_Angeles");
ZoneId zone2 = ZoneId.of("Asia/Kolkata");
LocalDateTime ldt1 = LocalDateTime.now(zone1);
LocalDateTime ldt2 = LocalDateTime.now(zone2);

System.out.println(ldt1); //2019-10-29T22:05:57.729368200
System.out.println(ldt2); //2019-10-30T10:35:57.827541900

Getting date and time values from LocalDateTime

Since LocalDateTime has both date and time values so it has methods to get year, month, day values as well as methods to get hour, minute, second values too.

public class FormatDate {
  public static void main(String[] args) {
    LocalDateTime dateTime = LocalDateTime.of(2019, 10, 28, 11, 59, 59);
    System.out.println("Date-Time: " + dateTime);
    
    System.out.println("Year- " + dateTime.getYear());
    System.out.println("Month- " + dateTime.getMonthValue());
    System.out.println("Day- " + dateTime.getDayOfMonth());
    
    System.out.println("Hour- " + dateTime.getHour());
    System.out.println("Minute- " + dateTime.getMinute());
    System.out.println("Second- " + dateTime.getSecond());
  }
}
Output
Date-Time: 2019-10-28T11:59:59
Year- 2019
Month- 10
Day- 28
Hour- 11
Minute- 59
Second- 59

Formatting LocalDateTime

Using DateTimeFormatter you can specify the pattern for formatting LocalDateTime.

public class FormatDate {
  public static void main(String[] args) {
    // get datetime
    LocalDateTime dateTime = LocalDateTime.now();
    // Format pattern
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
    System.out.println(dateTime.format(formatter));
    // Format pattern
    formatter = DateTimeFormatter.ofPattern("cccc, MMM dd, yyyy hh:mm:ss a");
    System.out.println(dateTime.format(formatter));
  }
}
Output
2019-10-30T11:06:51.899
Wednesday, Oct 30, 2019 11:06:51 AM

Date calculations using LocalDateTime

There are methods to add or subtract days, months and years from a LocalDateTime.

public class FormatDate {
  public static void main(String[] args) {
    // get datetime
    LocalDateTime dateTime = LocalDateTime.now();

    System.out.println("Created Date-Time: " + dateTime);  
    System.out.println("Date after subtraction - " + dateTime.minusDays(40));
    System.out.println("Date after year subtraction - " + dateTime.minusYears(2));
     
    System.out.println("Date after addition - " + dateTime.plusDays(40));
    System.out.println("Date after year addition - " + dateTime.plusYears(2));
  }
}
Output
Created Date-Time: 2019-10-30T11:11:06.820635900
Date after subtraction - 2019-09-20T11:11:06.820635900
Date after year subtraction - 2017-10-30T11:11:06.820635900
Date after addition - 2019-12-09T11:11:06.820635900
Date after year addition – 2021-10-30T11:11:06.820635900

Time calculations using LocalDateTime

There are methods to add or subtract hours, minutes, seconds, nano seconds from a LocalDateTime.

public class FormatDate {
  public static void main(String[] args) {
    // get datetime
    LocalDateTime dateTime = LocalDateTime.now();

    System.out.println("Created Date-Time: " + dateTime);  

    System.out.println("Hour after subtraction- " + dateTime.minusHours(2));
    System.out.println("Minute after subtraction- " + dateTime.minusMinutes(10));
    System.out.println("Second after subtraction- " + dateTime.minusSeconds(20));
    System.out.println("NanoSecond after subtraction- " + dateTime.minusNanos(100));

    System.out.println("Hour after addition- " + dateTime.plusHours(1));
    System.out.println("Minute after addition- " + dateTime.plusMinutes(15));
    System.out.println("Second after addition- " + dateTime.plusSeconds(25));
    System.out.println("NanoSecond after addition- " + dateTime.plusNanos(100));
  }
}
Output
Created Date-Time: 2019-10-30T11:14:07.632356
Hour after subtraction- 2019-10-30T09:14:07.632356
Minute after subtraction- 2019-10-30T11:04:07.632356
Second after subtraction- 2019-10-30T11:13:47.632356
NanoSecond after subtraction- 2019-10-30T11:14:07.632355900
Hour after addition- 2019-10-30T12:14:07.632356
Minute after addition- 2019-10-30T11:29:07.632356
Second after addition- 2019-10-30T11:14:32.632356
NanoSecond after addition- 2019-10-30T11:14:07.632356100

Comparing LocalDateTimes in Java

For comparing two LocalDateTime instances there are the following methods-

  • compareTo(ChronoLocalDateTime<?> other)- Compares this date-time to another date-time. Returns negative value if less than tha passed LocalDateTime instance, positive if greater.
  • isAfter(ChronoLocalDateTime<?> other)- Checks if this date-time is after the specified date-time.
  • isBefore(ChronoLocalDateTime<?> other)- Checks if this date-time is before the specified date-time.
  • isEqual(ChronoLocalDateTime<?> other)- Checks if this date-time is equal to the specified date-time.
public class FormatDate {
  public static void main(String[] args) {
    // get datetime
    LocalDateTime ldt1 = LocalDateTime.of(2019, Month.OCTOBER, 25, 20, 25, 45);
    LocalDateTime ldt2 = LocalDateTime.of(2019, Month.SEPTEMBER, 20, 22, 18, 40);

    System.out.println("Created Date-Time1: " + ldt1);  
    System.out.println("Created Date-Time2: " + ldt2);

    System.out.println(ldt1.compareTo(ldt2));
    System.out.println(ldt2.compareTo(ldt1));

    System.out.println(ldt1.isAfter(ldt2));
    System.out.println(ldt1.isBefore(ldt2));
    System.out.println(ldt1.isEqual(ldt2));
  }
}
Output
Created Date-Time1: 2019-10-25T20:25:45
Created Date-Time2: 2019-09-20T22:18:40
1
-1
true
false
false

Converting String to LocalDateTime

Check this post for String to LocalDateTime conversion- Convert String to Date in Java

Converting LocalDateTime to String

Check this post for LocalDateTime to String conversion- Convert Date to String in Java

That's all for the topic LocalDateTime in Java With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Thursday, January 5, 2023

LocalTime in Java With Examples

The java.time.LocalTime class is part of new date and time API added in Java 8 that represents a time in the ISO-8601 calendar system, such as 10:12:36. LocalTime class does not store or represent a date or time-zone. Instead, it is a description of the local time as seen on a wall clock.

LocalTime class is immutable thus thread-safe. Since it is marked as final so can't be extended.

In this post we’ll see some examples demonstrating usage of Java LocalTime class.

Creating instances of LocalTime

LocalTime class doesn't have any public constructors to obtain an instance, you will use a factory method to get an instance.

1. Using now() method you can obtain the current time from the system clock in the default time-zone.

LocalTime currentTime = LocalTime.now();
System.out.println(currentTime); //19:08:04.782387100

2. To obtain an instance of LocalTime by passing hour, minute, second using of() method.

LocalTime currentTime = LocalTime.of(18, 22, 32);
System.out.println(currentTime); //18:22:32

Note that of() method is overloaded so that you can pass all the four arguments (hour, minute, second, nano second) or only three (hour, minute, second) or only two (hour, minute)

  • of(int hour, int minute)
  • of(int hour, int minute, int second)
  • of(int hour, int minute, int second, int nanoOfSecond)

Local Time for specific time-zone

You can also obtain the current time from the system clock in the specified time-zone by passing the zone id.

ZoneId zone1 = ZoneId.of("America/Los_Angeles");
ZoneId zone2 = ZoneId.of("Asia/Kolkata");
LocalTime time1 = LocalTime.now(zone1);
LocalTime time2 = LocalTime.now(zone2);

System.out.println(time1); //06:52:20.179414600
System.out.println(time2); //19:22:20.222512

Getting hour, minute, second values from LocalTime

Using getHour(), getMinute(), getSecond() and getNano() methods of the LocalTime class you can get hour, minute, second and nano second field respectively.

public class FormatDate {
  public static void main(String[] args) {
    LocalTime time = LocalTime.of(18, 22, 32);
    System.out.println("Hour- " + time.getHour());
    System.out.println("Minute- " + time.getMinute());
    System.out.println("Second- " + time.getSecond());
  }
}
Output
Hour- 18
Minute- 22
Second- 32

Formatting LocalTime

Using DateTimeFormatter you can specify the pattern for formatting LocalTime.

public class FormatDate {
  public static void main(String[] args) {
    LocalTime time = LocalTime.of(18, 22, 32);
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("hh:mm:ss a");
    System.out.println("Time- "+time.format(dtf));
    
    dtf = DateTimeFormatter.ofPattern("HH:mm:ss");
    System.out.println("Time- "+time.format(dtf));
  }
}

Time calculations using LocalTime

There are methods to add or subtract hours, minutes, seconds, nano seconds from a LocalTime.

  • minusHours(long hoursToSubtract)- Returns a copy of this LocalTime with the specified number of hours subtracted.
  • minusMinutes(long minutesToSubtract)- Returns a copy of this LocalTime with the specified number of minutes subtracted.
  • minusSeconds(long secondsToSubtract)- Returns a copy of this LocalTime with the specified number of seconds subtracted.
  • minusNanos(long nanosToSubtract)- Returns a copy of this LocalTime with the specified number of nanoseconds subtracted.
  • plusHours(long hoursToAdd)- Returns a copy of this LocalTime with the specified number of hours added.
  • plusMinutes(long minutesToAdd)- Returns a copy of this LocalTime with the specified number of minutes added.
  • plusSeconds(long secondstoAdd)- Returns a copy of this LocalTime with the specified number of seconds added.
  • plusNanos(long nanosToAdd)- Returns a copy of this LocalTime with the specified number of nanoseconds added.
public class FormatDate {
  public static void main(String[] args) {
    LocalTime time = LocalTime.of(20, 25, 45, 534);
    System.out.println("Time- " + time);
    
    System.out.println("Hour after subtraction- " + time.minusHours(2));
    System.out.println("Minute after subtraction- " + time.minusMinutes(10));
    System.out.println("Second after subtraction- " + time.minusSeconds(20));
    System.out.println("NanoSecond after subtraction- " + time.minusNanos(100));
    
    System.out.println("Hour after addition- " + time.plusHours(1));
    System.out.println("Minute after addition- " + time.plusMinutes(15));
    System.out.println("Second after addition- " + time.plusSeconds(25));
    System.out.println("NanoSecond after addition- " + time.plusNanos(100));		
  }
}
Output
Time- 20:25:45.000000534
Hour after subtraction- 18:25:45.000000534
Minute after subtraction- 20:15:45.000000534
Second after subtraction- 20:25:25.000000534
NanoSecond after subtraction- 20:25:45.000000434
Hour after addition- 21:25:45.000000534
Minute after addition- 20:40:45.000000534
Second after addition- 20:26:10.000000534
NanoSecond after addition- 20:25:45.000000634

Comparing LocalTimes in Java

For comparing two LocalTime instances there are the following methods-

  • compareTo(LocalTime other)- Compares this time to another time. Returns a negative value if less than the passed LocalTime, positive if greater.
  • isAfter(LocalTime other)- Checks if this time is after the specified time.
  • isBefore(LocalTime other)- Checks if this time is before the specified time.
public class FormatDate {
  public static void main(String[] args) {
    LocalTime time1 = LocalTime.of(20, 25, 45);
    LocalTime time2 = LocalTime.of(22, 18, 40);
    
    System.out.println(time1.compareTo(time2));
    System.out.println(time2.compareTo(time1));
    
    System.out.println(time1.isAfter(time2));
    System.out.println(time1.isBefore(time2));
  }
}
Output
-1
1
false
true

Converting String to LocalTime

Check this post for String to LocalTime conversion- Convert String to Date in Java

Converting LocalTime to String

Check this post for LocalTime to String conversion- Convert Date to String in Java

That's all for the topic LocalTime in Java With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like