Core Java - Yash-777/MyWorld GitHub Wiki

OOPs Concepts scaler.com

OOPs or Object-Oriented Programming is an approach to programming which organizes a program around its data and well-defined interfaces. We use it to make our code closer to the real world. Some of the popular OOP languages include Java, C++, and Python.

What Is an Object?

Real-world objects contain state and behavior. state is stored in fields and behavior is exposed through methods.

image


Different ways to create an Object? new, class.getConstructor().newInstance(), Class.forname("EmpClass").newInstance()

Object Creation in 5 Ways;

  • new operator
  • EmpClass.class.newInstance() - LoadClass using Class.forname("EmpClass").newInstance() -- using newInstance() of a class forName() - Classnot found Exception, newInstance - IllegalAccessException
  • EmpClass.class.getConstructor().newInstance() - unsing Constructor Class newInstance
  • Object cloning - Emp implements Clonable - @Override clone() { super.clone() } - CloneNotSupportedException
  • Creating using DeSerialisation - Emp inplements Serialisable
    Serial- FileOutputSteam fos = new FOS("serial.txt"); - state storing to file fileNotfoundException
    ObjectOutputStream oos = new OOS(fos);
    oos.writeObject(new Emp());
    Deserial - FileInputStream fis = new FIS("serial.txt");
    ObjInputStream ois = OIS(fis);
    Emp emp = ois.readObject();

What Is a Class?

A class is a blueprint or prototype from which objects are created.



JVM Class Loaders Bootstrap, Extensions, System/Application

In Java, a class loader is responsible for loading Java classes and resources from a file system, network or other sources into the Java Virtual Machine (JVM) at runtime.

Different class loaders are used in Java to load classes from different sources. Here are some of the commonly used class loaders in Java:

  • Bootstrap class loader: This is the default class loader in Java that is responsible for loading core Java classes from the JAVA_HOME/lib directory. It is implemented in native code and is not a Java class. the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.

  • Extension class loader (sun.misc.Launcher$ExtClassLoader): This class loader is responsible for loading classes from the extensions directory (JAVA_HOME/lib/ext).

  • System class loader (sun.misc.Launcher$AppClassLoader): This class loader loads classes from the classpath. It is also called the application class loader and is used to load classes from the current working directory or other user-specified locations.

  • Custom class loaders: In addition to the above class loaders, custom class loaders can be created to load classes from custom locations or from remote servers.

public class ClassLoaderTest {
    public static void main(String[] args) {
    	// print the class loaders for the current class and its parent classes
        Class<?> clazz = ClassLoaderTest.class;
        while (clazz != null) {
            System.out.println(clazz.getName() + " is loaded by " + clazz.getClassLoader());
            clazz = clazz.getSuperclass();
        }
        
        System.out.println("JVM ClassLoader's");
        
        System.out.println("Bootstrap Class Loader: It loads JDK internal classes jre/lib/rt.jar");
        System.out.println("lib/rt.jar : Abstract Interface « " + java.io.Serializable.class.getClassLoader());
        System.out.println("lib/rt.jar : String  « " + java.lang.Object.class.getClassLoader());
        System.out.println("lib/rt.jar : Object  « " + java.lang.String.class.getClassLoader());
        System.out.println("lib/rt.jar : HashMap « " + java.util.HashMap.class.getClassLoader());
        
        
        System.out.println("lib/rt.jar : NameService Abstract Interface « " + sun.net.spi.nameservice.NameService.class.getClassLoader());
        System.out.println("lib/rt.jar : SensitivityWatchEventModifier Enum « " + com.sun.nio.file.SensitivityWatchEventModifier.class.getClassLoader());
        
        //usually $JAVA_HOME/lib/ext directory. « C:\Program Files (x86)\Java\jdk1.7.0_80\jre\lib\ext\dnsns.jar
        System.out.println("Extensions Class Loader: It loads classes from the JDK extensions directory $JAVA_HOME/lib/ext/dnsns.jar");
        System.out.println("lib/ext/dnsns.jar : DNSNameService « " + sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
        
        //System CL – It loads classes from the current classpath that can be set while invoking a program using -cp or -classpath command line options.
        System.out.println("Application Class Loader: Build|Class Path libraries"); // sun.misc.Launcher$AppClassLoader@2a139a55
        System.out.println("-cp : this class « " + ClassLoaderTest.class.getClassLoader());
    }
}
/*
lib/rt.jar : Object  « null

lib/ext/dnsns.jar : DNSNameService « sun.misc.Launcher$ExtClassLoader@33909752

-cp : this class « sun.misc.Launcher$AppClassLoader@2a139a55
*/



What are Access Modifiers in Java? default, pubic, private, protected

You must have seen public, private, and protected keywords while practicing java programs, these are called access modifiers. The access modifiers in Java specifies the accessibility or scope of classes, interfaces, variables, methods, constructors, data members, and setter methods.

There are two levels of access control:

