Quiz 2

Iterators & Callbacks

1054 words
5 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Iterators & Callbacks ## 🎯 Learning Objectives - Implement the `Iterable` and `Iterator` interfaces - Use enhanced for-each loops with custom collections - Understand the callback pattern using interfaces - Use anonymous inner classes and lambda expressions (preview) ## 1. Iterators — How For-Each Really Works ##...

Iterators & Callbacks

🎯 Learning Objectives

  • Implement the Iterable and Iterator interfaces
  • Use enhanced for-each loops with custom collections
  • Understand the callback pattern using interfaces
  • Use anonymous inner classes and lambda expressions (preview)

1. Iterators — How For-Each Really Works

1.1 The Iterable and Iterator Interfaces

java
// java.lang.Iterable<T> — what enables the for-each loop
public interface Iterable<T> {
    Iterator<T> iterator();
}
// java.util.Iterator<T> — the actual traversal
public interface Iterator<E> {
    boolean hasNext();  // Is there a next element?
    E next();           // Return next element and advance
    default void remove() { throw new UnsupportedOperationException(); }
}

1.2 Custom Iterable Collection

java
public class Range implements Iterable<Integer> {
    private int start, end;
    public Range(int start, int end) {
        this.start = start;
        this.end = end;
    }
    @Override
    public Iterator<Integer> iterator() {
        return new RangeIterator();
    }
    // Private inner class implements Iterator
    private class RangeIterator implements Iterator<Integer> {
        private int current = start;
        @Override
        public boolean hasNext() {
            return current < end;
        }
        @Override
        public Integer next() {
            if (!hasNext()) throw new NoSuchElementException();
            return current++;
        }
    }
}
// Usage:
Range range = new Range(1, 5);
for (int n : range) {  // Works because Range implements Iterable
    System.out.print(n + " ");
}
// Output: 1 2 3 4

1.3 How For-Each is Translated

java
// This code:
for (String s : list) {
    System.out.println(s);
}
// Is compiled to this:
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String s = iter.next();
    System.out.println(s);
}

1.4 Fail-Fast Iterators

Most collection iterators are fail-fast: if the collection is structurally modified after the iterator is created (except through the iterator's own remove), the iterator throws ConcurrentModificationException.
java
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String s : list) {
    if (s.equals("B")) {
        list.remove(s);  // Throws ConcurrentModificationException!
    }
}

2. Callbacks — Interfaces as Function Parameters

2.1 The Problem

How do you pass behavior to a method in Java? In Python, you can pass a function directly. In Java (pre-lambdas), you pass an object whose interface defines the behavior.

2.2 Callback via Interface

java
// Define the callback interface
public interface ClickListener {
    void onClick(Button source);
}
// The framework accepts callbacks
public class Button {
    private ClickListener listener;
    public void setOnClick(ClickListener listener) {
        this.listener = listener;
    }
    public void click() {
        if (listener != null) {
            listener.onClick(this);
        }
    }
}
// Client code
Button btn = new Button();
btn.setOnClick(new ClickListener() {  // Anonymous inner class
    @Override
    public void onClick(Button source) {
        System.out.println("Button clicked!");
    }
});

2.3 Anonymous Inner Classes

An anonymous inner class is a class without a name, defined and instantiated in one expression:
java
// Syntax: new Interface/Class() { method implementations }
Comparator<String> byLength = new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return Integer.compare(a.length(), b.length());
    }
};
Limitations:
  • Cannot define a constructor
  • Can only extend one class or implement one interface
  • Must override all abstract methods

2.4 Lambda Expressions (Java 8+ Preview)

java
// Lambda replaces anonymous inner class for functional interfaces
Comparator<String> byLength = (a, b) -> Integer.compare(a.length(), b.length());
// Even shorter:
Comparator<String> byLength = Comparator.comparingInt(String::length);
A functional interface is an interface with exactly one abstract method (like Comparable, Runnable, Comparator). Lambdas work only with functional interfaces.

3. Common Pitfalls

Pitfall 1: Concurrent Modification During Iteration

java
for (String s : list) { list.remove(s); }  // ConcurrentModificationException!
Fix: Use iterator.remove() or collect items to remove and do it after.

Pitfall 2: Iterator's next() Without hasNext() Check

java
Iterator<String> it = list.iterator();
String s = it.next();  // NoSuchElementException if list is empty

Pitfall 3: Forgetting to Declare Iterator as Inner Class

The iterator often needs access to the outer object's state. Using a private inner class (or anonymous class) is the standard pattern.

4. Practice Questions

Q1: What does Iterable provide?
Answer: The iterator() method, which returns an Iterator<T>. Implementing Iterable enables the for-each loop. Q2: What is the output?
java
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> it = list.iterator();
it.next();
it.remove();
System.out.println(list);
Answer: [B, C]remove() removes the element returned by the last next() call. Q3: Why can't you modify a collection during for-each iteration?
Answer: For-each internally uses an iterator. The collection tracks structural modifications via a modCount field. If the modCount changes during iteration (not via the iterator's own methods), the iterator detects this and throws ConcurrentModificationException to prevent undefined behavior. Q4: What is a functional interface?
Answer: An interface with exactly one abstract method. Examples: Runnable, Callable, Comparator, ActionListener. These can be implemented with lambda expressions. Q5: What are the limitations of anonymous inner classes?
Answer: No constructor, can only extend one class or implement one interface, verbose syntax, and can't be reused. Q6: Implement an Iterable that returns even numbers up to a limit.
java
public class EvenNumbers implements Iterable<Integer> {
    private int limit;
    public EvenNumbers(int limit) { this.limit = limit; }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            int current = 0;
            @Override
            public boolean hasNext() { return current <= limit; }
            @Override
            public Integer next() {
                int val = current;
                current += 2;
                return val;
            }
        };
    }
}
Q7: How does the callback pattern enable Swing event handling?
Answer: Swing components accept callback objects (listeners) that implement interfaces like ActionListener. When an event occurs (button click), Swing calls the listener's method. This decouples the UI framework from application logic. Q8: Can you use a lambda for any interface?
Answer: No. Lambda expressions can only be used for functional interfaces (interfaces with a single abstract method). For interfaces with multiple abstract methods, use anonymous inner classes.

📐 Key Concepts

InterfaceMethodPurpose
Iterableiterator()Enables for-each
IteratorhasNext(), next(), remove()Traversal
Functional interface1 abstract methodLambda-compatible
CallbackInterface passed to methodBehavior injection

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.