top of page

Exploring Java Data Types: Logging with Lombok's log.info()

  • pranaypourkar
  • Jun 14, 2023
  • 18 min read

Updated: Jul 7, 2023


Table of Contents




Primitive data types

The primitive data types include boolean, char, byte, short, int, long, float and double.

byte: The byte data type is used to store whole numbers from -128 to 127 (both inclusive). It occupies 8 bits or 1 byte of memory. Its default value is 0.
short: The short data type is used to store whole numbers from -32,768 to 32,767 (both inclusive). It occupies 16 bits or 2 bytes of memory.Its default value is 0.
int: The int data type is used to store whole numbers from -2,147,483,648 (-2^31) to 2,147,483,647 (2^31 -1). It occupies 32 bits or 4 bytes of memory. Its default value is 0.
long: The long data type is used to store whole numbers from -9,223,372,036,854,775,808 (-2^63) to 9,223,372,036,854,775,807 (2^63 -1) (both inclusive). It occupies 64 bits or 8 bytes of memory.
float: The float data type is used to store floating-point numbers with single precision. It occupies 32 bits or 4 bytes of memory. Its default value is 0.0f.
double: The double data type is used to store floating-point numbers with double precision. It occupies 64 bits or 8 byte of memory. Its default value is 0.0d.
boolean: The boolean data type is used to store either true or false values. It occupies 1 bit of memory. The default value of a boolean variable in Java is false
char: The char data type is used to store a single Unicode character using 16 bits or 2 bytes of memory. Its value range lies between '\u0000' (or 0) and '\uffff' (or 65,535). The '\u0000' character represents the lowest range of the Unicode system. In Java, if a char variable is declared without an explicit initialization, its default value is the null character, which is represented by '\u0000'.

char myChar1 = 'A'; // Prints to A
char myChar2 = 0; // Prints to null character (not visible)
char myChar3 = '\u00ff'; // Prints to ÿ

Java uses the Unicode character encoding system, not the ASCII code system.
Application.java
@Slf4j
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        byte myByte = 31;
        short myShort = -1000;
        int myInt = 1234567;
        long myLong = 76543210L;
        float myFloat = 2.54f;
        double myDouble = 4.545569d;
        boolean myBoolean = true;
        char myChar = 65;
        
        log.info("byte: {}", myByte);
        log.info("short: {}", myShort);
        log.info("int: {}", myInt);
        log.info("long: {}", myLong);
        log.info("float: {}", myFloat);
        log.info("double: {}", myDouble);
        log.info("boolean: {}", myBoolean);
        log.info("char: {}", myChar);
    }
}

Output
ree

Wrapper classes of the Java primitive data types


It includes eight wrapper classes Byte, Short, Integer, Long, Float, Double, Boolean, Character. Wrapper classes allow you to perform various operations on primitive values, such as converting them to strings, parsing strings to obtain primitive values, and providing utility methods for arithmetic operations and comparisons.

Byte: The Byte class wraps the byte primitive data type. It provides methods for working with byte values, such as converting bytes to strings and parsing strings to obtain byte values.
Short: The Short class wraps the short primitive data type. It provides methods for working with short values, such as converting shorts to strings and parsing strings to obtain short values.
Integer: The Integer class wraps the int primitive data type. It provides methods for working with int values, such as converting ints to strings and parsing strings to obtain int values.
Long: The Long class wraps the long primitive data type. It provides methods for working with long values, such as converting longs to strings and parsing strings to obtain long values.
Float: The Float class wraps the float primitive data type. It provides methods for working with float values, such as converting floats to strings and parsing strings to obtain float values.
Double: The Double class wraps the double primitive data type. It provides methods for working with double values, such as converting doubles to strings and parsing strings to obtain double values.
Boolean: The Boolean class wraps the boolean primitive data type. It provides methods for working with boolean values, such as converting booleans to strings and parsing strings to obtain boolean values.
Character: The Character class wraps the char primitive data type. It provides methods for working with char values, such as converting chars to strings and parsing

