Basic Level
1. Palindrome Check
EasyWrite a program to check if a given string is a palindrome (reads same forwards and backwards).
View Solution
public class Palindrome {
public static boolean isPalindrome(String str) {
str = str.toLowerCase().replaceAll("[^a-z0-9]", "");
int left = 0, right = str.length() - 1;
while (left < right) {
if (str.charAt(left++) != str.charAt(right--)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(isPalindrome("Madam")); // true
System.out.println(isPalindrome("Hello")); // false
}
}
2. Factorial Calculation
EasyWrite a program to calculate factorial of a number using both iteration and recursion.
View Solution
public class Factorial {
// Iterative approach
public static long factorialIterative(int n) {
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// Recursive approach
public static long factorialRecursive(int n) {
if (n <= 1) return 1;
return n * factorialRecursive(n - 1);
}
public static void main(String[] args) {
System.out.println(factorialIterative(5)); // 120
System.out.println(factorialRecursive(5)); // 120
}
}
3. Prime Number Check
EasyWrite a method to check if a number is prime.
View Solution
public class PrimeCheck {
public static boolean isPrime(int n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
for (int i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2) == 0) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(isPrime(17)); // true
System.out.println(isPrime(20)); // false
}
}
4. Reverse an Array
EasyWrite a program to reverse an array in-place.
View Solution
import java.util.Arrays;
public class ReverseArray {
public static void reverse(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int temp = arr[left];
arr[left++] = arr[right];
arr[right--] = temp;
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
reverse(arr);
System.out.println(Arrays.toString(arr)); // [5, 4, 3, 2, 1]
}
}
5. Fibonacci Series
EasyGenerate first N Fibonacci numbers.
View Solution
public class Fibonacci {
public static void printFibonacci(int n) {
long a = 0, b = 1;
for (int i = 0; i < n; i++) {
System.out.print(a + " ");
long next = a + b;
a = b;
b = next;
}
}
public static void main(String[] args) {
printFibonacci(10); // 0 1 1 2 3 5 8 13 21 34
}
}
Intermediate Level
5. Two Sum Problem
EasyGiven an array of integers and a target sum, find two numbers that add up to the target.
View Solution
import java.util.*;
public class TwoSum {
public static int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] {map.get(complement), i};
}
map.put(nums[i], i);
}
return new int[] {};
}
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
int[] result = twoSum(nums, 9);
System.out.println("Indices: " + Arrays.toString(result)); // [0, 1]
}
}
6. Find Missing Number
EasyGiven an array containing n-1 numbers taken from 1 to n, find the missing number.
View Solution
public class MissingNumber {
public static int findMissing(int[] arr, int n) {
// Sum of first n natural numbers: n*(n+1)/2
int expectedSum = n * (n + 1) / 2;
int actualSum = 0;
for (int num : arr) {
actualSum += num;
}
return expectedSum - actualSum;
}
public static void main(String[] args) {
int[] arr = {1, 2, 4, 5, 6};
System.out.println("Missing: " + findMissing(arr, 6)); // 3
}
}
7. Second Largest Element
EasyFind the second largest element in an array without sorting.
View Solution
public class SecondLargest {
public static int findSecondLargest(int[] arr) {
if (arr.length < 2) return -1;
int largest = Integer.MIN_VALUE;
int secondLargest = Integer.MIN_VALUE;
for (int num : arr) {
if (num > largest) {
secondLargest = largest;
largest = num;
} else if (num > secondLargest && num != largest) {
secondLargest = num;
}
}
return secondLargest;
}
public static void main(String[] args) {
int[] arr = {12, 35, 1, 10, 34, 1};
System.out.println("Second largest: " + findSecondLargest(arr)); // 34
}
}
8. Count Vowels and Consonants
EasyWrite a program to count vowels and consonants in a given string.
View Solution
public class VowelConsonantCounter {
public static void countVowelsConsonants(String str) {
str = str.toLowerCase();
int vowels = 0, consonants = 0;
for (char ch : str.toCharArray()) {
if (Character.isLetter(ch)) {
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
vowels++;
} else {
consonants++;
}
}
}
System.out.println("Vowels: " + vowels + ", Consonants: " + consonants);
}
public static void main(String[] args) {
countVowelsConsonants("Hello World"); // Vowels: 3, Consonants: 7
}
}
9. Remove Duplicates from Array
EasyRemove duplicate elements from a sorted array in-place.
View Solution
import java.util.Arrays;
public class RemoveDuplicates {
public static int removeDuplicates(int[] arr) {
if (arr.length == 0) return 0;
int j = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] != arr[j]) {
j++;
arr[j] = arr[i];
}
}
return j + 1;
}
public static void main(String[] args) {
int[] arr = {1, 1, 2, 2, 3, 4, 4};
int newLength = removeDuplicates(arr);
System.out.println("New length: " + newLength);
System.out.println(Arrays.toString(Arrays.copyOf(arr, newLength)));
}
}
10. Anagram Check
EasyCheck if two strings are anagrams of each other.
View Solution
import java.util.Arrays;
public class AnagramCheck {
public static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) return false;
char[] arr1 = s1.toLowerCase().toCharArray();
char[] arr2 = s2.toLowerCase().toCharArray();
Arrays.sort(arr1);
Arrays.sort(arr2);
return Arrays.equals(arr1, arr2);
}
public static void main(String[] args) {
System.out.println(isAnagram("listen", "silent")); // true
System.out.println(isAnagram("hello", "world")); // false
}
}
Intermediate Level
11. Find Duplicates in Array
MediumFind all duplicate elements in an array using different approaches.
View Solution
import java.util.*;
public class FindDuplicates {
public static Set<Integer> findDuplicates(int[] arr) {
Set<Integer> seen = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int num : arr) {
if (!seen.add(num)) {
duplicates.add(num);
}
}
return duplicates;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 2, 4, 3, 5};
System.out.println(findDuplicates(arr)); // [2, 3]
}
}
12. Custom Exception
MediumCreate a custom exception for invalid age and use it in a Person class.
View Solution
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
class Person {
private String name;
private int age;
public void setAge(int age) throws InvalidAgeException {
if (age < 0 || age > 150) {
throw new InvalidAgeException("Age must be between 0 and 150");
}
this.age = age;
}
}
public class CustomExceptionDemo {
public static void main(String[] args) {
Person p = new Person();
try {
p.setAge(-5);
} catch (InvalidAgeException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
13. Producer-Consumer with Threads
MediumImplement producer-consumer pattern using wait/notify.
View Solution
import java.util.LinkedList;
import java.util.Queue;
class Buffer {
private Queue<Integer> queue = new LinkedList<>();
private int capacity = 5;
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == capacity) {
wait();
}
queue.add(item);
System.out.println("Produced: " + item);
notifyAll();
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
int item = queue.poll();
System.out.println("Consumed: " + item);
notifyAll();
return item;
}
}
public class ProducerConsumer {
public static void main(String[] args) {
Buffer buffer = new Buffer();
Thread producer = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try { buffer.produce(i); }
catch (InterruptedException e) { e.printStackTrace(); }
}
});
Thread consumer = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try { buffer.consume(); }
catch (InterruptedException e) { e.printStackTrace(); }
}
});
producer.start();
consumer.start();
}
}
9. Stream API - Word Frequency
MediumCount word frequency in a list of strings using Stream API.
View Solution
import java.util.*;
import java.util.stream.*;
public class WordFrequency {
public static void main(String[] args) {
List<String> words = Arrays.asList(
"apple", "banana", "apple", "orange",
"banana", "apple"
);
Map<String, Long> frequency = words.stream()
.collect(Collectors.groupingBy(
word -> word,
Collectors.counting()
));
System.out.println(frequency);
// {orange=1, banana=2, apple=3}
// Find most frequent word
String mostFrequent = frequency.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("");
System.out.println("Most frequent: " + mostFrequent);
}
}
10. Comparable and Comparator
MediumCreate a Student class with multiple sorting options.
View Solution
import java.util.*;
class Student implements Comparable<Student> {
String name;
int age;
double gpa;
Student(String name, int age, double gpa) {
this.name = name;
this.age = age;
this.gpa = gpa;
}
@Override
public int compareTo(Student other) {
return this.name.compareTo(other.name);
}
@Override
public String toString() {
return name + "(" + age + ", " + gpa + ")";
}
}
public class SortingDemo {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("Charlie", 20, 3.5));
students.add(new Student("Alice", 22, 3.8));
students.add(new Student("Bob", 21, 3.2));
// Natural ordering (by name)
Collections.sort(students);
System.out.println("By name: " + students);
// By age using Comparator
students.sort(Comparator.comparingInt(s -> s.age));
System.out.println("By age: " + students);
// By GPA descending
students.sort(Comparator.comparingDouble((Student s) -> s.gpa).reversed());
System.out.println("By GPA (desc): " + students);
}
}
Advanced Level
11. LRU Cache Implementation
HardImplement a Least Recently Used (LRU) cache using LinkedHashMap.
View Solution
import java.util.*;
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true); // accessOrder=true
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
public class LRUCacheDemo {
public static void main(String[] args) {
LRUCache<Integer, String> cache = new LRUCache<>(3);
cache.put(1, "One");
cache.put(2, "Two");
cache.put(3, "Three");
System.out.println(cache); // {1=One, 2=Two, 3=Three}
cache.get(1); // Access 1
cache.put(4, "Four"); // Evicts 2 (least recently used)
System.out.println(cache); // {3=Three, 1=One, 4=Four}
}
}
12. Generic Stack Implementation
HardImplement a generic stack with push, pop, peek, and isEmpty operations.
View Solution
import java.util.ArrayList;
import java.util.EmptyStackException;
class GenericStack<T> {
private ArrayList<T> elements = new ArrayList<>();
public void push(T item) {
elements.add(item);
}
public T pop() {
if (isEmpty()) {
throw new EmptyStackException();
}
return elements.remove(elements.size() - 1);
}
public T peek() {
if (isEmpty()) {
throw new EmptyStackException();
}
return elements.get(elements.size() - 1);
}
public boolean isEmpty() {
return elements.isEmpty();
}
public int size() {
return elements.size();
}
}
public class GenericStackDemo {
public static void main(String[] args) {
GenericStack<String> stack = new GenericStack<>();
stack.push("A");
stack.push("B");
stack.push("C");
System.out.println("Peek: " + stack.peek()); // C
System.out.println("Pop: " + stack.pop()); // C
System.out.println("Size: " + stack.size()); // 2
}
}
13. File Copy with Streams
HardCopy a file using buffered streams with proper exception handling.
View Solution
import java.io.*;
public class FileCopy {
public static void copyFile(String source, String dest) {
try (
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(dest))
) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
System.out.println("File copied successfully");
} catch (FileNotFoundException e) {
System.err.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.err.println("IO error: " + e.getMessage());
}
}
public static void main(String[] args) {
copyFile("source.txt", "destination.txt");
}
}
14. Thread-Safe Singleton
HardImplement a thread-safe singleton pattern using double-checked locking.
View Solution
public class Singleton {
private static volatile Singleton instance;
private String data;
private Singleton(String data) {
this.data = data;
}
public static Singleton getInstance(String data) {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(data);
}
}
}
return instance;
}
public String getData() {
return data;
}
}
// Alternative: Bill Pugh Singleton (preferred)
class BillPughSingleton {
private BillPughSingleton() {}
private static class Holder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return Holder.INSTANCE;
}
}
15. Stream Parallel Processing
HardUse parallel streams to process large data efficiently.
View Solution
import java.util.*;
import java.util.stream.*;
public class ParallelStreamDemo {
public static void main(String[] args) {
List<Integer> numbers = IntStream.rangeClosed(1, 1000000)
.boxed()
.collect(Collectors.toList());
// Sequential sum
long start = System.currentTimeMillis();
long seqSum = numbers.stream()
.mapToLong(Integer::longValue)
.sum();
long seqTime = System.currentTimeMillis() - start;
// Parallel sum
start = System.currentTimeMillis();
long parSum = numbers.parallelStream()
.mapToLong(Integer::longValue)
.sum();
long parTime = System.currentTimeMillis() - start;
System.out.println("Sequential: " + seqSum + " in " + seqTime + "ms");
System.out.println("Parallel: " + parSum + " in " + parTime + "ms");
// Parallel filtering and mapping
List<Integer> evenSquares = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.limit(100)
.collect(Collectors.toList());
}
}
More Practice Problems
16. Second Largest Element in Array
EasyFind the second largest element in an array without sorting.
View Solution
public class SecondLargest {
public static int findSecondLargest(int[] arr) {
if (arr.length < 2) throw new IllegalArgumentException("Need at least 2 elements");
int first = Integer.MIN_VALUE, second = Integer.MIN_VALUE;
for (int num : arr) {
if (num > first) {
second = first;
first = num;
} else if (num > second && num != first) {
second = num;
}
}
return second;
}
public static void main(String[] args) {
int[] arr = {12, 35, 1, 10, 34, 1};
System.out.println("Second largest: " + findSecondLargest(arr)); // 34
}
}
17. Count Vowels and Consonants
EasyCount the number of vowels and consonants in a given string.
View Solution
public class VowelConsonant {
public static void count(String str) {
str = str.toLowerCase();
int vowels = 0, consonants = 0;
for (char c : str.toCharArray()) {
if (c >= 'a' && c <= 'z') {
if ("aeiou".indexOf(c) != -1) {
vowels++;
} else {
consonants++;
}
}
}
System.out.println("Vowels: " + vowels + ", Consonants: " + consonants);
}
public static void main(String[] args) {
count("Hello World"); // Vowels: 3, Consonants: 7
}
}
18. Armstrong Number Check
EasyCheck if a number is an Armstrong number (sum of cubes of digits equals the number).
View Solution
public class Armstrong {
public static boolean isArmstrong(int num) {
int original = num;
int digits = String.valueOf(num).length();
int sum = 0;
while (num > 0) {
int digit = num % 10;
sum += Math.pow(digit, digits);
num /= 10;
}
return sum == original;
}
public static void main(String[] args) {
System.out.println(isArmstrong(153)); // true (1^3 + 5^3 + 3^3 = 153)
System.out.println(isArmstrong(370)); // true
System.out.println(isArmstrong(123)); // false
}
}
19. GCD and LCM
EasyFind GCD (Greatest Common Divisor) and LCM (Least Common Multiple) of two numbers.
View Solution
public class GcdLcm {
public static int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
public static int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
public static void main(String[] args) {
System.out.println("GCD of 12, 18: " + gcd(12, 18)); // 6
System.out.println("LCM of 12, 18: " + lcm(12, 18)); // 36
}
}
20. Matrix Addition
EasyAdd two matrices and display the result.
View Solution
public class MatrixAddition {
public static int[][] add(int[][] a, int[][] b) {
int rows = a.length, cols = a[0].length;
int[][] result = new int[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
result[i][j] = a[i][j] + b[i][j];
}
}
return result;
}
public static void main(String[] args) {
int[][] a = {{1, 2}, {3, 4}};
int[][] b = {{5, 6}, {7, 8}};
int[][] sum = add(a, b);
for (int[] row : sum) {
System.out.println(Arrays.toString(row)); // [6, 8], [10, 12]
}
}
}
21. Binary Search
MediumImplement binary search algorithm for a sorted array.
View Solution
public class BinarySearch {
public static int search(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // Not found
}
public static void main(String[] args) {
int[] arr = {2, 3, 4, 10, 40};
System.out.println("Index of 10: " + search(arr, 10)); // 3
}
}
22. Merge Two Sorted Arrays
MediumMerge two sorted arrays into a single sorted array.
View Solution
public class MergeArrays {
public static int[] merge(int[] a, int[] b) {
int[] result = new int[a.length + b.length];
int i = 0, j = 0, k = 0;
while (i < a.length && j < b.length) {
if (a[i] <= b[j]) {
result[k++] = a[i++];
} else {
result[k++] = b[j++];
}
}
while (i < a.length) result[k++] = a[i++];
while (j < b.length) result[k++] = b[j++];
return result;
}
public static void main(String[] args) {
int[] a = {1, 3, 5};
int[] b = {2, 4, 6};
System.out.println(Arrays.toString(merge(a, b))); // [1, 2, 3, 4, 5, 6]
}
}
23. String Anagram Check
MediumCheck if two strings are anagrams of each other.
View Solution
import java.util.*;
public class AnagramCheck {
public static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) return false;
char[] arr1 = s1.toLowerCase().toCharArray();
char[] arr2 = s2.toLowerCase().toCharArray();
Arrays.sort(arr1);
Arrays.sort(arr2);
return Arrays.equals(arr1, arr2);
}
// Alternative using HashMap
public static boolean isAnagramMap(String s1, String s2) {
if (s1.length() != s2.length()) return false;
Map<Character, Integer> map = new HashMap<>();
for (char c : s1.toLowerCase().toCharArray()) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
for (char c : s2.toLowerCase().toCharArray()) {
if (!map.containsKey(c) || map.get(c) == 0) return false;
map.put(c, map.get(c) - 1);
}
return true;
}
public static void main(String[] args) {
System.out.println(isAnagram("Listen", "Silent")); // true
System.out.println(isAnagram("Hello", "World")); // false
}
}
24. Remove Duplicates from ArrayList
MediumRemove duplicate elements from an ArrayList while preserving order.
View Solution
import java.util.*;
public class RemoveDuplicates {
// Using LinkedHashSet
public static <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
// Using Stream API
public static <T> List<T> removeDuplicatesStream(List<T> list) {
return list.stream()
.distinct()
.collect(Collectors.toList());
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 2, 1, 4));
System.out.println(removeDuplicates(list)); // [1, 2, 3, 4]
}
}
25. Bank Account Class
MediumCreate a BankAccount class with deposit, withdraw, and balance checking functionality.
View Solution
public class BankAccount {
private String accountNumber;
private String holderName;
private double balance;
public BankAccount(String accountNumber, String holderName, double initialBalance) {
this.accountNumber = accountNumber;
this.holderName = holderName;
this.balance = initialBalance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: " + amount);
} else {
System.out.println("Invalid deposit amount");
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrawn: " + amount);
} else {
System.out.println("Insufficient balance or invalid amount");
}
}
public double getBalance() {
return balance;
}
public static void main(String[] args) {
BankAccount acc = new BankAccount("123456", "John", 1000);
acc.deposit(500);
acc.withdraw(200);
System.out.println("Balance: " + acc.getBalance()); // 1300
}
}
26. Quick Sort Implementation
HardImplement the Quick Sort algorithm.
View Solution
public class QuickSort {
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return i + 1;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {10, 7, 8, 9, 1, 5};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr)); // [1, 5, 7, 8, 9, 10]
}
}
27. Linked List Implementation
HardImplement a singly linked list with insert, delete, and display operations.
View Solution
public class LinkedList {
private Node head;
class Node {
int data;
Node next;
Node(int data) { this.data = data; }
}
public void insertAtEnd(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node current = head;
while (current.next != null) {
current = current.next;
}
current.next = newNode;
}
public void insertAtBeginning(int data) {
Node newNode = new Node(data);
newNode.next = head;
head = newNode;
}
public void delete(int key) {
if (head == null) return;
if (head.data == key) {
head = head.next;
return;
}
Node current = head;
while (current.next != null && current.next.data != key) {
current = current.next;
}
if (current.next != null) {
current.next = current.next.next;
}
}
public void display() {
Node current = head;
while (current != null) {
System.out.print(current.data + " -> ");
current = current.next;
}
System.out.println("null");
}
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.insertAtEnd(1);
list.insertAtEnd(2);
list.insertAtEnd(3);
list.insertAtBeginning(0);
list.display(); // 0 -> 1 -> 2 -> 3 -> null
list.delete(2);
list.display(); // 0 -> 1 -> 3 -> null
}
}
28. Binary Tree Traversals
HardImplement inorder, preorder, and postorder traversals of a binary tree.
View Solution
public class BinaryTree {
class Node {
int data;
Node left, right;
Node(int data) { this.data = data; }
}
private Node root;
// Inorder: Left -> Root -> Right
public void inorder(Node node) {
if (node != null) {
inorder(node.left);
System.out.print(node.data + " ");
inorder(node.right);
}
}
// Preorder: Root -> Left -> Right
public void preorder(Node node) {
if (node != null) {
System.out.print(node.data + " ");
preorder(node.left);
preorder(node.right);
}
}
// Postorder: Left -> Right -> Root
public void postorder(Node node) {
if (node != null) {
postorder(node.left);
postorder(node.right);
System.out.print(node.data + " ");
}
}
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.root = tree.new Node(1);
tree.root.left = tree.new Node(2);
tree.root.right = tree.new Node(3);
tree.root.left.left = tree.new Node(4);
tree.root.left.right = tree.new Node(5);
System.out.print("Inorder: ");
tree.inorder(tree.root); // 4 2 5 1 3
System.out.print("\nPreorder: ");
tree.preorder(tree.root); // 1 2 4 5 3
System.out.print("\nPostorder: ");
tree.postorder(tree.root); // 4 5 2 3 1
}
}
29. Student Management System
HardCreate a Student class with CRUD operations using ArrayList.
View Solution
import java.util.*;
class Student {
private int id;
private String name;
private double marks;
public Student(int id, String name, double marks) {
this.id = id;
this.name = name;
this.marks = marks;
}
// Getters and Setters
public int getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getMarks() { return marks; }
public void setMarks(double marks) { this.marks = marks; }
public String toString() {
return "Student[id=" + id + ", name=" + name + ", marks=" + marks + "]";
}
}
public class StudentManagement {
private List<Student> students = new ArrayList<>();
public void addStudent(Student s) {
students.add(s);
}
public Student findById(int id) {
return students.stream()
.filter(s -> s.getId() == id)
.findFirst()
.orElse(null);
}
public void updateStudent(int id, String name, double marks) {
Student s = findById(id);
if (s != null) {
s.setName(name);
s.setMarks(marks);
}
}
public void deleteStudent(int id) {
students.removeIf(s -> s.getId() == id);
}
public void displayAll() {
students.forEach(System.out::println);
}
public static void main(String[] args) {
StudentManagement sm = new StudentManagement();
sm.addStudent(new Student(1, "Alice", 85.5));
sm.addStudent(new Student(2, "Bob", 90.0));
sm.displayAll();
sm.updateStudent(1, "Alice Smith", 88.0);
sm.deleteStudent(2);
System.out.println("After update and delete:");
sm.displayAll();
}
}
30. File Word Counter
MediumRead a file and count occurrences of each word.
View Solution
import java.io.*;
import java.util.*;
public class WordCounter {
public static Map<String, Integer> countWords(String filename) throws IOException {
Map<String, Integer> wordCount = new HashMap<>();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
String[] words = line.toLowerCase().split("\\W+");
for (String word : words) {
if (!word.isEmpty()) {
wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}
}
}
}
return wordCount;
}
public static void main(String[] args) {
try {
Map<String, Integer> counts = countWords("sample.txt");
counts.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(10)
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Exam Practice Questions
These problems are based on actual exam patterns. Practice these for your semester exams.
E1. Method Overriding - Shape and Rectangle
MediumWrite a superclass Shape with method displayArea() and subclass Rectangle implementing method overriding. Compare method overloading vs overriding.
View Solution
// Superclass Shape
class Shape {
public void displayArea() {
System.out.println("Area calculation depends on shape type");
}
// Method Overloading - same name, different parameters
public void displayArea(String shapeName) {
System.out.println("Calculating area for: " + shapeName);
}
}
// Subclass Rectangle - Method Overriding
class Rectangle extends Shape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public void displayArea() {
double area = length * width;
System.out.println("Rectangle Area: " + area);
}
}
// Subclass Circle - Another example of overriding
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void displayArea() {
double area = Math.PI * radius * radius;
System.out.println("Circle Area: " + String.format("%.2f", area));
}
}
public class ShapeDemo {
public static void main(String[] args) {
Shape shape = new Shape();
Rectangle rect = new Rectangle(5.0, 3.0);
Circle circle = new Circle(4.0);
// Method Overriding demonstration
System.out.println("--- Method Overriding ---");
shape.displayArea(); // Parent method
rect.displayArea(); // Overridden in Rectangle
circle.displayArea(); // Overridden in Circle
// Runtime Polymorphism
System.out.println("\n--- Runtime Polymorphism ---");
Shape s1 = new Rectangle(10, 5);
Shape s2 = new Circle(7);
s1.displayArea(); // Calls Rectangle's displayArea()
s2.displayArea(); // Calls Circle's displayArea()
// Method Overloading demonstration
System.out.println("\n--- Method Overloading ---");
shape.displayArea(); // No parameter
shape.displayArea("Triangle"); // With parameter
}
}
/*
OUTPUT:
--- Method Overriding ---
Area calculation depends on shape type
Rectangle Area: 15.0
Circle Area: 50.27
--- Runtime Polymorphism ---
Rectangle Area: 50.0
Circle Area: 153.94
--- Method Overloading ---
Area calculation depends on shape type
Calculating area for: Triangle
KEY DIFFERENCES:
| Overloading | Overriding |
|--------------------------|-------------------------------|
| Same class | Parent-child classes |
| Different parameters | Same signature |
| Compile-time polymorphism| Runtime polymorphism |
| Can change return type | Must be same/covariant return |
*/
E2. Constructor Overloading
MediumCreate a class with at least three constructors demonstrating constructor overloading. Show how constructors are invoked.
View Solution
class Student {
private int rollNo;
private String name;
private double marks;
private String course;
// Constructor 1: Default constructor
public Student() {
this.rollNo = 0;
this.name = "Unknown";
this.marks = 0.0;
this.course = "Not Assigned";
System.out.println("Default constructor called");
}
// Constructor 2: With rollNo and name
public Student(int rollNo, String name) {
this.rollNo = rollNo;
this.name = name;
this.marks = 0.0;
this.course = "Not Assigned";
System.out.println("Constructor with rollNo and name called");
}
// Constructor 3: With rollNo, name, and marks
public Student(int rollNo, String name, double marks) {
this.rollNo = rollNo;
this.name = name;
this.marks = marks;
this.course = "Not Assigned";
System.out.println("Constructor with rollNo, name, marks called");
}
// Constructor 4: With all parameters
public Student(int rollNo, String name, double marks, String course) {
this.rollNo = rollNo;
this.name = name;
this.marks = marks;
this.course = course;
System.out.println("Parameterized constructor with all fields called");
}
// Constructor 5: Copy constructor
public Student(Student other) {
this.rollNo = other.rollNo;
this.name = other.name;
this.marks = other.marks;
this.course = other.course;
System.out.println("Copy constructor called");
}
public void display() {
System.out.println("Roll: " + rollNo + ", Name: " + name +
", Marks: " + marks + ", Course: " + course);
}
}
public class ConstructorOverloadingDemo {
public static void main(String[] args) {
// Invoking different constructors
System.out.println("=== Constructor Invocation Examples ===\n");
// 1. Using default constructor
Student s1 = new Student();
s1.display();
System.out.println();
// 2. Using constructor with 2 parameters
Student s2 = new Student(101, "Alice");
s2.display();
System.out.println();
// 3. Using constructor with 3 parameters
Student s3 = new Student(102, "Bob", 85.5);
s3.display();
System.out.println();
// 4. Using constructor with all parameters
Student s4 = new Student(103, "Charlie", 92.0, "Computer Science");
s4.display();
System.out.println();
// 5. Using copy constructor
Student s5 = new Student(s4);
s5.display();
}
}
/*
OUTPUT:
=== Constructor Invocation Examples ===
Default constructor called
Roll: 0, Name: Unknown, Marks: 0.0, Course: Not Assigned
Constructor with rollNo and name called
Roll: 101, Name: Alice, Marks: 0.0, Course: Not Assigned
Constructor with rollNo, name, marks called
Roll: 102, Name: Bob, Marks: 85.5, Course: Not Assigned
Parameterized constructor with all fields called
Roll: 103, Name: Charlie, Marks: 92.0, Course: Computer Science
Copy constructor called
Roll: 103, Name: Charlie, Marks: 92.0, Course: Computer Science
*/
E3. Multiple Exception Handling with try-catch-finally
MediumWrite a Java program to handle multiple exceptions using try-catch-finally. Include throw and throws keywords.
View Solution
import java.util.Scanner;
public class MultipleExceptionDemo {
// Method using 'throws' keyword
public static int divide(int a, int b) throws ArithmeticException {
if (b == 0) {
// Using 'throw' keyword to explicitly throw exception
throw new ArithmeticException("Cannot divide by zero!");
}
return a / b;
}
public static void main(String[] args) {
Scanner scanner = null;
try {
scanner = new Scanner(System.in);
// Example 1: ArrayIndexOutOfBoundsException
int[] numbers = {10, 20, 30};
System.out.println("Array element at index 1: " + numbers[1]);
// Example 2: ArithmeticException
int result = divide(10, 2);
System.out.println("Division result: " + result);
// Example 3: NumberFormatException
String numStr = "123";
int num = Integer.parseInt(numStr);
System.out.println("Parsed number: " + num);
// Example 4: NullPointerException
String str = "Hello";
System.out.println("String length: " + str.length());
// Uncomment any line below to trigger exception:
// System.out.println(numbers[5]); // ArrayIndexOutOfBoundsException
// divide(10, 0); // ArithmeticException
// Integer.parseInt("abc"); // NumberFormatException
// String s = null; s.length(); // NullPointerException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Error: Array index out of bounds!");
System.out.println("Details: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Error: Arithmetic exception occurred!");
System.out.println("Details: " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("Error: Invalid number format!");
System.out.println("Details: " + e.getMessage());
} catch (NullPointerException e) {
System.out.println("Error: Null pointer exception!");
System.out.println("Details: " + e.getMessage());
} catch (Exception e) {
// Generic catch block for any other exceptions
System.out.println("Error: An unexpected exception occurred!");
System.out.println("Details: " + e.getMessage());
} finally {
// Finally block always executes
System.out.println("\n--- Finally Block ---");
System.out.println("Cleanup operations performed.");
if (scanner != null) {
scanner.close();
System.out.println("Scanner closed.");
}
}
System.out.println("\nProgram continues after exception handling...");
}
}
/*
KEY CONCEPTS:
1. try: Contains code that might throw exceptions
2. catch: Handles specific exception types
3. finally: Always executes (cleanup code)
4. throw: Explicitly throws an exception
5. throws: Declares exceptions a method might throw
OUTPUT (normal execution):
Array element at index 1: 20
Division result: 5
Parsed number: 123
String length: 5
--- Finally Block ---
Cleanup operations performed.
Scanner closed.
Program continues after exception handling...
*/
E4. Multiple Inheritance using Interfaces
MediumDemonstrate why multiple inheritance is not supported in Java with classes and show how interfaces achieve multiple inheritance.
View Solution
/*
WHY MULTIPLE INHERITANCE IS NOT SUPPORTED WITH CLASSES:
If Java allowed:
class A { void show() { print("A"); } }
class B { void show() { print("B"); } }
class C extends A, B { } // NOT ALLOWED
Problem: Which show() would C inherit? This is the "Diamond Problem"
*/
// Interface 1
interface Printable {
void print();
// Default method (Java 8+)
default void defaultPrint() {
System.out.println("Default print from Printable");
}
}
// Interface 2
interface Showable {
void show();
default void defaultShow() {
System.out.println("Default show from Showable");
}
}
// Interface 3 - extends another interface
interface Displayable extends Printable {
void display();
}
// Class implementing multiple interfaces - MULTIPLE INHERITANCE
class Document implements Printable, Showable {
private String content;
public Document(String content) {
this.content = content;
}
@Override
public void print() {
System.out.println("Printing: " + content);
}
@Override
public void show() {
System.out.println("Showing: " + content);
}
}
// Another class implementing Displayable (which extends Printable)
class Report implements Displayable, Showable {
private String title;
public Report(String title) {
this.title = title;
}
@Override
public void print() {
System.out.println("Printing Report: " + title);
}
@Override
public void show() {
System.out.println("Showing Report: " + title);
}
@Override
public void display() {
System.out.println("Displaying Report: " + title);
}
}
public class MultipleInheritanceDemo {
public static void main(String[] args) {
System.out.println("=== Multiple Inheritance via Interfaces ===\n");
// Document implements both Printable and Showable
Document doc = new Document("Hello World");
doc.print();
doc.show();
doc.defaultPrint();
doc.defaultShow();
System.out.println();
// Report implements Displayable (extends Printable) and Showable
Report report = new Report("Annual Report 2024");
report.print();
report.show();
report.display();
System.out.println("\n=== Polymorphism with Interfaces ===\n");
// Interface reference can hold implementing class object
Printable p = new Document("Polymorphic Doc");
p.print();
Showable s = new Report("Polymorphic Report");
s.show();
}
}
/*
OUTPUT:
=== Multiple Inheritance via Interfaces ===
Printing: Hello World
Showing: Hello World
Default print from Printable
Default show from Showable
Printing Report: Annual Report 2024
Showing Report: Annual Report 2024
Displaying Report: Annual Report 2024
=== Polymorphism with Interfaces ===
Polymorphic Doc
Polymorphic Report
KEY POINTS:
1. Java doesn't support multiple inheritance with classes (Diamond Problem)
2. A class can implement multiple interfaces
3. Interfaces provide method signatures (contract)
4. Default methods allow code in interfaces (Java 8+)
5. Interface can extend multiple interfaces
*/
E5. Thread Creation - Thread Class and Runnable Interface
MediumCreate threads using both extending Thread class and implementing Runnable interface. Demonstrate the thread lifecycle.
View Solution
// Method 1: Extending Thread class
class MyThread extends Thread {
private String threadName;
public MyThread(String name) {
this.threadName = name;
}
@Override
public void run() {
System.out.println(threadName + " started (extends Thread)");
for (int i = 1; i <= 5; i++) {
System.out.println(threadName + ": Count " + i);
try {
Thread.sleep(500); // Sleep for 500ms
} catch (InterruptedException e) {
System.out.println(threadName + " interrupted");
}
}
System.out.println(threadName + " finished");
}
}
// Method 2: Implementing Runnable interface
class MyRunnable implements Runnable {
private String threadName;
public MyRunnable(String name) {
this.threadName = name;
}
@Override
public void run() {
System.out.println(threadName + " started (implements Runnable)");
for (int i = 1; i <= 5; i++) {
System.out.println(threadName + ": Count " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println(threadName + " interrupted");
}
}
System.out.println(threadName + " finished");
}
}
public class ThreadCreationDemo {
public static void main(String[] args) {
System.out.println("=== Thread Creation Demo ===\n");
System.out.println("Main thread started");
// Method 1: Using Thread class
MyThread thread1 = new MyThread("Thread-1");
// Method 2: Using Runnable interface
MyRunnable runnable = new MyRunnable("Thread-2");
Thread thread2 = new Thread(runnable);
// Method 3: Using Lambda (Java 8+) - Anonymous Runnable
Thread thread3 = new Thread(() -> {
System.out.println("Thread-3 started (Lambda)");
for (int i = 1; i <= 3; i++) {
System.out.println("Thread-3: Count " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread-3 finished");
});
// Display thread states before starting
System.out.println("\n--- Thread States ---");
System.out.println("Thread-1 state: " + thread1.getState()); // NEW
// Start all threads
System.out.println("\n--- Starting Threads ---");
thread1.start(); // Transitions to RUNNABLE
thread2.start();
thread3.start();
System.out.println("Thread-1 state after start: " + thread1.getState());
// Wait for threads to complete
try {
thread1.join(); // Main waits for thread1
thread2.join(); // Main waits for thread2
thread3.join(); // Main waits for thread3
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\nThread-1 state after completion: " + thread1.getState()); // TERMINATED
System.out.println("Main thread finished");
}
}
/*
THREAD LIFECYCLE STATES:
1. NEW - Thread created but not started
2. RUNNABLE - Thread executing or ready to execute
3. BLOCKED - Waiting to acquire a lock
4. WAITING - Waiting indefinitely for another thread
5. TIMED_WAITING - Waiting for specified time (sleep, wait with timeout)
6. TERMINATED - Thread execution completed
DIFFERENCE: Thread vs Runnable
| Thread Class | Runnable Interface |
|------------------------|------------------------------|
| Extends Thread | Implements Runnable |
| Cannot extend other | Can extend other classes |
| Each thread has object | Single object, multiple threads |
| Less flexible | More flexible (preferred) |
*/
E6. User-Defined Exception
MediumCreate a user-defined exception and demonstrate proper exception handling with custom exceptions.
View Solution
// User-defined exception class
class InsufficientBalanceException extends Exception {
private double balance;
private double amount;
public InsufficientBalanceException(String message) {
super(message);
}
public InsufficientBalanceException(double balance, double amount) {
super("Insufficient balance! Available: " + balance +
", Requested: " + amount);
this.balance = balance;
this.amount = amount;
}
public double getBalance() { return balance; }
public double getAmount() { return amount; }
}
// Another user-defined exception
class InvalidAccountException extends Exception {
public InvalidAccountException(String message) {
super(message);
}
}
// Bank Account class using custom exceptions
class BankAccount {
private String accountNumber;
private double balance;
public BankAccount(String accountNumber, double initialBalance)
throws InvalidAccountException {
if (accountNumber == null || accountNumber.length() < 5) {
throw new InvalidAccountException(
"Account number must be at least 5 characters");
}
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
public void withdraw(double amount) throws InsufficientBalanceException {
if (amount > balance) {
throw new InsufficientBalanceException(balance, amount);
}
balance -= amount;
System.out.println("Withdrawn: " + amount + ", New Balance: " + balance);
}
public void deposit(double amount) {
balance += amount;
System.out.println("Deposited: " + amount + ", New Balance: " + balance);
}
public double getBalance() { return balance; }
}
public class UserDefinedExceptionDemo {
public static void main(String[] args) {
System.out.println("=== User-Defined Exception Demo ===\n");
// Test 1: Invalid Account Exception
System.out.println("Test 1: Creating account with invalid number");
try {
BankAccount invalidAcc = new BankAccount("123", 1000);
} catch (InvalidAccountException e) {
System.out.println("Exception caught: " + e.getMessage());
}
System.out.println();
// Test 2: Valid account operations
System.out.println("Test 2: Valid account operations");
try {
BankAccount account = new BankAccount("ACC001", 5000);
System.out.println("Account created. Balance: " + account.getBalance());
account.deposit(2000);
account.withdraw(3000);
// This will throw InsufficientBalanceException
System.out.println("\nAttempting to withdraw 10000...");
account.withdraw(10000);
} catch (InvalidAccountException e) {
System.out.println("Account Error: " + e.getMessage());
} catch (InsufficientBalanceException e) {
System.out.println("Transaction Error: " + e.getMessage());
System.out.println("Available Balance: " + e.getBalance());
System.out.println("Requested Amount: " + e.getAmount());
} finally {
System.out.println("\nTransaction processing completed.");
}
}
}
/*
OUTPUT:
=== User-Defined Exception Demo ===
Test 1: Creating account with invalid number
Exception caught: Account number must be at least 5 characters
Test 2: Valid account operations
Account created. Balance: 5000.0
Deposited: 2000.0, New Balance: 7000.0
Withdrawn: 3000.0, New Balance: 4000.0
Attempting to withdraw 10000...
Transaction Error: Insufficient balance! Available: 4000.0, Requested: 10000.0
Available Balance: 4000.0
Requested Amount: 10000.0
Transaction processing completed.
KEY POINTS:
1. Extend Exception for checked exceptions
2. Extend RuntimeException for unchecked exceptions
3. Call super(message) in constructor
4. Can add custom fields and methods
*/
E7. Functional Interface with Lambda Expression
MediumDefine a functional interface and implement it using lambda expressions. Show built-in functional interfaces.
View Solution
import java.util.*;
import java.util.function.*;
// Custom Functional Interface
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// Can have default methods
default void printResult(int a, int b) {
System.out.println("Result: " + calculate(a, b));
}
}
// Another Functional Interface
@FunctionalInterface
interface Greeting {
String greet(String name);
}
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
System.out.println("=== Custom Functional Interface ===\n");
// Lambda implementations of Calculator
Calculator add = (a, b) -> a + b;
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
Calculator divide = (a, b) -> b != 0 ? a / b : 0;
System.out.println("10 + 5 = " + add.calculate(10, 5));
System.out.println("10 - 5 = " + subtract.calculate(10, 5));
System.out.println("10 * 5 = " + multiply.calculate(10, 5));
System.out.println("10 / 5 = " + divide.calculate(10, 5));
// Using default method
System.out.print("Using default method: ");
add.printResult(20, 30);
// Greeting functional interface
Greeting formalGreeting = name -> "Good morning, " + name + "!";
Greeting casualGreeting = name -> "Hey " + name + "!";
System.out.println("\n" + formalGreeting.greet("Mr. Smith"));
System.out.println(casualGreeting.greet("John"));
// Built-in Functional Interfaces
System.out.println("\n=== Built-in Functional Interfaces ===\n");
// 1. Predicate - takes T, returns boolean
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println("Is 4 even? " + isEven.test(4));
System.out.println("Is 7 even? " + isEven.test(7));
// 2. Function - takes T, returns R
Function<String, Integer> strLength = s -> s.length();
System.out.println("Length of 'Hello': " + strLength.apply("Hello"));
// 3. Consumer - takes T, returns nothing
Consumer<String> printer = s -> System.out.println("Printing: " + s);
printer.accept("Consumer demo");
// 4. Supplier - takes nothing, returns T
Supplier<Double> randomSupplier = () -> Math.random();
System.out.println("Random number: " + randomSupplier.get());
// 5. BiFunction - takes T and U, returns R
BiFunction<Integer, Integer, Integer> max = (a, b) -> a > b ? a : b;
System.out.println("Max of 10, 20: " + max.apply(10, 20));
// Using with Collections
System.out.println("\n=== Lambda with Collections ===\n");
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// forEach with Consumer
System.out.print("Names: ");
names.forEach(name -> System.out.print(name + " "));
// filter with Predicate
System.out.println("\nNames starting with 'A' or 'C':");
names.stream()
.filter(n -> n.startsWith("A") || n.startsWith("C"))
.forEach(System.out::println);
}
}
/*
OUTPUT:
=== Custom Functional Interface ===
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2
Using default method: Result: 50
Good morning, Mr. Smith!
Hey John!
=== Built-in Functional Interfaces ===
Is 4 even? true
Is 7 even? false
Length of 'Hello': 5
Printing: Consumer demo
Random number: 0.xyz...
Max of 10, 20: 20
=== Lambda with Collections ===
Names: Alice Bob Charlie David
Names starting with 'A' or 'C':
Alice
Charlie
*/
E8. Abstraction vs Encapsulation
MediumDemonstrate the difference between abstraction and encapsulation with practical examples.
View Solution
/*
ABSTRACTION: Hiding implementation details, showing only functionality
ENCAPSULATION: Binding data and methods together, protecting data
*/
// ABSTRACTION using Abstract Class
abstract class Vehicle {
// Abstract method - no implementation (ABSTRACTION)
public abstract void start();
public abstract void stop();
// Concrete method
public void honk() {
System.out.println("Vehicle is honking!");
}
}
// ENCAPSULATION - Data hiding with private fields
class Car extends Vehicle {
// Private fields (ENCAPSULATION)
private String model;
private int speed;
private boolean engineRunning;
public Car(String model) {
this.model = model;
this.speed = 0;
this.engineRunning = false;
}
// Implementing abstract methods (ABSTRACTION)
@Override
public void start() {
engineRunning = true;
System.out.println(model + " engine started");
}
@Override
public void stop() {
engineRunning = false;
speed = 0;
System.out.println(model + " engine stopped");
}
// Getters and Setters (ENCAPSULATION)
public String getModel() { return model; }
public int getSpeed() { return speed; }
// Controlled access with validation (ENCAPSULATION)
public void setSpeed(int speed) {
if (!engineRunning) {
System.out.println("Cannot set speed. Engine is off!");
return;
}
if (speed >= 0 && speed <= 200) {
this.speed = speed;
System.out.println("Speed set to " + speed + " km/h");
} else {
System.out.println("Invalid speed! Must be 0-200");
}
}
public boolean isEngineRunning() { return engineRunning; }
}
// ABSTRACTION using Interface
interface PaymentProcessor {
void processPayment(double amount);
boolean validatePayment();
}
// Implementation hides the complexity (ABSTRACTION)
class CreditCardPayment implements PaymentProcessor {
// Encapsulated data
private String cardNumber;
private String cvv;
public CreditCardPayment(String cardNumber, String cvv) {
this.cardNumber = cardNumber;
this.cvv = cvv;
}
@Override
public void processPayment(double amount) {
if (validatePayment()) {
// Complex logic hidden from user (ABSTRACTION)
System.out.println("Processing credit card payment of $" + amount);
System.out.println("Connecting to bank...");
System.out.println("Payment successful!");
}
}
@Override
public boolean validatePayment() {
// Validation logic hidden (ABSTRACTION)
return cardNumber != null && cardNumber.length() == 16;
}
// Encapsulated - no direct access to card details
public String getMaskedCardNumber() {
return "****-****-****-" + cardNumber.substring(12);
}
}
public class AbstractionEncapsulationDemo {
public static void main(String[] args) {
System.out.println("=== Abstraction vs Encapsulation Demo ===\n");
// Abstraction: User doesn't know HOW car starts
System.out.println("--- Abstraction Example ---");
Vehicle myCar = new Car("Tesla Model 3");
myCar.start(); // Abstract method implemented
myCar.honk();
myCar.stop();
System.out.println("\n--- Encapsulation Example ---");
// Encapsulation: Cannot directly access/modify private fields
Car car = new Car("BMW X5");
// Cannot do: car.speed = 500; (field is private)
// Must use setter with validation
car.setSpeed(100); // Fails - engine not running
car.start();
car.setSpeed(100); // Works
car.setSpeed(300); // Fails validation
System.out.println("Current speed: " + car.getSpeed());
System.out.println("\n--- Payment Processing Example ---");
PaymentProcessor payment = new CreditCardPayment("1234567890123456", "123");
payment.processPayment(99.99); // User doesn't know internal logic
CreditCardPayment cc = (CreditCardPayment) payment;
System.out.println("Card: " + cc.getMaskedCardNumber()); // Protected access
}
}
/*
KEY DIFFERENCES:
| Abstraction | Encapsulation |
|----------------------------------|----------------------------------|
| WHAT an object does | HOW an object does it |
| Achieved via abstract class/ | Achieved via private fields |
| interface | and public methods |
| Hides complexity | Hides data |
| Design level concept | Implementation level concept |
| Example: Interface methods | Example: Getters/Setters |
Both work together:
- Abstraction defines the contract
- Encapsulation protects the implementation
*/
E9. Static Members Demonstration
EasyExplain and demonstrate the use of static variables, static methods, and static blocks in Java.
View Solution
class Counter {
// Static variable - shared across all instances
private static int count = 0;
// Instance variable - unique to each object
private int id;
private String name;
// Static block - executes once when class is loaded
static {
System.out.println("Static block executed - Class loaded!");
System.out.println("Initial count: " + count);
}
// Constructor
public Counter(String name) {
this.name = name;
count++; // Increment shared counter
this.id = count;
System.out.println("Object created: " + name + " (ID: " + id + ")");
}
// Static method - belongs to class, not instances
public static int getCount() {
// Cannot access instance variables directly
// Cannot use 'this' keyword
return count;
}
// Static method
public static void resetCount() {
count = 0;
System.out.println("Count reset to 0");
}
// Instance method - can access both static and instance members
public void display() {
System.out.println("ID: " + id + ", Name: " + name +
", Total Count: " + count);
}
public int getId() { return id; }
}
// Utility class with only static members
class MathUtils {
// Static constant
public static final double PI = 3.14159;
// Private constructor - prevents instantiation
private MathUtils() {}
// Static utility methods
public static int square(int n) {
return n * n;
}
public static double circleArea(double radius) {
return PI * radius * radius;
}
}
public class StaticMembersDemo {
public static void main(String[] args) {
System.out.println("=== Static Members Demo ===\n");
// Accessing static method before creating any object
System.out.println("Count before creating objects: " + Counter.getCount());
System.out.println();
// Creating objects - static variable is shared
Counter c1 = new Counter("First");
Counter c2 = new Counter("Second");
Counter c3 = new Counter("Third");
System.out.println();
// Static variable reflects total count
System.out.println("Total objects created: " + Counter.getCount());
// Each object has unique ID but shares count
c1.display();
c2.display();
c3.display();
System.out.println("\n--- Utility Class Example ---");
// Static members accessed via class name
System.out.println("PI value: " + MathUtils.PI);
System.out.println("Square of 5: " + MathUtils.square(5));
System.out.println("Circle area (r=3): " + MathUtils.circleArea(3));
System.out.println("\n--- Static vs Instance ---");
// Can access static via instance (not recommended)
System.out.println("Via instance (not recommended): " + c1.getCount());
// Recommended way
System.out.println("Via class name: " + Counter.getCount());
}
}
/*
OUTPUT:
=== Static Members Demo ===
Static block executed - Class loaded!
Initial count: 0
Count before creating objects: 0
Object created: First (ID: 1)
Object created: Second (ID: 2)
Object created: Third (ID: 3)
Total objects created: 3
ID: 1, Name: First, Total Count: 3
ID: 2, Name: Second, Total Count: 3
ID: 3, Name: Third, Total Count: 3
--- Utility Class Example ---
PI value: 3.14159
Square of 5: 25
Circle area (r=3): 28.27431
--- Static vs Instance ---
Via instance (not recommended): 3
Via class name: 3
KEY POINTS:
1. Static variables: One copy shared by all instances
2. Static methods: Called via class name, cannot access instance members
3. Static blocks: Execute once when class loads
4. Static constants: final static (e.g., Math.PI)
5. Cannot use 'this' or 'super' in static context
*/