Unit 3: Intermediate Java Concepts & Application Development
Advanced Object-Oriented Programming Review & Patterns
Interfaces vs. Abstract Classes
| Feature | Interface | Abstract Class |
|---|---|---|
| Purpose | Define a contract (what) | Provide a base (what + partial how) |
| Inheritance | Multiple inheritance allowed (implements multiple) |
Single inheritance only (extends) |
| Methods | public abstract by default (Java 8+ allows default/static) |
Can have abstract and concrete methods |
| Variables | public static final (constants only) |
Any access modifier; can be non-final |
| Constructor | No constructors | Can have constructors (called via super()) |
[!TIP] When to Use
- Interface: For defining capabilities across unrelated classes (e.g.,
Runnable,Serializable). Use when you need multiple inheritance of type.
- Abstract Class: For sharing common code among closely related classes (e.g.,
AbstractList). Use when you have a base template with shared state/behavior.
Polymorphism
-
Method Overriding: Subclass provides specific implementation for a method declared in its superclass.
- Rules: Same method name, parameters, return type (or covariant), access cannot be more restrictive.
-
Dynamic Method Dispatch: Runtime resolution of overridden method call based on the actual object type, not reference type.
Animal a = new Dog(); // Animal reference, Dog object a.makeSound(); // Calls Dog's makeSound() at runtime
Design Patterns (Conceptual)
-
Singleton: Ensure a class has only one instance & provide global access.
public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }Key: Private constructor, static instance, synchronized
getInstance()for thread safety (or use eager initialization/static inner class). -
Factory: Create objects without specifying exact class.
interface Shape { void draw(); } class Circle implements Shape { public void draw() { /*...*/ } } class Factory { public Shape getShape(String shapeType) { if ("CIRCLE".equals(shapeType)) return new Circle(); // ... } }
Exception Handling
Exception Hierarchy
Throwable
├── Error (system-level, e.g., OutOfMemoryError - not handled)
└── Exception
├── RuntimeException (unchecked, e.g., NullPointerException)
└── Checked Exceptions (must be handled/declared, e.g., IOException)
try-catch-finally Syntax & Flow
try {
// Code that may throw exception
} catch (SpecificException e) {
// Handle specific exception
} catch (Exception e) {
// Handle general exception (last)
} finally {
// Always executes (even if return/catch), for cleanup
}
[!TIP] Best Practices
- Catch most specific exception first.
finallyfor closing resources (but prefer try-with-resources).
- Avoid empty
catchblocks.
- Do not catch
Throwable/Errorunless absolutely necessary.
throw vs. throws
-
throw: Used inside a method to raise an exception.throw new IllegalArgumentException("Invalid age"); -
throws: Used in method signature to declare exceptions that method might throw.public void readFile() throws IOException { ... }
Custom Exception Class
class MyException extends Exception { // or RuntimeException
public MyException(String message) {
super(message);
}
}
Try-with-resources (for AutoCloseable)
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
// Use br
} catch (IOException e) { ... }
// br.close() called automatically
\boxed{\text{Resources must implement } \texttt{AutoCloseable}}
Collections Framework & Generics
Core Interfaces & Primary Implementations
| Interface | Ordered? | Duplicates? | Nulls? | Common Implementations |
|---|---|---|---|---|
List |
Yes (index) | Yes | Yes (except Vector) |
ArrayList, LinkedList |
Set |
No | No | At most one null |
HashSet, TreeSet |
Queue |
Yes (FIFO) | Yes | Varies | LinkedList, PriorityQueue |
Map |
No (key-value) | Keys: No, Values: Yes | One null key, multiple null values |
HashMap, TreeMap |
Iteration Methods
-
Enhanced
forloop:for (String s : list) { ... } -
Iterator:
Iterator<E> it = list.iterator(); while(it.hasNext()) { E e = it.next(); }- Allows
remove()during iteration.
- Allows
-
ListIterator (for
Listonly): Bidirectional (hasPrevious(),previous()), allowsadd()/set().
Sorting: Comparable vs. Comparator
-
Comparable<T>: Natural ordering. Implemented by the class itself.class Student implements Comparable<Student> { public int compareTo(Student s) { return this.id - s.id; } } Collections.sort(list); // Uses natural order -
Comparator<T>: External ordering. Separate class or lambda.Comparator<Student> byName = (s1, s2) -> s1.name.compareTo(s2.name); list.sort(byName); // or Collections.sort(list, byName)
Generics
-
Type Parameters:
<T>in class/interface/method declaration. -
Raw Types: Using generic class without type parameter (e.g.,
List list = new ArrayList();) — unsafe, generates warnings. -
Wildcards:
-
?: Unknown type. -
? extends T: Upper bound (T or subtype). Read-only (covariant). -
? super T: Lower bound (T or supertype). Write-only (contravariant).
PECS: Producer
extends, Consumersuper. -
-
Type Erasure: Generic type info removed at compile time; replaced with bounds/
Object. No reification.
Java I/O Streams
Byte vs. Character Streams
| Byte Streams | Character Streams |
|---|---|
| For binary data (images, audio) | For text data (Unicode) |
Classes: InputStream, OutputStream |
Classes: Reader, Writer |
Subclasses: FileInputStream, BufferedInputStream |
Subclasses: FileReader, BufferedReader, PrintWriter |
Common Classes & Usage
-
Fileclass:new File("path")— check existence (exists()), is directory (isDirectory()), list files (listFiles()). -
BufferedReader/BufferedWriter: Buffered I/O for efficiency.readLine()for reading lines. -
PrintWriter: Convenientprint(),println(). Can wrap other writers/streams.
Object Serialization & Deserialization
-
Serializable: Marker interface (no methods). Class must implement it. -
ObjectOutputStream/ObjectInputStream:try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data.obj"))) { oos.writeObject(object); } // Deserialization: Object obj = ois.readObject();Note:
transientfields are not serialized.serialVersionUIDfor version control.
Multithreading & Concurrency Basics
Thread Creation
-
Extend
Thread: Overriderun().new MyThread().start(); -
Implement
Runnable: Pass toThreadconstructor. Preferred (allows extending other classes).Thread t = new Thread(() -> { /* task */ });
Thread Lifecycle States
NEW → RUNNABLE (executing or ready) → BLOCKED/WAITING/TIMED_WAITING → TERMINATED
Synchronization
-
Intrinsic Lock (Monitor): Each object has one.
-
Synchronized Method:
public synchronized void method() { ... }— locksthis(or Class object for static). -
Synchronized Block: Finer-grained control.
synchronized(lockObject) { // critical section }
Inter-thread Communication (must own lock, call from synchronized context)
-
obj.wait(): Releases lock, entersWAITING. -
obj.notify(): Wakes one waiting thread. -
obj.notifyAll(): Wakes all waiting threads.
java.util.concurrent Intro
-
ExecutorService: Manages a pool of threads.ExecutorService exec = Executors.newFixedThreadPool(2); exec.submit(() -> task()); exec.shutdown(); -
Future<T>: Represents result of async computation.Future<Integer> f = exec.submit(() -> compute()); int result = f.get(); // blocks until done
Graphical User Interface (GUI) with Swing
Swing vs. AWT
-
Swing: Lightweight (pure Java), pluggable look-and-feel, more components.
-
AWT: Heavyweight (native peers), platform-dependent.
Top-level Containers
-
JFrame: Main window (has content pane). -
JDialog: Popup window. -
JApplet(deprecated),JWindow.
Common Components
-
JLabel,JButton,JTextField,JTextArea(withJScrollPane), -
JCheckBox,JRadioButton(inButtonGroup),JComboBox,JList.
Layout Managers
| Layout | Description |
|---|---|
FlowLayout |
Left-to-right, wraps. Default for JPanel. |
BorderLayout |
North, South, East, West, Center. Default for JFrame content pane. |
GridLayout |
Uniform grid (rows x cols). |
GridBagLayout |
Flexible grid with constraints (complex). |
Event Handling
-
Listener Interfaces:
ActionListener(buttons, menu items),ItemListener(checkboxes, radio buttons),WindowListener(window events). -
Adapter Classes: Provide empty implementations (e.g.,
WindowAdapter) so you override only needed methods.frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
Menus
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem exitItem = new JMenuItem("Exit");
fileMenu.add(exitItem);
menuBar.add(fileMenu);
frame.setJMenuBar(menuBar);
Database Connectivity (JDBC)
JDBC Architecture
Java App → JDBC API → JDBC Driver → Database
-
DriverManager: Manages drivers, createsConnection. -
Connection: Session with DB. CreatesStatements. -
Statement: Executes SQL.executeQuery()(SELECT),executeUpdate()(INSERT/UPDATE/DELETE). -
ResultSet: Tabular data.next(),getXxx(column). -
PreparedStatement: Precompiled SQL with parameters (?). Prevents SQL injection. -
CallableStatement: Calls stored procedures.
Basic Connection & Query (MySQL Example)
String url = "jdbc:mysql://localhost:3306/db";
String user = "root", pass = "password";
try (Connection con = DriverManager.getConnection(url, user, pass);
PreparedStatement pst = con.prepareStatement("INSERT INTO users(name) VALUES(?)")) {
pst.setString(1, "Alice");
int rows = pst.executeUpdate();
} catch (SQLException e) { e.printStackTrace(); }
Transaction Management
con.setAutoCommit(false); // Start transaction
try {
// multiple statements
con.commit(); // success
} catch (SQLException e) {
con.rollback(); // failure
} finally {
con.setAutoCommit(true);
}
Modern Java Features (Post-Java 8)
Lambda Expressions
-
Syntax:
(parameters) -> expressionor(parameters) -> { statements; } -
Functional Interfaces: Single abstract method (SAM). Examples:
-
Predicate<T>:test(T)→boolean -
Consumer<T>:accept(T)→void -
Function<T,R>:apply(T)→R -
Supplier<T>:get()→T
List<String> list = Arrays.asList("a", "bb", "ccc"); list.forEach(s -> System.out.println(s)); // Consumer list.removeIf(s -> s.length() > 1); // Predicate -
Method References
-
ClassName::staticMethod -
instance::instanceMethod -
ClassName::instanceMethod(first arg is receiver) -
ClassName::new(constructor)list.forEach(System.out::println); // instead of s -> System.out.println(s)
Stream API
-
Obtain stream:
collection.stream(),Arrays.stream(array),Stream.of(...). -
Intermediate Ops (lazy, return
Stream):filter,map,sorted,distinct,limit. -
Terminal Ops (eager, return non-
Stream):forEach,collect,reduce,count,min/max.int sum = list.stream() .filter(s -> s.length() > 1) .mapToInt(String::length) .sum(); List<String> filtered = list.stream() .filter(s -> s.startsWith("a")) .collect(Collectors.toList());
Optional<T>
-
Container object which may or may not contain non-null value.
-
Avoids
NullPointerException.Optional<String> opt = Optional.ofNullable(str); String result = opt.orElse("default"); opt.ifPresent(s -> System.out.println(s));
Development Tools & Best Practices
IDE Proficiency (IntelliJ IDEA / Eclipse)
-
Debugging: Set breakpoints, step over (
F8), step into (F7), evaluate expression, watch variables. -
Refactoring: Rename (
Shift+F6), extract method, change signature.
Unit Testing with JUnit 5
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
class MyTest {
@BeforeEach void init() { /* runs before each test */ }
@AfterEach void cleanup() { /* runs after each test */ }
@Test
void testAddition() {
assertEquals(4, Calculator.add(2, 2));
assertTrue(condition);
assertThrows(Exception.class, () -> method());
}
}
Build Automation: Maven
-
POM.xml: Project Object Model. Declares dependencies, plugins, build config.
-
Commands:
mvn compile,mvn test,mvn package,mvn install. -
Dependency Example:
<dependency> <groupId>junit</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency>
Javadoc
-
Comments:
/** ... */with tags@param,@return,@throws. -
Generate:
javadoc MyClass.javaor via IDE/Maven (mvn javadoc:javadoc).
Logging (SLF4J + Logback example)
-
SLF4J: Facade API.
Logger logger = LoggerFactory.getLogger(ClassName.class); -
Logback: Implementation. Configure via
logback.xml.logger.info("Message"); logger.error("Error", exception);Avoid
System.out.println()for production logging.