Solution (source code)

= Solution

Keep storage private. Find the first entry whose horizontal coordinate is not smaller than the new one. Equality there means that the coordinate is already present; otherwise insertion at that position preserves strict ordering. Reject nonfinite coordinates, since a `NaN` would make the required comparisons meaningless. This is an explicit finite-coordinate contract for a display application.<Java 8 Double API documentation>[isFinite(double)]{ref}

The <Observer pattern> uses a small callback <Java interface>. With `import java.util.*;`, the full implementation is:

``
interface GraphObserver {
    void changed(DataList source);
}

final class DataList implements Iterable<Point> {
    private final List<Point> points;
    private final List<GraphObserver> observers;

    public DataList() {
        points = new ArrayList<Point>();
        observers = new ArrayList<GraphObserver>();
    }

    public void addObserver(GraphObserver observer) {
        if (observer == null)
            throw new IllegalArgumentException("null observer");
        for (GraphObserver old : observers)
            if (old == observer) return;
        observers.add(observer);
    }

    public void removeObserver(GraphObserver observer) {
        for (int i = 0; i < observers.size(); ++i) {
            if (observers.get(i) == observer) {
                observers.remove(i);
                return;
            }
        }
    }

    public void addPoint(double x, double y) throws Exception {
        if (!Double.isFinite(x) || !Double.isFinite(y))
            throw new Exception("nonfinite coordinate");
        int i = 0;
        while (i < points.size() && points.get(i).getX() < x) ++i;
        if (i < points.size() && points.get(i).getX() == x)
            throw new Exception("duplicate x coordinate");
        points.add(i, new Point(x, y));
        List<GraphObserver> current =
            new ArrayList<GraphObserver>(observers);
        for (GraphObserver observer : current) observer.changed(this);
    }

    public Iterator<Point> iterator() {
        List<Point> snapshot = new ArrayList<Point>(points.size());
        for (Point p : points) snapshot.add(p.clone());
        return Collections.unmodifiableList(snapshot).iterator();
    }
}
``

This is a sequential implementation. Callback <object methods> are required to return normally and not reenter `addPoint`; they may change their registrations. Copying the registration <list> means such changes affect future notifications, while each observer present at the start of this notification gets exactly one call. Repeated registration of the same observer is ignored by <object identity>. Both signed zeros compare equal and therefore count as the same horizontal coordinate.

For correctness, all old entries before position `i` have smaller horizontal coordinates. If an entry at `i` exists after the duplicate check, it has a strictly larger coordinate. Inserting between these two groups preserves the <representation invariant>; rejecting a duplicate has no state effect. No client receives a stored mutable `Point`. Thus
$$
\boxed{\text{sorted, duplicate-free insertion first; observer notification second}.}
$$