Angle Bracket <> in Java with Examples Different types of Recursions in Java Java Lambda Filter Example Java Program for Shopping Bill Pythagorean Triplet with Given Sum Using Single Loop in Java TemporalAdjusters lastInMonth() method in Java with Examples ZIP API in Java Atomic reference in Java Digit Extraction in Java DRY (Don't Repeat Yourself) Principles in Java with Examples Empty array in Java Is main method compulsory in Java? Java I/O Operation - Wrapper Class vs Primitive Class Variables Java Program to Find the Perimeter of a Rectangle Java Thread Priority Java Type Erasure Need of Concurrent Collections in Java Nested ArrayList in Java Print Odd and Even Numbers by Two Threads in Java Square pattern in Java TemporalAdjusters next() method in Java with Examples What does start() function do in multithreading in Java Convert Number to Words Problem in Java Detect And Remove Cycle in a Single Linked List in Java Evolution of Interfaces in Java How to pad a String in Java Implementing Patricia Trie in Java Java Program to Find the Most Repeated Word in a Text File java.util.UUID class in Java ReadWriteLock Interface in Java Reference Data Types in Java Sort An Array According to The Count of Set Bits in Java Alternate Vowel and Consonant string in Java Built-in Exceptions in Java with Examples Capture the Pawns Problem in Java Collections.shuffle() Method in Java with Examples JDBC MySQL Localhost 3306 Alternate Vowel and Consonant string in Java Built-in Exceptions in Java with Examples Capture the Pawns Problem in Java Collections.shuffle() Method in Java with Examples Convert Number to Words Problem in Java Detect And Remove Cycle in a Single Linked List in Java Evolution of Interfaces in Java How to pad a String in Java Implementing Patricia Trie in Java Java Program to Find the Most Repeated Word in a Text File java.util.UUID class in Java ReadWriteLock Interface in Java Reference Data Types in Java Sort An Array According to The Count of Set Bits in Java JDBC MySQL Localhost 3306 Adding a Character as Thousands Separator to Given Number in Java Circular Primes in Java Equilibrium Index Problem in Java Java String regionMatches() Method with Examples LFU Cache Problem in Java Longest Repeating and Non-Overlapping Substring in Java Prefix Suffix Search in Java Product Array Puzzle Problem in Java Russian Doll Envelopes Problem in Java Second Most Repeated Word in a Sequence in Java Special Two-Digit Numbers in a Binary Search Tree in Java Swap Corner Words and Reverse Middle Characters in Java Toggle K bits Problem in Java Upside Down Binary Tree in Java Verbal Arithmetic Puzzle Problem in Java Insert a String into another String in Java Print Shortest Path to Print a String on Screen in Java Search Insert Position in Java BST Sequences in Java Burrows - Wheeler Data Transform Algorithm in Java Convert BST to Min Heap in Java Fibonacci Sum in Java Get name of current method being executed in Java Keith number in Java Longest Even Length Substring in Java Saint-Exupery Numbers in Java Standard practice for protecting sensitive data in Java application Strobogrammatic number in Java Types of Methods in Java Programming Valid Number Problem in Java Boggle Search Problem in Java Convert Java Object to JSON String using Jackson API Generate Random String in Java Java Program to Determine the Unicode Code Point at Given Index in Strin Java 18 snippet tags Jumping Numbers in Java Junction Numbers in Java Find Four Elements that Sums to a given value in Java How to print string vertically in Java How to remove in string in Java Three-Way Partition Problem in Java Apocalyptic Number in Java Check if the given two matrices are mirror images of one another in Java Duplicate Characters Problem in Java Duplicate Parenthesis Problem in Java Sum of Minimum and Maximum Elements of all Subarrays of Size K in Java Triple Shift Operator in Java Valid Pairing of Numbers in Java Valid Sudoku problem in Java Java Cipher Class Kth Missing Positive Number in Java Largest Square Matrix Problem in Java Length of the longest substring without repeating characters in Java Minimum Cost to Make String Valid Problem in Java Ordered pair in Java Range Addition Problem in Java

DRY (Don't Repeat Yourself) Principles in Java with Examples

The DRY (Don't Repeat Yourself) principle is a software development concept that encourages the avoidance of duplicating code in a codebase. The idea is to write code once and reuse it wherever necessary, rather than duplicating the same logic in multiple places. This principle promotes code maintainability, reduces the chances of introducing bugs, and makes the codebase more modular. In Java, several techniques and patterns can be used to adhere to the DRY principle.

Key components of DRY principle

1. Encapsulation

Encapsulation involves bundling the implementation details of a piece of functionality into a well-defined unit, such as a function, method, class, or module. By encapsulating logic, you can create reusable components that can be invoked whenever the specific functionality is needed. Encapsulation ensures that a piece of logic is defined in a single place, reducing redundancy and making it easier to maintain.

2. Abstraction

Abstraction involves simplifying complex systems by modeling classes based on the essential properties of the problem domain. It allows developers to focus on the high-level functionality without getting bogged down by unnecessary details. Abstraction helps create generalized solutions that can be reused across different parts of the application, reducing the need for duplicating similar code.

3. Modularity

Modularity involves breaking down a system into smaller, independent, and interchangeable modules. Each module should have a specific, well-defined responsibility. By creating modular components, developers can avoid duplicating entire sections of code. Instead, they can reuse existing modules in different parts of the application.

4. Reusable Components

Creating reusable components involves designing and implementing units of code that can be used in various parts of an application or even across different projects. Reusable components are a direct manifestation of the DRY principle, as they enable the same logic to be applied in multiple contexts without duplication.

5. Functions/Methods

Functions (or methods in object-oriented languages) are a fundamental building block of code. They encapsulate a specific piece of functionality and can be called from various parts of the code. Writing functions for common tasks allows developers to avoid duplicating the same logic in multiple places, promoting code reuse.

6. Inheritance (for Object-Oriented Languages)

-Inheritance allows a class to inherit properties and methods from another class, promoting code reuse and extensibility. Common functionality can be placed in a base class, and subclasses can inherit and extend this functionality without duplicating code.

7. Generics (for languages that support them)

-Generics allow developers to write code that can work with different data types. This is especially useful for creating reusable components that are type-agnostic. Generics help avoid duplication by allowing the creation of flexible, reusable code that can handle a variety of data types.

8. Interfaces (for Object-Oriented Languages)

-Interfaces define a contract for classes, specifying a set of methods that must be implemented by any class that implements the interface. Interfaces promote consistency and code reuse by ensuring that classes implementing the same interface adhere to a common set of methods.

Examples of DRY principle

1. Extracting Methods

Extracting methods is a common practice to apply the DRY (Don't Repeat Yourself) principle. It involves taking a block of code that performs a specific task and placing it into a separate method.

Filename: OrderProcessor.java

// Order class representing an order with a price

class Order {

    private double price;

    public Order(double price) {

        this.price = price;

    }

    public double getPrice() {

        return price;

    }

}

// OrderProcessor class for processing orders

public class OrderProcessor {

    public double processOrder(Order order) {

        double discountedPrice = calculateDiscountedPrice(order);

        double totalPrice = applyTax(discountedPrice);

        // Additional processing logic...

        return totalPrice;

    }

    private double calculateDiscountedPrice(Order order) {

        // Calculate discounted price

        double discount = calculateDiscount(order);

        return order.getPrice() - discount;

    }

    private double calculateDiscount(Order order) {

        // Complex logic for calculating discount based on order details

        // ...

        return order.getPrice() * 0.1;  // Example: 10% discount

    }

    private double applyTax(double price) {

        // Complex logic for applying tax

        // ...

        return price * 1.08;  // Example: 8% tax

    }

    // Additional methods...

    public static void main(String[] args) {

        // Example usage

        Order order = new Order(100.0);

        OrderProcessor orderProcessor = new OrderProcessor();

        double totalPrice = orderProcessor.processOrder(order);

        System.out.println("Total Price: $" + totalPrice);

    }

}

Output:

Total Price: $97.2

Explanation

The above example includes the Order class with a getPrice method and the OrderProcessor class with methods for processing orders, calculating discounts, and applying tax. To adhere to the DRY principle, methods are extracted to perform specific tasks. calculateDiscountedPrice now calls calculateDiscount and calculates the discounted price. processOrder becomes cleaner, as it delegates tasks to more focused methods.

2. Using inheritance

Using inheritance is a way to apply the DRY (Don't Repeat Yourself) principle by allowing one class to inherit the properties and methods of another class.

Filename: InheritanceExample.java

// Base class representing a generic shape

class Shape {

    protected int side;

    public Shape(int side) {

        this.side = side;

    }

    public int calculateArea() {

        return 0; // Default implementation for generic shape

    }

}

// Subclass representing a square

class Square extends Shape {

    public Square(int side) {

        super(side);

    }

    // Override the calculateArea method for a square

    @Override

    public int calculateArea() {

        return side * side;

    }

}

// Subclass representing a rectangle

class Rectangle extends Shape {

    protected int length;

    public Rectangle(int side, int length) {

        super(side);

        this.length = length;

    }

    // Override the calculateArea method for a rectangle

    @Override

    public int calculateArea() {

        return side * length;

    }

}

// Main class for testing the inheritance example

public class InheritanceExample {

    public static void main(String[] args) {

        // Create instances of Square and Rectangle

        Square square = new Square(5);

        Rectangle rectangle = new Rectangle(4, 6);

        // Calculate and display the area of each shape

        System.out.println("Area of Square: " + square.calculateArea());

        System.out.println("Area of Rectangle: " + rectangle.calculateArea());

    }

}

Output:

Area of Square: 25

Area of Rectangle: 24

Explanation

The InheritanceExample class contains the main method for testing the inheritance example. It creates instances of both Square and Rectangle and calls the calculateArea method on each to demonstrate polymorphism, where the appropriate method is called based on the actual type of the object.

3. Utilizing Interfaces

Interfaces in Java provide a way to achieve abstraction and define a contract that classes must adhere to. They are a powerful tool for promoting code flexibility, allowing different classes to share common behavior without requiring a common base class.

Filename: InterfaceExample.java

// Interface defining the contract for loggable objects

interface Loggable {

    void log(String message);

}

// Class implementing the Loggable interface for console logging

class ConsoleLogger implements Loggable {

    @Override

    public void log(String message) {

        System.out.println("Console Log: " + message);

    }

}

// Class implementing the Loggable interface for file logging

class FileLogger implements Loggable {

    @Override

    public void log(String message) {

        // Code for logging to a file

        System.out.println("File Log: " + message);

    }

}

// Main class for testing the use of interfaces

public class InterfaceExample {

    public static void main(String[] args) {

        // Create instances of ConsoleLogger and FileLogger

        Loggable consoleLogger = new ConsoleLogger();

        Loggable fileLogger = new FileLogger();

        // Log messages using the log method from the Loggable interface

        consoleLogger.log("This message will be logged to the console.");

        fileLogger.log("This message will be logged to a file.");

    }

}

Output:

Console Log: This message will be logged to the console.

File Log: This message will be logged to a file.

Explanation

The InterfaceExample class contains the main method for testing the use of interfaces. Instances of ConsoleLogger and FileLogger are created and assigned to a variable of the Loggable type. This demonstrates polymorphism, where objects can be treated as instances of their interface. The log method from the Loggable interface is then called on both objects, and each class provides its specific implementation.

4. Using Generics

Generics in Java provide a way to create classes, interfaces, and methods that operate on different types while maintaining type safety. They allow you to write code that can be reused with different data types without sacrificing type checking at compile time.

Filename: GenericsExample.java

// Generic class representing a Box that can hold any type of content

class Box<T> {

    private T content;

    // Constructor to initialize the content of the box

    public Box(T content) {

        this.content = content;

    }

    // Getter method to retrieve the content of the box

    public T getContent() {

        return content;

    }

    // Setter method to update the content of the box

    public void setContent(T content) {

        this.content = content;

    }

}

// Main class for testing the use of generics

public class GenericsExample {

    public static void main(String[] args) {

        // Create a Box for holding an Integer

        Box<Integer> integerBox = new Box<>(42);

        // Create a Box for holding a String

        Box<String> stringBox = new Box<>("Hello, Generics!");

        // Get and display the content of each box

        System.out.println("Integer Box Content: " + integerBox.getContent());

        System.out.println("String Box Content: " + stringBox.getContent());

        // Update the content of the boxes

        integerBox.setContent(100);

        stringBox.setContent("Updated Content");

        // Display the updated content

        System.out.println("Updated Integer Box Content: " + integerBox.getContent());

        System.out.println("Updated String Box Content: " + stringBox.getContent());

    }

}

Output:

Integer Box Content: 42

String Box Content: Hello, Generics!

Updated Integer Box Content: 100

Updated String Box Content: Updated Content

Explanation

The Box class is a generic class that can hold any type of content. The generic type parameter T is a placeholder for the actual type that will be specified when creating an instance of the class. The class has a private field content of type T, a constructor to initialize the content, and getter and setter methods to retrieve and update the content.

5. Using Constants

Using constants is a good practice to avoid hardcoding values throughout your code, and it aligns with the DRY (Don't Repeat Yourself) principle. Constants centralize values that might be reused in multiple places, making the code more maintainable and less error-prone.

Filename: ConstantsUsageExample.java

public class ConstantsUsageExample {

    // Constants for geometric calculations

    public static final double PI = 3.14159;

    public static final int RECTANGLE_LENGTH = 5;

    public static final int RECTANGLE_WIDTH = 3;

    public static void main(String[] args) {

        // Calculate and display the area and perimeter of a rectangle

        double rectangleArea = RECTANGLE_LENGTH * RECTANGLE_WIDTH;

        double rectanglePerimeter = 2 * (RECTANGLE_LENGTH + RECTANGLE_WIDTH);

        System.out.println("Rectangle Area: " + rectangleArea);

        System.out.println("Rectangle Perimeter: " + rectanglePerimeter);

        // Calculate and display the circumference of a circle

        int circleRadius = 4;

        double circleCircumference = 2 * PI * circleRadius;

        System.out.println("Circle Circumference: " + circleCircumference);

    }

}

Output:

Rectangle Area: 15.0

Rectangle Perimeter: 16.0

Circle Circumference: 25.13272

Explanation

In this example, constants are used directly in calculations without the need for helper methods. This approach centralizes important values, such as dimensions and mathematical constants, avoiding repetition and promoting code clarity.

6. Utilizing Helper Methods

Utilizing helper methods is a common practice in software development to encapsulate and modularize specific functionalities. It aligns with the DRY (Don't Repeat Yourself) principle by avoiding redundancy and promoting code reuse.

Filename: HelperMethodsExample.java

public class HelperMethodsExample {

    // Helper method for calculating the area of a rectangle

    public static double calculateRectangleArea(double length, double width) {

        return length * width;

    }

    // Helper method for calculating the perimeter of a rectangle

    public static double calculateRectanglePerimeter(double length, double width) {

        return 2 * (length + width);

    }

    // Helper method for checking if a number is even

    public static boolean isEven(int number) {

        return number % 2 == 0;

    }

    // Helper method for checking if a number is odd

    public static boolean isOdd(int number) {

        return number % 2 != 0;

    }

    // Helper method for converting Fahrenheit to Celsius

    public static double fahrenheitToCelsius(double fahrenheit) {

        return (fahrenheit - 32) * 5 / 9;

    }

    // Helper method for converting Celsius to Fahrenheit

    public static double celsiusToFahrenheit(double celsius) {

        return (celsius * 9 / 5) + 32;

    }

    // Main method for testing helper methods

    public static void main(String[] args) {

        testRectangleCalculations();

        testEvenOddCheck();

        testTemperatureConversions();

    }

    // Helper method to test rectangle calculations

    private static void testRectangleCalculations() {

        double length = 5.0;

        double width = 3.0;

        double area = calculateRectangleArea(length, width);

        double perimeter = calculateRectanglePerimeter(length, width);

        System.out.println("Rectangle Area: " + area);

        System.out.println("Rectangle Perimeter: " + perimeter);

        System.out.println();

    }

    // Helper method to test even/odd check

    private static void testEvenOddCheck() {

        int number1 = 10;

        int number2 = 15;

        System.out.println(number1 + " is even: " + isEven(number1));

        System.out.println(number2 + " is odd: " + isOdd(number2));

        System.out.println();

    }

    // Helper method to test temperature conversions

    private static void testTemperatureConversions() {

        double fahrenheitTemp = 68.0;

        double celsiusTemp = 20.0;

        System.out.println(fahrenheitTemp + " Fahrenheit to Celsius: " + fahrenheitToCelsius(fahrenheitTemp));

        System.out.println(celsiusTemp + " Celsius to Fahrenheit: " + celsiusToFahrenheit(celsiusTemp));

    }

}

Output:

Rectangle Area: 15.0

Rectangle Perimeter: 16.0

10 is even: true

15 is odd: true

68.0 Fahrenheit to Celsius: 20.0

20.0 Celsius to Fahrenheit: 68.0

Explanation

The main method serves as a testing ground for the helper methods, demonstrating their use in calculating rectangle properties, checking even/odd numbers, and performing temperature conversions.

Conclusion

In summary, the DRY principle emphasizes the importance of avoiding code duplication by promoting modularity, abstraction, and encapsulation. By adhering to this principle, developers can create more maintainable, readable, and extensible code.