Application.java
@Slf4j
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        // Declaration of wrapper variables
        Byte wrapperByte = 100;
        Short wrapperShort = 123;
        Integer wrapperInteger = 2000;
        Long wrapperLong = 30000L;
        Float wrapperFloat = 5.14f;
        Double wrapperDouble = 6.14159d;
        Boolean wrapperBoolean = true;
        Character wrapperCharacter = 'B';

        // Logging the values
        log.info("Byte - {}", wrapperByte);
        log.info("Short - {}", wrapperShort);
        log.info("Integer - {}", wrapperInteger);
        log.info("Long - {}", wrapperLong);
        log.info("Float - {}", wrapperFloat);
        log.info("Double - {}", wrapperDouble);
        log.info("Boolean - {}", wrapperBoolean);
        log.info("Character - {}", wrapperCharacter);
    }
}
Output
ree

Non-primitive data types

The non-primitive data types includes Classes, Interfaces, and Arrays, Strings and Collections such as ArrayList, HashMap etc.

Class: A class is a blueprint for creating objects. It defines the properties (variables) and behaviors (methods) that objects of that class will have. Classes can have constructors, instance variables, static variables, methods, and can also be extended or implemented by other classes.
A class does not necessarily have to have a toString() method, but it is often recommended to provide one. By default, if a class does not explicitly override the toString() method inherited from the Object class, it will inherit the default implementation provided by Object. The default toString() method returns a string representation of the object's class name along with its hash code. For example
Person@1f32e575
Note, we will use Lombok @Data annotation which will automatically override toString() method
Person.java
package com.company.project.model;

import lombok.Data;

@Data
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
Application.java
@Slf4j
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        Person person = new Person("John", 25);
        log.info("Person - {}", person);
    }
}
Output
ree
Interfaces: An interface is a reference type that defines a set of methods that a class implementing the interface must implement. It provides a contract for the behavior of implementing classes. Interfaces can contain constant declarations and method signatures, but cannot have method implementations. It is not allowed to add a default implementation for toString() in an interface

Arrays: An array is a data structure that stores a fixed-size sequence of elements of the same type. Elements in an array can be accessed by their index, starting from 0. Arrays provide a way to store and manipulate collections of values.

>> Category: Based on Data Type
Array of Primitive Types
@Slf4j
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        short[] shortArray = {1, 2, 3, 4, 5};
        byte[] byteArray = {10, 20, 30, 40, 50};
        int[] intArray = {100, 200, 300, 400, 500};
        long[] longArray = {1000000001L, 1000000002L, 1000000003L};
        float[] floatArray = {98.5f, 85.2f, 76.8f};
        double[] doubleArray = {2.3d, 4.7d, 6.1d, 8.9d};
        boolean[] booleanArray = {true, false, true};
        char[] charArray = {'a', 'b', 'c', 'd'};

        log.info("short[]: {}", Arrays.toString(shortArray));
        log.info("byte[]: {}", Arrays.toString(byteArray));
        log.info("int[]: {}", Arrays.toString(intArray));
        log.info("long[]: {}", Arrays.toString(longArray));
        log.info("float[]: {}", Arrays.toString(floatArray));
        log.info("double[]: {}", Arrays.toString(doubleArray));
        log.info("boolean[]: {}", Arrays.toString(booleanArray));
        log.info("char[]: {}", Arrays.toString(charArray));
    }
}
ree

