Tuesday, 14 January 2025

What are the SOLID principles in object-oriented programming (OOP)

The SOLID principles are a set of five design principles in object-oriented programming (OOP) that help make software designs more understandable, flexible, and maintainable. The acronym SOLID stands for:

  1. S - Single Responsibility Principle (SRP):

    • A class should have only one reason to change, meaning it should have only one job or responsibility. This helps make the system easier to maintain and understand by reducing the complexity of each class.
    • Example: A class that handles both customer data management and logging responsibilities would violate this principle. Instead, you could split the responsibilities into two separate classes: one for customer data and one for logging.
  2. O - Open/Closed Principle (OCP):

    • Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means that you should be able to add new functionality to a class without changing its existing code, typically by using inheritance or interfaces.
    • Example: Instead of modifying a class directly to add a new feature, you could extend the class via a subclass or implement a new interface.
  3. L - Liskov Substitution Principle (LSP):

    • Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. This ensures that derived classes can stand in for their base classes without introducing bugs or unexpected behavior.
    • Example: If a subclass overrides methods of the superclass, the overridden methods should behave in a way that is consistent with the expectations set by the superclass.
  4. I - Interface Segregation Principle (ISP):

    • Clients should not be forced to depend on interfaces they do not use. This principle advocates for creating smaller, more specific interfaces rather than large, general ones that combine multiple responsibilities.
    • Example: Instead of having a single interface with multiple unrelated methods (like IWorker that includes Work and Eat), you could split it into IWorkable and IEatable interfaces, so clients only implement what they need.
  5. D - Dependency Inversion Principle (DIP):

    • High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. This helps to decouple components and reduce the impact of changes in lower-level details.
    • Example: Instead of a high-level class directly instantiating a low-level class, you can inject dependencies through an interface or abstraction, allowing for greater flexibility in testing and maintenance.

Friday, 3 January 2025

Java 8 Steam API | on Object based operations

 package com.sk.demos;

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

import java.util.stream.Collectors;

public class OperationsOnStundentObject {

public static void main(String[] args) {

List<Student> listStd = Arrays.asList(new Student("ravi", 1, 60), new Student("suri", 2, 80),

new Student("kavi", 3, 90), new Student("mani", 4, 50), new Student("suvi", 5, 70));

                // get list of marks from student object

List<Integer> studentMarks = listStd.stream()

.map(marks -> marks.getMarks())

.collect(Collectors.toList());

System.out.println("studentMarks::" + studentMarks);

                // Finding highest marks using Stream API

System.out.println("\nPrinting the highest marks");

Optional<Integer> highestMarks = listStd.stream()

.map(Student::getMarks) // Mapping to only marks

.max(Integer::compare); // Finding max marks

// Printing the highest marks if present

highestMarks.ifPresent(System.out::println);

// Finding student with highest marks using Stream API

System.out.println("\nFinding student with highest marks");

Optional<Student> highestMarksStudent = listStd.stream()

.max((student1, student2) -> Integer.compare(student1.getMarks(), student2.getMarks()));

highestMarksStudent.ifPresent(System.out::println);

// Sorting by names in ascending order

        System.out.println("\nAscending order based on names:");

                listStd.stream().

sorted((student1,student2)-> student1.getStudenName().compareTo(student2.getStudenName()))

                .forEach(System.out::println);


        // Sorting by names in descending order

        System.out.println("\nDescending order based on names:");

                    listStd.stream()

        .sorted((student1, student2) -> student2.getStudenName().compareTo(student1.getStudenName()))

                .forEach(System.out::println);

}

}

output:
=====================
studentMarks::[60, 80, 90, 50, 70]

Printing the highest marks
90

Finding student with highest marks
Student [studenName=kavi, studentId=3, marks=90]

Ascending order based on names:
Student [studenName=kavi, studentId=3, marks=90]
Student [studenName=mani, studentId=4, marks=50]
Student [studenName=ravi, studentId=1, marks=60]
Student [studenName=suri, studentId=2, marks=80]
Student [studenName=suvi, studentId=5, marks=70]

Descending order based on names:
Student [studenName=suvi, studentId=5, marks=70]
Student [studenName=suri, studentId=2, marks=80]
Student [studenName=ravi, studentId=1, marks=60]
Student [studenName=mani, studentId=4, marks=50]
Student [studenName=kavi, studentId=3, marks=90]