How has composition vs inheritance changed in recent Java versions?

In recent Java versions, the conversation around composition versus inheritance has evolved significantly, with a stronger emphasis on composition as a more flexible and maintainable approach. While inheritance has traditionally been a cornerstone of object-oriented programming, composition allows for greater modularity, reducing the tight coupling associated with class hierarchies. This shift is partly due to the introduction of features like interfaces with default methods in Java 8, which enable more dynamic and flexible design patterns.

Example of Composition vs Inheritance

// Using Inheritance class Animal { public void sound() { System.out.println("Animal sound"); } } class Dog extends Animal { @Override public void sound() { System.out.println("Bark"); } } // Using Composition class BarkBehavior { public void makeSound() { System.out.println("Bark"); } } class Dog { private BarkBehavior barkBehavior; public Dog(BarkBehavior barkBehavior) { this.barkBehavior = barkBehavior; } public void performSound() { barkBehavior.makeSound(); } } // Usage Dog dog = new Dog(new BarkBehavior()); dog.performSound(); // Outputs: Bark

composition inheritance Java object-oriented programming interfaces Java 8 design patterns