Array of Wrapper Classes
Arrays can be created to hold elements of wrapper classes for primitive types, such as Integer, Double, Character, etc.
@Slf4j
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        Short[] shortArray = {1, 2, 3, 4, 5};
        Byte[] byteArray = {10, 20, 30, 40, 50};
        Integer[] intArray = {100, 200, 300, 400, 500};
        Long[] longArray = {1000000001L, 1000000002L, 1000000003L};
        Float[] floatArray = {98.5f, 85.2f, 76.8f};
        Double[] doubleArray = {2.3d, 4.7d, 6.1d, 8.9d};
        Boolean[] booleanArray = {true, false, true};
        Character[] charArray = {'a', 'b', 'c', 'd'};

        log.info("Short[]: {}", Arrays.toString(shortArray));
        log.info("Byte[]: {}", Arrays.toString(byteArray));
        log.info("Integer[]: {}", Arrays.toString(intArray));
        log.info("Long[]: {}", Arrays.toString(longArray));
        log.info("Float[]: {}", Arrays.toString(floatArray));
        log.info("Double[]: {}", Arrays.toString(doubleArray));
        log.info("Boolean[]: {}", Arrays.toString(booleanArray));
        log.info("Char[]: {}", Arrays.toString(charArray));
    }
}
ree

Array of Strings
Since String is an object type in Java, an array can be created specifically to hold elements of type String.
       String[] names = {"Alice", "Bob", "Charlie"};
        log.info("Short[]: {}", Arrays.toString(names));
ree


Array of Classes
We can create an array of objects where each object is an instance of a class. This allows you to store multiple instances of the same class in an array.

Person.java
import lombok.Data;

@Data
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
Application.java
@Slf4j
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        Person[] people = {new Person("John", 25), new Person("Jane", 30), new Person("Doe", 20)};
        log.info("Person[]: {}", Arrays.toString(people));
    }
}
Output
ree

Array of Object class (java.lang.Object)
Every class in Java directly or indirectly inherits from the Object class. It provides a set of methods and behaviors that are available to all objects in Java. We can create an array of objects of the Object class in Java. The Object class is a superclass of all other classes in Java, so an array of Object can hold instances of any class.

Some key aspects of the Object class:

Default Methods: The Object class provides several default methods that can be overridden in subclasses, including equals(), hashCode(), toString(), clone(), finalize(), and more. These methods allow customization and behavior definition for objects.
Equality and Comparison: The equals() method in the Object class is used for comparing objects for equality. It checks if two objects are equal based on their content (not just reference equality). The hashCode() method is used for generating a hash code for an object, which is often needed when working with collections. The compareTo() method is used for comparing objects for ordering, implementing the Comparable interface.
String Representation: The toString() method in the Object class returns a string representation of the object. It is commonly used for debugging and printing object information.
Object Identity: The Object class provides the getClass() method, which returns the runtime class of an object. It also provides the finalize() method, which can be overridden to define the cleanup behavior before an object is garbage collected.
Synchronization: The Object class provides methods like wait(), notify(), and notifyAll() that are used for inter-thread communication and synchronization.
Array Support: The Object class provides methods such as clone() for creating a copy of an object and finalize() for cleaning up resources. These methods can be useful when working with arrays of objects.

Application.java
@Slf4j
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        // Create an array of Object
        Object[] objectArray = new Object[3];
        objectArray[0] = "Hello";
        objectArray[1] = 123;
        objectArray[2] = new Person("John", 23);

        // Access and use the elements of the array
        for (Object obj : objectArray) {
            if (obj instanceof String) {
                String str = (String) obj;
                log.info("String: {}", str);
            } else if (obj instanceof Integer) {
                int num = (int) obj;
                log.info("Integer: {}", num);
            } else if (obj instanceof Person) {
                Person myObj = (Person) obj;
                log.info("Custom Object: {}", myObj.getName());
            }
        }
        log.info("Object[]: {}", Arrays.toString(objectArray));
    }
}
Output
ree

>> Category: Based on Dimensions
In Java, we can create multi-dimensional arrays, which are arrays with more than one dimension. This allows to create arrays of arrays, forming a matrix-like structure. The Arrays.toString() method in Java is primarily designed to work with one-dimensional arrays. When you pass a multi-dimensional array (such as a two-dimensional array) to Arrays.toString(), it will not provide the desired output because it does not support nested arrays. The deepToString() method handles nested arrays and provides a string representation of the entire multi-dimensional array.