  • At the top-level— public, or package-private (no explicit modifier).
  • At the member level— public, private, protected, or default (“default access“, “package-private” or “no modifier“).

image


Object-Oriented Programming Concepts

What is inheritance in OOP?

Inheritance is a mechanism in OOP that allows one class to inherit properties and behavior from another class. The class that is being inherited from is called the superclass, and the class that is inheriting is called the subclass. This allows for code reusability and promotes the concept of modularity in software development.

What is polymorphism in OOP?

Polymorphism is the ability of an object to take on multiple forms. In OOP, polymorphism refers to the ability of a method to perform different actions based on the object that it is called upon. This can be achieved through method overriding, where a subclass provides a different implementation of a method that is already defined in its superclass.

What is encapsulation in OOP?

Encapsulation is a mechanism in OOP that wraps data and behavior within an object, making it inaccessible to the outside world. Encapsulation is achieved through the use of access modifiers such as "private" and "protected", which restrict access to the members of an object. This protects the internal state of an object from external modification and promotes the concept of data hiding.

What is abstraction in OOP?

Abstraction is a mechanism in OOP that allows the hiding of complex implementation details behind a simple interface. This allows for the creation of objects with well-defined interfaces, without exposing the underlying implementation details. This promotes the concept of modularity in software development, as well as simplifies the use of complex systems by hiding the complexities of their implementation.

What is the difference between method overloading and method overriding?

Method overloading is the ability of a class to have multiple methods with the same name, but with different parameter lists. This allows for the creation of methods that perform similar actions, but with different inputs. Method overriding, on the other hand, is the ability of a subclass to provide a new implementation of a method that is already defined in its superclass.

What is the difference between an abstract class and an interface?

An abstract class is a class that cannot be instantiated on its own and serves as a base for subclasses, while an interface is a blueprint for classes and defines a set of methods that must be implemented by the classes that implement the interface. Abstract classes can have instance variables and instance methods, while interfaces cannot. Interfaces can be used to define a common set of methods that can be implemented by multiple classes, while abstract classes are used to provide a common implementation of methods that can be inherited by subclasses.

Interface Java8
public class Test implements I1, I2{
    public static void main(String[] args) {
        
        Test obj = new Test();
        obj.print();
        I1.i1();
        I2.i2();
    }

    @Override
    public void print() {
        I1.super.print(); // Calling print of I1 interface
    }
}
interface I1 {
    static void i1() {
        System.out.println("I1 static function");
    }
    default void print() {
        System.out.println("I1 print");
    }
}
interface I2 {
    static void i2() {
        System.out.println("I2 static function");
    }
    default void print() {
        System.out.println("I2 print");
    }
}

Polymorphism : Methods Overloading, Overhiding, overriding

The ability of a reference variable to change the behaviour according to what object instance it is holding.
The @overriden methods behaves differently on different objcet calls.

Polymorphism allows you define one interface and have multiple implementtations.

There are two types of Polymorphism in Java Example

  1. Compile time polymorphism (Static binding) – Method overloading
  2. Runtime polymorphism (Dynamic binding) – Method overriding
  • Overloading Method Signatures with in the same class has method's name same but with the different parameter types.

