Module 2: Core Java & OOP Principles, covering syntax mastery and object-oriented design.
2.1 Java Basics
1. Detailed Explanations
Data Types (Primitives vs. Wrappers):
o Primitives (int, boolean, double): These store actual values directly in the
Stack memory. They are lightweight and fast.
o Wrapper Classes (Integer, Boolean, Double): These are Objects that "wrap"
primitives so they can be stored in the Heap. This is necessary because Java
Collections (like ArrayList) only work with Objects, not primitives.
o Autoboxing/Unboxing: Java automatically converts between the two (e.g., int $\
leftrightarrow$ Integer).
String Handling (The Immutability Trap):
o String: Strings in Java are immutable. If you do s = s + " World", you aren't
changing the original string; you are creating a brand new object in memory. This
is inefficient in loops.
o StringBuilder/StringBuffer: These are mutable. You can append or modify
characters without creating new objects. StringBuilder is faster (non-thread-
safe), while StringBuffer is synchronized.
Demo 1: The String Performance Test
Objective: Prove why StringBuilder is essential for loops.
Java
public class StringDemo {
public static void main(String[] args) {
// INEFFICIENT: Creates 1000 objects in memory
String str = "";
long start = [Link]();
for (int i = 0; i < 1000; i++) {
str += i;
}
[Link]("String time: " + ([Link]() - start));
// EFFICIENT: Modifies 1 object
StringBuilder sb = new StringBuilder();
start = [Link]();
for (int i = 0; i < 1000; i++) {
[Link](i);
}
[Link]("StringBuilder time: " + ([Link]() -
start));
}
}
2.2 OOP Pillars
1. Detailed Explanations
Encapsulation: "Data Hiding." Restricting direct access to fields using private and
providing controlled access via public Getters/Setters.
Inheritance: Acquiring properties of a parent class using extends. Java supports single
inheritance (a class can only extend one parent) but can implement multiple interfaces.
Polymorphism:
o Compile-time (Overloading): Same method name, different parameters (e.g.,
print(int i) vs print(String s)).
o Runtime (Overriding): Subclass provides a specific implementation of a parent
method. The @Override annotation ensures compile-time safety.
Abstraction:
o Abstract Class: Can have partial implementation (some logic, some abstract
methods).
o Interface: Pure abstraction (mostly). Defines a contract of what needs to be done.
Exercise 1: OOP Lab - Library Management System
This exercise is explicitly recommended in your course outline.
Task: Design a system using Interfaces for Book and User types.
Requirement: Create a generic Lendable interface.
Solution:
Java
// 1. Abstraction (The Contract)
interface Lendable {
void checkout(String userName);
void returnItem();
}
// 2. Encapsulation (Private fields)
class Book implements Lendable {
private String title;
private boolean isAvailable;
public Book(String title) {
[Link] = title;
[Link] = true;
}
// 3. Polymorphism (Overriding interface methods)
@Override
public void checkout(String userName) {
if (isAvailable) {
isAvailable = false;
[Link]("Book '" + title + "' checked out to " +
userName);
} else {
[Link]("Sorry, '" + title + "' is currently
unavailable.");
}
}
@Override
public void returnItem() {
isAvailable = true;
[Link]("Book '" + title + "' has been returned.");
}
}
public class LibrarySystem {
public static void main(String[] args) {
Lendable myBook = new Book("Java Mastery");
[Link]("Alice"); // Success
[Link]("Bob"); // Fail (Already out)
[Link](); // Return
}
}
2.3 Interfaces & Functional Interfaces
1. Detailed Explanations
Modern Interfaces (Java 8+): Interfaces can now contain default methods (methods
with a body) and static methods. This allows developers to add new methods to
interfaces without breaking existing classes that implement them.
Functional Interfaces: An interface with exactly one abstract method. They are the
basis for Lambda Expressions.
o Predicate<T>: Takes an argument, returns boolean (e.g., checking if age > 18).
o Consumer<T>: Takes an argument, returns nothing (e.g., printing a value).
o Supplier<T>: Takes nothing, returns a value (e.g., generating a random ID).
o Function<T, R>: Takes type T, returns type R (e.g., converting String to
Integer).
Demo 2: Functional Interfaces in Action
Java
import [Link];
import [Link];
public class FunctionalDemo {
public static void main(String[] args) {
// Predicate: Logic to check a condition
Predicate<Integer> isAdult = age -> age >= 18;
// Consumer: Logic to perform an action
Consumer<String> greeter = name -> [Link]("Hello, " +
name);
if ([Link](20)) {
[Link]("User");
}
}
}
2.4 Exception Handling
1. Detailed Explanations
Hierarchy:
o Throwable is the root.
o Error: Serious system problems (e.g., OutOfMemoryError) that applications
should not try to catch.
o Exception: Problems that an application might want to catch.
Checked Exceptions: Compile-time check (e.g., IOException). Must be
handled with try-catch or declared with throws.
Unchecked Exceptions (Runtime): Logic errors (e.g.,
NullPointerException).
Try-With-Resources: A modern syntax that automatically closes resources (like files or
database connections) when the block finishes, preventing memory leaks.
Exercise 2: Custom Exception
Task: Create a banking program that throws a custom InsufficientFundsException if a
withdrawal is too large.
Solution:
Java
// 1. Define Custom Exception
class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}
class BankAccount {
private double balance;
public BankAccount(double balance) {
[Link] = balance;
}
// 2. Declare that this method might throw the exception
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Need " + amount + " but only
have " + balance);
}
balance -= amount;
[Link]("Withdrew " + amount + ". Remaining: " + balance);
}
}
public class ExceptionLab {
public static void main(String[] args) {
BankAccount account = new BankAccount(100.00);
try {
[Link](150.00); // This will fail
} catch (InsufficientFundsException e) {
// 3. Handle the exception gracefully
[Link]("Transaction Failed: " + [Link]());
}
}
}