@Slf4j
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);

        // One-Dimensional Array
        int[] oneDArray = {1, 2, 3};
        log.info("oneDArray[]: {}", Arrays.toString(oneDArray));

        // Two-Dimensional Array
        int[][] twoDArray = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
        log.info("twoDArray[][]: {}", Arrays.deepToString(twoDArray));

        // Three-Dimensional Array
        int[][][] threeDArray = { { {1, 2}, {3, 4}, {5, 6} }, { {7, 8}, {9, 10}, {11, 12} } };
        log.info("threeDArray[][][]: {}", Arrays.deepToString(threeDArray));
    }
}
ree

Collections


List
An ordered collection that allows duplicate elements.
>> ArrayList
ArrayList is a class in Java that provides a resizable array implementation of the List interface. It belongs to the java.util package and is commonly used to store and manipulate collections of objects.
The ArrayList class offers several advantages over traditional arrays. One key advantage is its ability to dynamically resize itself, meaning you can add or remove elements without worrying about the underlying array's size. It automatically handles resizing and reallocation of memory as needed.

Some commonly used types that can be used as the "type" parameter in ArrayList<type>:
ArrayList<Integer>: Used to store integer values.
ArrayList<String>: Used to store strings.
ArrayList<Double>: Used to store floating-point numbers.
ArrayList<Boolean>: Used to store boolean values.
ArrayList<Character>: Used to store individual characters.
ArrayList<Long>: Used to store long integer values.
ArrayList<Byte>: Used to store byte values.
ArrayList<Short>: Used to store short integer values.
ArrayList<Float>: Used to store floating-point numbers with single precision.
ArrayList<SomeClass>: Used to store objects of a custom class SomeClass.
In Java, generics cannot be used with primitive types such as int, char, boolean, etc. Generics in Java only work with reference types. We can use the wrapper class (for eg) Integer instead in int. Reference types are objects or instances of classes. They are created using the new keyword and can have methods, properties, and additional functionalities defined within their respective classes. Primitive types are not objects and do not belong to any class. They are basic data types with a fixed size in memory and have no additional methods or properties.
       // List: ArrayList
        List<String> arrayList = new ArrayList<>();
        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add("Orange");
        log.info("ArrayList: {}", arrayList);
ree

>> LinkedList
LinkedList uses a doubly-linked list structure to store elements and dynamically allocates memory for each element. It provides efficient insertion and deletion operations but slower random access compared to ArrayList. In LinkedList, each element, known as a node, contains a reference to the previous and next nodes in the list. This allows efficient insertion and deletion operations as it only requires updating the references of neighboring nodes. However, accessing elements at a specific index in a LinkedList is less efficient compared to an ArrayList, as it requires traversing the list from the beginning or end until reaching the desired position.
        // List: LinkedList
        List<String> linkedList = new LinkedList<>();
        linkedList.add("Elephant");
        linkedList.add("Dog");
        linkedList.add("Cat");
        log.info("LinkedList: {}", linkedList);
ree

>> Vector
Vector is a class in Java that provides a dynamic array-like implementation similar to ArrayList. It is part of the java.util package.

The main differences between Vector and ArrayList are:
Thread Safety: Vector is synchronized, which means it is thread-safe and can be safely accessed by multiple threads concurrently. On the other hand, ArrayList is not synchronized, so it is not inherently thread-safe. If you require thread-safe behavior, we can use Collections.synchronizedList() to create a synchronized ArrayList.
Performance: Due to its synchronized nature, Vector may have some performance overhead compared to ArrayList. ArrayList generally performs better in single-threaded scenarios.

       // List: Vector
        List<String> vector = new Vector<>();
        vector.add("Red");
        vector.add("Green");
        vector.add("Blue");
        log.info("Vector: {}", vector);
ree

>> Stack
Stack is a class that represents a last-in, first-out (LIFO) data structure. It is part of the java.util package and extends the Vector class. However, it is usually recommended to use the Deque interface and its implementing class LinkedList instead, as Stack inherits from Vector, which is a legacy class.
       // List: Stack
        Stack<String> stack = new Stack<>();
        stack.push("One");
        stack.push("Two");
        stack.push("Three");
        log.info("Stack: {}", stack);