    The signature of the method declared as:

    methodName(parametersList y) 
    
  • Over Ridding Method Declarations form its parent class

    An instance method in a subclass with the same signature and return type as an instance method in the superclass overrides the superclass's method. Overriding and Hiding Methods

    Method signature « It consists of method name and parameter list
    	           (number of parameters, type of the parameters and order of the parameters). 
    accessModifier   « Cannot reduce the visibility of the inherited method from parent class
    		   [Public, default, protected] 
    returnType       « must be same as its parent 
    throwsExceptionsList « its up to the child class code. it may throw or not
    
      public void M1() throws Ex { } // superclass
      public void M1() { } // Child Valid
    
      public void M2() { } // superclass
      public void M2() { } // Child should not use throws exception

    accessModifier « Cannot reduce the visibility of the inherited method from parent class

    OverHiding: Static access from reference side.
    OverRiding: Instance access from constructor side.

    accessModifier returnType methodName(paramtersList ...) throwsExceptionsList {
       methodBody
    }
    
    public void m1(int a) throws Exception {
       ...
    }

    Overriding method (method of child class) can throw unchecked exceptions, regardless of whether the overridden method(method of parent class) throws any exception or not. However the overriding method should not throw checked exceptions

    When overriding a method, you might want to use the @Override annotation that instructs the compiler that you intend to override a method in the superclass. If, for some reason, the compiler detects that the method does not exist in one of the superclasses, then it will generate an error.

    Checked Unchecked
    Checked exceptions are checked at compile-time.(try-catch | throws) Unchecked exceptions are occurred at Runtime due to the bad data provided|Interactions
    SQLException, IOException-FileNotFoundException, ClassNotFoundException NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException, NumberFormatException

    NOTE: Method arguments are passed by value « Primitive arguments, such as an int or a double, are passed into methods by value. This means that any changes to the values of the parameters exist only within the scope of the method. When the method returns, the parameters are gone and any changes to them are lost.



Polymorphism : Methods Overloading, Overhiding, overriding

The ability of a reference variable to change the behaviour according to what object instance it is holding.
The @overriden methods behaves differently on different objcet calls.

Polymorphism allows you define one interface and have multiple implementtations.

There are two types of Polymorphism in Java Example

  1. Compile time polymorphism (Static binding) – Method overloading
  2. Runtime polymorphism (Dynamic binding) – Method overriding
  • Overloading Method Signatures with in the same class has method's name same but with the different parameter types.

    The signature of the method declared as:

    methodName(parametersList y) 
    
  • Over Ridding Method Declarations form its parent class

    An instance method in a subclass with the same signature and return type as an instance method in the superclass overrides the superclass's method. Overriding and Hiding Methods

    Method signature « It consists of method name and parameter list
    	           (number of parameters, type of the parameters and order of the parameters). 
    accessModifier   « Cannot reduce the visibility of the inherited method from parent class
    		   [Public, default, protected] 
    returnType       « must be same as its parent 
    throwsExceptionsList « its up to the child class code. it may throw or not
    
      public void M1() throws Ex { } // superclass
      public void M1() { } // Child Valid
    
      public void M2() { } // superclass
      public void M2() { } // Child should not use throws exception

    accessModifier « Cannot reduce the visibility of the inherited method from parent class

    OverHiding: Static access from reference side.
    OverRiding: Instance access from constructor side.

    accessModifier returnType methodName(paramtersList ...) throwsExceptionsList {
       methodBody
    }
    
    public void m1(int a) throws Exception {
       ...
    }

    Overriding method (method of child class) can throw unchecked exceptions, regardless of whether the overridden method(method of parent class) throws any exception or not. However the overriding method should not throw checked exceptions

    When overriding a method, you might want to use the @Override annotation that instructs the compiler that you intend to override a method in the superclass. If, for some reason, the compiler detects that the method does not exist in one of the superclasses, then it will generate an error.