ree


Set
A collection that does not allow duplicate elements.
>> HashSet
HashSet is a class that implements the Set interface and provides an unordered collection of unique elements. It is part of the java.util package and offers constant-time performance for basic operations such as adding, removing, and checking for the presence of elements.
       // Set: HashSet
        Set<String> hashSet = new HashSet<>();
        hashSet.add("Apple");
        hashSet.add("Banana");
        hashSet.add("Orange");
        log.info("HashSet: {}", hashSet);
ree

>> LinkedHashSet
LinkedHashSet is a class that extends HashSet and provides a hash table implementation with predictable iteration order. It is part of the java.util package and combines the uniqueness of elements provided by HashSet with the insertion order preservation of LinkedHashMap

       // Set: LinkedHashSet
        Set<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("Cat");
        linkedHashSet.add("Dog");
        linkedHashSet.add("Elephant");
        log.info("LinkedHashSet: {}", linkedHashSet);
ree

>> TreeSet
TreeSet is a class that implements the SortedSet interface and provides a sorted set of unique elements. It is part of the java.util package and uses a self-balancing binary search tree to store and maintain its elements in sorted order.
       // Set: TreeSet
        Set<String> treeSet = new TreeSet<>();
        treeSet.add("Red");
        treeSet.add("Green");
        treeSet.add("Blue");
        log.info("TreeSet: {}", treeSet);
ree

Queue
A collection designed for holding elements prior to processing.
>> LinkedList
LinkedList can also be used to implement a Queue data structure. A queue is a collection that follows the first-in, first-out (FIFO) principle, where elements are added at the end and removed from the beginning.

LinkedList as a Queue offers several advantages:
- It allows efficient insertion and removal at both ends of the queue, making it suitable for implementing a FIFO structure.
- It can dynamically resize to accommodate elements without a fixed capacity.
- It provides additional methods from the LinkedList class, such as addFirst(), addLast(), removeFirst(), removeLast(), which can be useful in certain scenarios.

       // Queue: LinkedList
        Queue<String> linkedListQueue = new LinkedList<>();
        linkedListQueue.add("One");
        linkedListQueue.add("Two");
        linkedListQueue.add("Three");
        log.info("LinkedList: {}", linkedListQueue);
ree

>> PriorityQueue
PriorityQueue is a class that implements the Queue interface and provides a priority-based ordering of elements. It is part of the java.util package and internally uses a binary heap data structure to maintain the elements in the queue.

The key features of PriorityQueue include:
- It maintains the elements in a partially ordered state, with the highest-priority element at the head.
- It provides logarithmic-time performance (O(log n)) for insertion and removal operations.
- It does not provide constant-time access to arbitrary elements (e.g., random access by index).
- It allows duplicates unless a custom comparator is used that treats them as distinct elements.
       // Queue: PriorityQueue
        Queue<String> priorityQueue = new PriorityQueue<>();
        priorityQueue.add("Apple");
        priorityQueue.add("Banana");
        priorityQueue.add("Orange");
        log.info("PriorityQueue: {}", priorityQueue);
ree


Deque
A double-ended queue that supports adding and removing elements from both ends.
>> ArrayDeque
ArrayDeque is a class that implements the Deque interface and provides a resizable-array implementation of a double-ended queue. It is part of the java.util package and offers efficient insertion and removal operations at both ends of the deque

The key features of ArrayDeque include:
- It allows efficient insertion and removal at both ends of the deque.
- It provides constant-time performance (O(1)) for these basic operations.
- It can dynamically resize to accommodate elements without a fixed capacity.
- It can be used as a stack (Last-In, First-Out) or a queue (First-In, First-Out) depending on the required behavior.
- It does not allow null elements
       // Deque: ArrayDeque
        Deque<String> arrayDeque = new ArrayDeque<>();
        arrayDeque.addFirst("First");
        arrayDeque.addLast("Second");
        log.info("PriorityQueue: {}", arrayDeque);
ree

>> LinkedList
LinkedList can also be used to implement a Deque data structure. A deque (short for double-ended queue) is a collection that allows insertion and removal of elements at both ends.

LinkedList as a Deque offers several advantages:
- It allows efficient insertion and removal at both ends of the deque, making it suitable for various use cases.
- It can dynamically resize to accommodate elements without a fixed capacity.
- It provides additional methods from the LinkedList class, such as add(), remove(), get(), which can be useful in certain scenarios.
       // Deque: LinkedList
        Deque<String> linkedListDeque = new LinkedList<>();
        linkedListDeque.addFirst("First");
        linkedListDeque.addLast("Last");
        log.info("PriorityQueue: {}", linkedListDeque);
ree

Map
An object that maps keys to values, where each key is unique.
>> HashMap
HashMap is a class that implements the Map interface and provides a hash table-based implementation of a map. It is part of the java.util package and allows storing key-value pairs, where each key is unique.

The key features of HashMap include:
- It allows efficient insertion, retrieval, and removal of key-value pairs.
- It provides constant-time performance (O(1)) for basic operations on average.
- It does not maintain the insertion order of elements.
- It allows null values and one null key.
- It does not guarantee the order of iteration over the elements.

HashMap is commonly used when you need to store and retrieve data based on unique keys. It is suitable for a wide range of applications, including caching, indexing, and data lookup. HashMap is not thread-safe for concurrent access. If we require thread-safe behavior, we can use java.util.concurrent.ConcurrentHashMap, which is a concurrent implementation of the Map interface.

       // Map: HashMap
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "One");
        hashMap.put(2, "Two");
        hashMap.put(3, "Three");
        log.info("HashMap: {}", hashMap);
ree

>> LinkedHashMap
LinkedHashMap is a class that extends HashMap and provides a hash table-based implementation of a map that maintains the insertion order of elements. It is part of the java.util package and offers the same key-value mapping functionality as HashMap, with the additional guarantee of predictable iteration order based on the order of insertion.

The key features of LinkedHashMap include:
- It maintains the insertion order of elements, allowing predictable iteration order based on the order of insertion.
- It provides efficient insertion, retrieval, and removal of key-value pairs similar to HashMap.
- It offers constant-time performance (O(1)) for basic operations on average.
- It allows null values and one null key.
- It supports optional access-ordering, where elements can be ordered based on their access patterns.

LinkedHashMap is particularly useful when we need to iterate over the elements in the order they were inserted. It can be beneficial in scenarios where maintaining the insertion order is important, such as building a cache or preserving the order of configuration settings.
       // Map: LinkedHashMap
        Map<Integer, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put(1, "One");
        linkedHashMap.put(2, "Two");
        linkedHashMap.put(3, "Three");
        log.info("LinkedHashMap: {}", linkedHashMap);
ree

>> TreeMap
TreeMap is a class that implements the NavigableMap interface and provides a sorted map implementation based on a red-black tree data structure. It is part of the java.util package and offers key-value mapping where the keys are sorted in natural order or based on a custom comparator.

The key features of TreeMap include:
- It maintains the keys in a sorted order, allowing efficient retrieval of elements based on the key's natural order or a custom comparator.
- It provides logarithmic-time performance (O(log n)) for basic operations, such as insertion, retrieval, and removal.
- It allows null values but not null keys.
- It supports various methods for navigating the map, such as higherKey(), lowerKey(), ceilingKey(), and floorKey().
- It offers methods for submap views, including subMap(), headMap(), and tailMap(), to work with a portion of the map.

TreeMap is commonly used when you need to maintain a sorted order of keys and efficiently access elements based on their keys. It is suitable for scenarios where we require key-based lookups, range queries, or ordered iteration.
// Map: TreeMap
        Map<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(3, "Three");
        treeMap.put(1, "One");
        treeMap.put(2, "Two");
        log.info("TreeMap: {}", treeMap);
ree

>> Hashtable
Hashtable is a class that implements the Map interface and provides a hash table-based implementation of a map. It is part of the java.util package and offers key-value mapping where the keys are hashed to provide efficient lookup and retrieval.