    Checked Unchecked
    Checked exceptions are checked at compile-time.(try-catch | throws) Unchecked exceptions are occurred at Runtime due to the bad data provided|Interactions
    SQLException, IOException-FileNotFoundException, ClassNotFoundException NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException, NumberFormatException

    NOTE: Method arguments are passed by value « Primitive arguments, such as an int or a double, are passed into methods by value. This means that any changes to the values of the parameters exist only within the scope of the method. When the method returns, the parameters are gone and any changes to them are lost.


Conditional Flow of Control

switch, ternary operator(exp?val:val2), for, foreach, while, do-while, switch

Switch

switch(expression) {
  case x:
    // code block
    break; // optional
  case y:
    // code block
    break; // optional
  default: // optional
    // code block to be executed if no cases match
}

Ternary Operator Variable = Condition ? Expression1 : Expression2

Loop for, for-each, while, do-while

The Java for-each loop or enhanced for loop is introduced since J2SE 5.0. It provides an alternative approach to traverse the array or collection in Java. It is mainly used to traverse the array or collection elements.

for(Initialization ; Test Expression ; Updation){ //for(int i = 0; i >= 0; i++)
    // Body of the Loop (Statement(s))
}
for(Identifier : Collection){
    // Statements
}
Initialization;
while(Test Expression){
    // Body of the Loop (Statement(s))
    Updation;
}
do {
  // Body of the loop (Statement(s))
  // Updation;
}
while(Test Expression);

break, Continue Statement, System.exit(0)

As mentioned earlier, System.exit(0) method terminates JVM which results in termination of the currently running program too. Status is the single parameter that the method takes. If the status is 0, it indicates the termination is successful.

String Class, String Constant/intern Pool, String Buffer, String Builder

Java - Stack Memory Allocation and Heap Memory Allocation, SCP/SIP

String Constant/Intern Pool

String pool is a storage space in the Java heap memory where string literals are stored. It is also known as String Constant Pool or String Intern Pool. It is privately maintained by the Java String class. By default, the String pool is empty. A pool of strings decreases the number of String objects created in the JVM, thereby reducing memory load and improving performance.

Whenever a string literal is created, the JVM first checks the String Constant Pool before creating a new String object corresponding to it.

Memory allocation methods used in Java - Stack Memory Allocation and Heap Memory Allocation.

  • In stack memory, only the primitive data types like- int, char, byte, short, boolean, long, float and double are stored.
  • Whereas, in the heap memory, non-primitive data types like strings are stored. A reference to this location is held by the stack memory.

Ways to Create Strings

There are three popular ways of creating strings in Java:

  • String literal
  • Using new keyword
  • Using String.intern() method

Characters, String, String Buffer, String Builder

Interface CharSequence

Characters: Most of the time, if you are using a single character value, you will use the primitive char type.

The Character class wraps a value of the primitive type char in an object. An object of class Character contains a single field whose type is char.

char ch = 'a';
char[] charArray = { 'a', 'b', 'c', 'd', 'e' };
Character charWrapper = new Character('a');

The Character class is immutable, so that once it is created, a Character object cannot be changed.

image 'https://stackoverflow.com/a/26498954/5081877'

Strings, which are widely used in Java programming, are a sequence of characters. In the Java programming language, strings are objects.

String greeting = "Hello world!";

char[] helloArray = { 'h', 'e', 'l', 'l', 'o', '.' };
String helloString = new String(helloArray);

The String class is immutable, so that once it is created a String object cannot be changed

  • public String intern(): Returns a canonical representation for the string object.

    intern() « Before saving in String Constant Pool(SCP) it invokes intern() method to check object availability with same content in pool using equals method. If String-copy is available in the Pool then returns the reference. Otherwise, String object is added to the pool and returns the reference.

    A pool of strings, initially empty, is maintained privately by the class String.

    When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

    It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.

  • string concatenation operator ( + )

  • hash() « String @override hash() of Object class to generate same hash code for sequence of characters.

  • equals and == « == operator is to check the hash code where as equals() method is to check the content of a String.

  • indexOf(int ch): Returns the index within this string of the first occurrence of the specified character.

    String str = "Greetings";
    if (str.indexOf('G') > -1) //Return 0th index position as it is available
    if (str.indexOf('Y') = -1) //Return -1th index position as it is not-available

StringBuilder

A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.

StringBuilder objects are like String objects, except that they can be modified. Internally, these objects are treated like variable-length arrays that contain a sequence of characters. At any point, the length and content of the sequence can be changed through method invocations.

Unlike strings, every string builder also has a capacity, the number of character spaces that have been allocated. The capacity, which is returned by the capacity() method, is always greater than or equal to the length (usually greater than) and will automatically expand as necessary to accommodate additions to the string builder.

StringBuilder sb = new StringBuilder(); // creates empty builder, capacity 16
sb.append("Greetings");// adds 9 character string at beginning

image

If you convert the palindrome string to a string builder, you can use the reverse() method in the StringBuilder class. It makes the code simpler and easier to read:

public class StringBuilderDemo {
    public static void main(String[] args) {
        String palindrome = "Dot saw I was Tod";
         
        StringBuilder sb = new StringBuilder(palindrome); // String to StringBuilder Conversion
        
        sb.reverse();  // reverse it
        
        String reverseStr = sb.toString(); // StringBuilder to String convertion
        System.out.println(reverseStr);
    }
}

Running this program produces the same output:

doT saw I was toD

StringBuffer class that is exactly the same as the StringBuilder class, except that it is thread-safe by virtue of having its methods synchronized.

String reverse program.

public static String reverseStr(String str) {
    //String str = "Yashwanth"; //https://stackoverflow.com/a/59166517/5081877
    String collect = IntStream.range(0, str.length())
            .boxed().sorted(Collections.reverseOrder())
            .map(i -> { 
                System.out.println(i);
                return String.valueOf(str.charAt(i)); 
                })
            .distinct().collect(Collectors.joining("")); //htnawsY
            //.collect(Collectors.joining("")); //htnawhsaY
            //.collect(Collectors.joining(".")); //h.t.n.a.w.h.s.a.Y
    System.out.println("Reverse Str:"+collect);
    return collect;
}
public class ReverseObject {
    public static void main(String[] args) {
        // String is immutable Object, once created we cannot change the object
        //The SCP is an area inside the heap memory. It contains the unique strings. 
        //In order to put the strings in the string pool, one needs to call the intern().
        String s1_scp = "Yash";
        System.out.println("SCP intern():"+s1_scp.intern());
        String s2_scp = "Yash";
        System.out.println("SCP intern():"+s2_scp.intern());
        
        String s3_h = new String("Yash");
        String s4_h = new String("Yash");
        
        System.out.println("Memory Address & Content :"+ (s1_scp == s2_scp));
        System.out.println("Memory Address & Content :"+ (s3_h   == s4_h));
        
        System.out.println("Content :"+ s1_scp.equals(s2_scp) );
        System.out.println("Content :"+ s3_h.equals(s4_h));
        
        String str = "Yashwanth";
        stringReverse(str, false);
        stringReverse(str, true);
        
        int num = 1234;
        reverseNumberString(num);
        reverseNumber(num);
        
        StringBuffer buff = new StringBuffer(str);
        System.out.println("String Buffer : "+ buff.reverse());
        
        // Use List interface to reverse string.
        char[] ch = str.toCharArray();
        List<Character> reverse = new LinkedList<>();
        for (int i = ch.length - 1; i >= 0; i--) {
            reverse.add(ch[i]);
        }
        System.out.println("Reverse of a String with LIST : "+ reverse);
    }
    
    public static String stringReverse(String str, boolean isDistinct) {
        char[] ch = str.toCharArray();
        String reverse = "";
        for (int i = ch.length - 1; i >= 0; i--) {
            if ( isDistinct && !(reverse.indexOf(ch[i]) > -1) ) // Remove duplicates
                reverse += ch[i];
            if (!isDistinct) reverse += ch[i];
        }
        System.out.println("Reverse of a String: "+ reverse +", DISTINCT:"+isDistinct);
        return reverse;
    }