The key features of Hashtable include:
- It provides efficient insertion, retrieval, and removal of key-value pairs based on the hashed keys.
- It offers constant-time performance (O(1)) for basic operations on average.
- It does not allow null keys or null values.
- It is synchronized and thread-safe, making it suitable for multi-threaded environments.
- It provides methods for enumerating keys and values, such as keys(), elements(), and entrySet().

Hashtable is commonly used when we need a synchronized and thread-safe map implementation. It ensures that the operations on the map are atomic and can be safely accessed by multiple threads concurrently. If we don't require synchronization or thread-safety, we can use HashMap instead, which provides similar functionality but without the overhead of synchronization.
       // Map: Hashtable
        Map<String, Integer> hashtable = new Hashtable<>();
        hashtable.put("One", 1);
        hashtable.put("Two", 2);
        hashtable.put("Three", 3);
        log.info("Hashtable: {}", hashtable);
ree

>> Properties
The Properties class is a subclass of Hashtable that represents a persistent set of properties. It is part of the java.util package and provides a convenient way to handle key-value pairs, typically used for configuration settings or application properties.

The key features of Properties include:
- It extends the Hashtable class, providing key-value mapping functionality.
- It is commonly used for managing configuration settings and application properties.
- It allows properties to be stored and loaded from various sources, such as files or input streams.
- It supports default properties, where a set of default values can be specified and used when a key is not found in the properties.
- It provides methods for storing properties to an output stream and loading properties from an input stream or a reader.

Properties is particularly useful when you need to handle key-value pairs for configuration purposes. It simplifies the process of storing and retrieving properties from different sources, such as property files or databases. Properties is synchronized and thread-safe, making it suitable for multi-threaded environments. However, if we don't require synchronization, we can use HashMap or LinkedHashMap for key-value mapping operations
       // Map: Properties
        Properties properties = new Properties();
        properties.setProperty("name", "John");
        properties.setProperty("age", "25");
        log.info("Properties: {}", properties);
ree

SortedSet
A set that maintains its elements in sorted order.
>> TreeSet
TreeSet is a class that implements the SortedSet interface. It represents a sorted set of elements stored in a tree-like structure. It is part of the java.util package and offers functionality similar to HashSet, but with elements sorted in their natural order or according to a custom comparator.

The key features of TreeSet include:
- It stores elements in sorted order, based on their natural order (if they implement the Comparable interface) or a custom comparator provided during set creation.
- It provides efficient insertion, deletion, and retrieval of elements, with a time complexity of O(log n) for basic operations.
- It does not allow duplicate elements, ensuring that each element in the set is unique.
- It supports operations for finding elements greater than or equal to a given element (ceiling(), higher()) and finding elements less than or equal to a given element (floor(), lower()).
- It provides methods for obtaining a subset of elements within a given range (subSet(), headSet(), tailSet()).

TreeSet is commonly used when we need to store elements in sorted order or perform operations such as finding the nearest elements or iterating in a sorted manner. It is particularly useful for scenarios where we require a dynamic set of elements that are always maintained in sorted order.
       // SortedSet: TreeSet
        SortedSet<Integer> sortedSet = new TreeSet<>();
        sortedSet.add(3);
        sortedSet.add(1);
        sortedSet.add(2);
        log.info("TreeSet: {}", sortedSet);
ree

SortedMap
A map that maintains its entries in sorted order.
>> TreeMap
TreeMap is a class that implements the SortedMap interface. It represents a sorted map based on a red-black tree data structure. It is part of the java.util package and offers functionality similar to HashMap, but with the keys sorted in their natural order or according to a custom comparator.

The key features of TreeMap include:
- It stores key-value pairs in sorted order based on the natural order of keys (if they implement the Comparable interface) or a custom comparator provided during map creation.
- It provides efficient insertion, deletion, and retrieval of key-value pairs, with a time complexity of O(log n) for basic operations.
- It does not allow duplicate keys, ensuring that each key in the map is unique.
- It supports operations for finding entries greater than or equal to a given key (ceilingEntry(), higherEntry()) and finding entries less than or equal to a given key (floorEntry(), lowerEntry()).
- It provides methods for obtaining a submap of entries within a given range (subMap(), headMap(), tailMap()).