    public static int reverseNumberString(int num) {
        String str = new Integer(num).toString();
        char[] ch = str.toCharArray();
        String reverse = "";
        for (int i = ch.length - 1; i >= 0; i--) {
                reverse += ch[i];
        }
        System.out.println("Reverse of a String Number : "+ reverse);
        return Integer.parseInt(reverse);
    }

    public static int reverseNumber(int num) {
        int temp = num;
        int rev = 0;
        int sum = 0; // sumOfDigits
        while (temp > 0 ) {
            rev = (rev * 10) + temp % 10;
            sum += temp % 10;
            temp = temp / 10;
        }
        System.out.println("Reverse of a Number : "+ rev);
        System.out.println("Sum of Digits of a Number : "+ sum);
        
        if(rev == num) {
            System.out.println("Polyndrome Number : [121 = 121]");
        }
        return rev;
    }
}

Widening, Narrowing Primitive Conversion, Autoboxing and Unboxing primitives to Wrappers

Widening(Implicit), Narrowing(Explicit) Primitive Conversion

A widening conversion occurs when you convert from a type with smaller (or narrower) to type with larger (or wider) range. Because of this, there is no chance for data loss and the conversion is considered "safe."

A narrowing conversion occurs when you convert from a type with larger (or wider) to type with smaller (or narrower) range. Since we are shrinking the range, there is a chance of data loss so this conversion is considered "unsafe"

Widening Implicit converion from int to float, their is no loss of data.
Narrowing explicit conversion form float to int, thier is loss of data

byte to short, int, long, float, or double

Autoboxing and Unboxing Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on. If the conversion goes the other way, this is called unboxing.

Primitive type Wrapper class
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double


Comparable java.lang.Comparable: int compareTo(Object o1) vs Comparator java.util.Comparator: int compare(Object o1, Object o2)

Comparable - java.lang.Comparable: int compareTo(Object o1)

A comparable object is capable of comparing itself with another object. The class itself must implements the java.lang.Comparable interface in order to be able to compare its instances.

  • Capable of comparing current object with the provided object.
  • By using this we can implement only one sort sequence based on the instances properties. EX: Person.id
  • Some of the Predefined Classes like String, Wrapper classes, Date, Calendar has implemented Comparable interface.

Comparator - java.util.Comparator: int compare(Object o1, Object o2)

A comparator object is capable of comparing two different objects. The class is not comparing its instances, but some other class’s instances. This comparator class must implement the java.util.Comparator interface.

  • Capable of comparing any two Objects of Same Type.
  • By using this we can implement many sort sequence and name each, based on the instances properties. EX: Person.id, Person.name, Person.age
  • We can implement Comparator interface to our Pre-defined classes for Customized sorting.

Example:

public class Employee implements Comparable<Employee> {
    
    private int id;
    private String name;
    private int age;
    private long salary;
    
    // Many sort sequences can be created with different names.
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
    public static Comparator<Employee> idComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
        }
    };
    
    public Employee() {    }
    public Employee(int id, String name, int age, long salary){
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    // setters and getters.
    
    // Only one sort sequence can be created with in the class.
    @Override
    public int compareTo(Employee e) {
    //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
    //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        if (this.id > e.id) {
            return 1;
        }else if(this.id < e.id){
            return -1;
        }else {
            return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        }
        
    }    

    public static void main(String[] args) {
        
        Employee e1 = new Employee(5, "Yash", 22, 1000);
        Employee e2 = new Employee(8, "Tharun", 24, 25000);
        
        List<Employee> list = new ArrayList<Employee>();
        list.add(e1);
        list.add(e2);
        Collections.sort(list); // call @compareTo(o1)
        Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
        Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
    }
}
  • For customized sorting we go for comparator @compare(o1, o2) for other scenarios we go for comparable @compareTo(o1), with out changing code if we want to sort more than one field then we use comparator.

For Java 8 Lambda : Comparator refer to my post.


⚠️ **GitHub.com Fallback** ⚠️