TreeMap is commonly used when we need a map with sorted keys or when you require operations such as finding the nearest entries or iterating over the entries in sorted order. It is particularly useful for scenarios where we need a dynamic map that maintains keys in a sorted manner.
       // SortedMap: TreeMap
        SortedMap<Integer, String> sortedMap = new TreeMap<>();
        sortedMap.put(3, "Three");
        sortedMap.put(1, "One");
        sortedMap.put(2, "Two");
        log.info("TreeMap: {}", sortedMap);
ree

Enumeration
An interface representing an enumeration of a collection of objects.
>> Vector
Vector is a class that represents a dynamic array, similar to ArrayList, and is part of the java.util package. The Enumeration interface is also part of the java.util package and provides a way to iterate over a collection of objects.

The key features of Vector and Enumeration include:
- Vector is a resizable array that can grow or shrink dynamically.
- Enumeration provides a way to iterate over elements in a collection, such as a Vector, Hashtable, or legacy classes.
- Vector provides methods for adding, removing, and accessing elements in the vector, similar to ArrayList.
- Enumeration provides methods to check if there are more elements in the collection (hasMoreElements()) and to retrieve the next element (nextElement()).

       // Enumeration: Vector
        Vector<String> vectorEnum = new Vector<>();
        vectorEnum.add("One");
        vectorEnum.add("Two");
        vectorEnum.add("Three");
        Enumeration<String> enumeration = vectorEnum.elements(); // Prints to java.util.Vector$1@11478137
        String elements = Stream.generate(enumeration::nextElement)
                .limit(vectorEnum.size())
                .collect(Collectors.joining(" "));
        log.info("Enumeration Elements: {}", elements);
ree

>> Stack
Stack class implements the Vector class and provides additional methods to support a LIFO (Last-In-First-Out) stack of objects. The Enumeration interface is part of the java.util package and provides a way to iterate over a collection of objects.
Stack<String> stack = new Stack<>();
        stack.push("One");
        stack.push("Two");
        stack.push("Three");
        Enumeration<String> enumeration = stack.elements();
        String elements = Stream.generate(enumeration::nextElement)
                .limit(stack.size())
                .collect(Collectors.joining(" "));
        log.info("Enumeration Elements: {}", elements);

Iterator
An interface that provides a way to access elements in a collection. All collection classes provide iterators.
List<String> arrayList = new ArrayList<>();
        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add("Orange");
        
        // Iterator: All collection classes provide iterators.
        Iterator<String> iterator = arrayList.listIterator();
        
        String str = Stream.generate(iterator::next).limit(arrayList.size()).collect(Collectors.joining(" "));
        log.info("Iterator Elements: {}", str);
ree

ListIterator
An interface that extends the Iterator interface to provide additional functionality for traversing and modifying lists.
>> ArrayList
List<String> arrayList = new ArrayList<>();
        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add("Orange");
        
        // ListIterator: ArrayList
        ListIterator<String> arrayListIterator = arrayList.listIterator();
        
        String str = Stream.generate(arrayListIterator::next).limit(arrayList.size()).collect(Collectors.joining(" "));
        log.info("ListIterator Elements: {}", str);
ree

>> LinkedList
List<String> linkedList = new LinkedList<>();
        linkedList.add("Apple");
        linkedList.add("Banana");
        linkedList.add("Orange");
        
        // ListIterator: LinkedList
        ListIterator<String> linkedListIterator = linkedList.listIterator();
        
        String str = Stream.generate(linkedListIterator::next).limit(linkedList.size()).collect(Collectors.joining(" "));
        log.info("ListIterator Elements: {}", str);
ree


Thank you for taking the time to read this post. I hope that you found it informative and useful in your own development work.

Comments


bottom of page