Skip to content

Appendix A: Programming Readiness and Notation

Java 17 baseline, exception idioms, collections, and UML class diagram notation.

OO Development and Agile Practices
Designing, Testing and Evolving Software with AI Assistance

How to use this appendix

You can understand a design decision only if you can follow the code that expresses it. This appendix supplies a short diagnostic and a reference for the Java and diagram notation used in the book. It assumes previous programming experience; it is not a first programming course.

Start with A.1. Revise the sections that address your gaps, then return to the chapter. Use A.8 beside Chapter 2’s longer class-diagram exercises, and return to it when Chapters 8 to 10 introduce sequence, state and dependency diagrams. Records, streams and Optional can wait until a chapter uses them.

The language and API baseline is Java 17 without preview features. The syntax here describes the book’s examples, not permissions for an examination. Your approved assessment instructions decide what tools and notation you may use. Appendix B covers installation and the wider toolchain; Appendix D covers project versions and domain terminology.

The Appendix A companion (in the Code, Explanations and Solutions companion) contains complete runnable files, diagnostic answers and a diagram solution. Its small lab is separate from the running lending project. It neither changes the project nor depends on any of its versions.

A.1 Readiness diagnostic

Try these before opening the answers. Explain your reasoning as well as giving a result. Java fragments in this diagnostic are reading exercises; the companion supplies their executable context.

D1. Trace a boundary

boolean mayRequest(int count, int days) {
    return count >= 0 && count < 3 && days >= 1 && days <= 7;
}

What does it return for (2, 7), (3, 7), (0, 0) and (-1, 2)? What changes if < 3 becomes <= 3? Does a result of true mean a camera has been reserved?

D2. Follow two references

List<String> first = new ArrayList<>();
List<String> second = first;
second.add("CAM1");
second = new ArrayList<>();

What does first contain at the end? Which statement changes an object and which changes a variable?

D3. Distinguish identity from value

String left = new String("CAM1");
String right = new String("CAM1");

Predict left == right and left.equals(right). Why would two equal borrower identifiers not necessarily mean two variables refer to the same object?

D4. Read final precisely

final List<String> items = new ArrayList<>();
items.add("CAM1");

Does this compile? Would items = new ArrayList<>(); compile afterwards? Does final make the list immutable?

D5. Trace a snapshot

List<String> source = new ArrayList<>(List.of("CAM1"));
List<String> snapshot = List.copyOf(source);
source.add("CAM2");

What does each list contain? What happens if you call snapshot.clear()? Would the copy protect fields inside a mutable element?

D6. Protect an invariant

A loan period has a start date and an exclusive end date. Which inputs should its constructor reject? Do [20 October, 22 October) and [22 October, 24 October) overlap?

D7. Identify the method that runs

BorrowingPolicy policy = new StudentRules();
boolean allowed = policy.mayRequest(2, 7);

Which type describes the variable? Which class supplies the implementation? Does declaring an interface automatically establish that the implementation obeys the borrowing rule?

D8. Classify three failures

Classify each as a compile-time problem, a run-time failure or a wrong result:

  • Calling period.intersects(other) when LoanPeriod declares only overlaps.
  • Calling a method through a null reference.
  • Changing the reservation limit comparison from < 3 to <= 3.

D9. Preserve the meaning of failure

A directory lookup can find no borrower or fail because the service is unavailable. Why is catching every exception and returning “borrower not found” misleading? What does throws IOException require a caller to consider?

D10. Review a diagram after Chapter 2

A department keeps zero or more equipment items. Each item belongs to exactly one department at a time. One item may have several reservations; each reservation concerns exactly one item. Reservations have identifiers and periods. Draw those three classes and their multiplicities. Does this description justify a filled composition diamond?

Choose a revision route

If you struggled with…RevisitEvidence that the gap is closing
D1A.2Trace both sides of a boundary and state what the method does not do.
D2–D5A.3–A.4Explain the difference between changing a reference and changing its object.
D6A.3 and A.6Reject invalid periods and explain adjacency.
D7A.5Follow a call through an interface to an implementation.
D8–D9A.7Separate an ordinary result from invalid input and operational failure.
D10A.8 and Chapter 2 §2.6Read each multiplicity in both directions and justify the relationship.

There is no pass mark. Record the topic to revisit and the example you can now explain. D10 is revision after the notation lesson, not a prerequisite for opening Chapter 1.

A.2 Reading a small Java method

In public boolean mayRequest(int count, int days), public describes access, boolean is the result type, mayRequest is the name, and the two named int parameters receive the supplied values. return ends the method and supplies its result. A void method supplies no result value.

SyntaxMeaning hereCommon mistake
int count = 2;Declare and initialise an integer variable.Confusing assignment = with comparison ==.
count < 3Compare two numbers.Using the limit after addition when the input count is before addition.
a && bRequire both; evaluate b only if a is true.Treating & as an interchangeable spelling.
`ab`
!allowedNegate a Boolean value.Negating the wrong part of a longer condition.
if (...) { ... } else { ... }Select a branch.Believing indentation controls Java’s blocks.
for (String id : ids)Visit each element of the iterable in its encounter order.Assuming every collection has the same ordering guarantee.

Use parentheses when grouping is difficult to read. For example, id != null && !id.isBlank() avoids invoking isBlank() when id is null because && short-circuits. This is a specific guard, not a general solution to missing values. Java’s evaluation and operator rules are defined in [1].

A variable declared within a method is local to its scope. A field belongs to a class or an object and may outlive one call. When tracing code, write down both the local values and the object state that a later call can observe.

A.3 Classes, constructors and references

An instance method operates on a particular object. this refers to that object. A constructor establishes its initial state and has the class’s name with no return type. A static method belongs to the class and has no instance this. These mechanisms say how code runs; they do not decide whether a responsibility belongs in that class [2].

The companion’s LoanPeriod checks its invariant in the constructor. This is a constructor excerpt, with fields and accessors supplied in the complete file:

public LoanPeriod(LocalDate start, LocalDate endExclusive) {
    this.start = Objects.requireNonNull(start, "start");
    this.endExclusive = Objects.requireNonNull(endExclusive, "endExclusive");
    if (!start.isBefore(endExclusive)) {
        throw new IllegalArgumentException("End must be after start.");
    }
}

Passing a reference copies the reference value; Java does not pass the caller’s variable itself. A method can use that reference to mutate a mutable object. Reassigning the method’s parameter does not reassign the caller’s variable. D2 is the same distinction within one method.

For references, == compares identity. equals follows the class’s equality implementation. The companion’s ordinary LoanPeriod does not override equals; two separate periods with identical dates therefore do not become equal automatically. Compare their values deliberately, or design an equality contract when the domain needs one. Never assume a domain identifier and Java object identity are the same concept.

Reading access and modifiers

FormReading
publicAccessible where the enclosing type and module rules permit.
privateRestricted to the declaring top-level class and its nested classes.
No access modifierPackage access. It does not mean public.
protectedPackage access plus subclass access, subject to Java’s subclass rules.
final variableMay be assigned only once; a referenced object can still be mutable.
final classCannot be subclassed.
final methodCannot be overridden.
abstract classCannot be instantiated directly; may supply both implemented and abstract operations.

Chapter 2 develops encapsulation and information hiding. Keep those design ideas separate from memorising keywords.

A.4 Collections, copying and small functional expressions

List<Reservation> describes a list whose element type is Reservation; angle brackets express a generic type argument. new ArrayList<>() supplies a mutable list implementation. Declaring against List gives callers a different commitment from exposing ArrayList specifically.

ExpressionUseful interpretation
List.of("CAM1", "CAM2")An unmodifiable list containing those values.
new ArrayList<>(items)A mutable copy of the list structure.
List.copyOf(items)An unmodifiable snapshot of the element references.
items.size()Number of elements, not a count of completed loans or eligible borrowers.
items.get(0)First element; fails if the list is empty.

List.of and List.copyOf reject null elements. A snapshot does not follow later structural changes to its source. It also does not deep-copy elements. These distinctions matter when a class returns a collection to its callers [3].

Later chapters use lambdas and streams. Read the following equivalent counting excerpts before deciding which is clearer for the task:

long cameras = 0;
for (String id : ids) {
    if (id.startsWith("CAM")) {
        cameras++;
    }
}
long cameras = ids.stream()
        .filter(id -> id.startsWith("CAM"))
        .count();

id -> ... supplies a small function. Here, filter selects matching elements and count performs the terminal operation. This expression does not remove nonmatching entries from ids. A method reference such as wanted::overlaps supplies a compatible operation on an existing object. Prefer a loop when it makes a state change or failure path easier to follow.

A.5 Interfaces, overriding and the later Java idioms

The companion defines BorrowingPolicy and a StudentRules implementation. The declaration BorrowingPolicy policy = new StudentRules(); lets the caller use the interface’s operation while the object’s class supplies its implementation. @Override asks the compiler to check that a declaration overrides or implements an inherited operation. It does not test the operation’s meaning [4].

Overloading provides methods with the same name and different parameter lists. Overriding supplies an implementation of an inherited instance method. A call’s declared types help select an overload; the receiving object’s run-time class matters for an overridden instance method. Chapter 5 examines the behavioural obligations that syntax cannot enforce.

The following is the appendix’s reading scope, not an examination rule:

IdiomDepthWhat to recognise
Classes, interfaces, constructors, enums and genericsCoreRead declarations and follow ordinary calls.
Lambdas, method references and simple streamsWorking knowledgeExplain a short expression; expand it to ordinary steps.
RecordsWorking knowledge when encounteredA compact data-carrier class with component accessors and generated value methods.
Optional<T>Working knowledge when encounteredA result explicitly containing a value or no value.
varReading knowledgeLocal type inference; the type remains fixed at compile time.
Arrow-form switch expressionsReading knowledgeSelect a result without the traditional case fall-through.
Sealed types and advanced type patternsAwareness only hereNo dependency on them in this appendix.
Preview syntax and APIs newer than Java 17Outside this appendixDo not introduce them into its runnable files.

A record such as record Request(String borrowerId, int days) {} receives accessors named borrowerId() and days(), together with generated equals, hashCode and toString. Records are final; their component fields are final. A component can still refer to a mutable object, so a record is not automatically deeply immutable. A compact constructor can validate its arguments [5].

Optional.empty() should mean the absence specified by the operation’s contract. Calling get() on an empty optional throws. Inspect it, transform it or provide an appropriate alternative; do not use “empty” to conceal a failed lookup. For a present value, Optional.of requires non-null; ofNullable can convert a nullable value into present or empty [6].

var is useful where the initializer makes the type clear; it is not a dynamically typed variable. The companion demonstrates an enum, a switch expression and a record in executable context. You need not rewrite earlier ordinary classes into records to follow the book.

A.6 Dates and the interval convention

LocalDate represents a date without a time or time zone and is immutable. start.plusDays(2) returns a date; it does not modify start [7]. The book’s reservation periods are start inclusive, end exclusive, written [start, end).

First periodSecond periodOverlap?
[20 Oct, 22 Oct)[21 Oct, 23 Oct)Yes
[20 Oct, 22 Oct)[22 Oct, 24 Oct)No
[20 Oct, 22 Oct)[20 Oct, 22 Oct)Yes

For valid nonempty periods, overlap is expressed by both strict comparisons:

// Method-body excerpt from LoanPeriod.overlaps.
return start.isBefore(other.endExclusive)
        && other.start.isBefore(endExclusive);

Use Instant for a point on the time line and an injected Clock when tests need a controlled “now”, as later chapters do. A date and an instant answer different questions. Do not turn a calendar-day loan into an assumed fixed number of elapsed hours without an explicit time-zone policy.

A.7 Exceptions and evidence of a failure

An exception transfers control away from the ordinary return path. throw raises one; throws declares possible propagation from a method. Checked exceptions must be caught or declared where Java’s rules require it. RuntimeException subclasses and Error subclasses are unchecked [8].

SituationExampleWhat the caller needs to know
Ordinary negative resultNo matching borrower foundThe lookup completed and found no match.
Invalid argumentEnd date is not after startThe caller supplied an invalid period.
Operational failureApproval file could not be readThe decision could not be completed.
Assertion failureA check expected rejection but saw approvalThe observed result disagrees with the check.

The choice between a result and an exception belongs to the operation’s contract. Chapter 1 deliberately returns false for a negative count; the period constructor rejects invalid dates. Read the particular contract instead of assuming every invalid input has the same treatment.

The companion includes this complete method, with its imports and containing class provided there:

static String readFirstLine(Path path) throws IOException {
    try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
        return reader.readLine();
    }
}

The resource closes when the block exits, including exceptional exit. A file-reading failure propagates as an IOException; this method does not substitute “no borrower”. An empty file returns null because that is readLine’s contract. Interpret that result at the appropriate boundary.

Read an error in context: identify the operation, the exception type, the first relevant frame in your code and any cause. Catch an exception where you can handle it meaningfully or translate it into the declared boundary contract. Catching everything simply to make the program continue can destroy the information needed to diagnose it.

A.8 UML and Mermaid notation reference

UML describes modelling concepts; Mermaid is the text notation used to render diagrams in this book. Mermaid supports a useful subset and does not enforce every UML semantic rule. A successfully rendered diagram can still describe the wrong design [9, 10].

Class compartments and member notation

MeaningConventional UML formBook’s Mermaid form
Private attribute- start : LocalDate-LocalDate start
Public operation+ overlaps(other : LoanPeriod) : Boolean+overlaps(LoanPeriod other) boolean
InterfaceInterface annotation<<interface>> inside the class declaration
Generic typeA parameterised typeList~Reservation~ in a member label
VisibilityPublic, private, protected, package+, -, #, ~, respectively

Keep one convention within a diagram. Omit implementation details that are irrelevant to its question. Missing members in a selective diagram are not evidence that the members do not exist.

Relationships and arrow direction

The strings in the following table are Mermaid source syntax, not diagrams made from text characters. The renderer supplies the actual symbols; the last column says how to draw the same relationship by hand.

RelationshipMermaid declarationMeaning and review questionDrawn by hand
AssociationA --> B : holdsA structural link, navigable from A to B. Does the design retain that link?A solid line, with an open arrowhead at B to show navigation.
Association with navigation unspecifiedA -- BA link without a stated navigation direction; do not infer that both Java classes have fields.A solid line with no arrowhead.
DependencyA ..> B : usesA uses B. A method-only use often needs no stronger relation.A dashed line with an open arrowhead at B.
Shared aggregationWhole o-- PartA grouping claim, with a hollow diamond at the whole. Its precise meaning needs the model’s explanation.A solid line with a hollow diamond at the whole.
Composite aggregationWhole *-- PartStrong whole/part ownership, with a filled diamond at the whole. Is exclusive composite ownership and lifecycle intent actually specified?A solid line with a filled diamond at the whole.
Generalisation / inheritanceBase <|-- DerivedThe hollow triangle points to the general type. Does Derived meet Base’s behavioural obligations?A solid line with a hollow triangle at the general type.
Interface realisationContract <|.. ImplementationThe hollow triangle points to the interface; the line is dashed. Does the class implement that contract?A dashed line with a hollow triangle at the interface.

A class that holds another type in a field depends on that type too, but the diagram normally shows only the more informative association and not a second dependency line for the same pair. Use a dependency arrow for a weaker link, such as a method that only uses the type as a parameter or a local variable. Navigation expresses a modelling decision and can be implemented in more than one way.

Neither private, final nor construction with new proves UML composition. Garbage collection is not a domain lifecycle rule. A shared immutable period needs no filled diamond merely because a reservation refers to it. Use plain association when the stronger claim is unsupported.

Multiplicity: look at the far end

Label at an endNumber of objects at that end for one object at the other end
1Exactly one
0..1None or one
0..* or *Zero or more
1..*One or more

A Java List<T> does not by itself enforce a minimum size, uniqueness or exclusive ownership. A reference type does not by itself exclude null. The constructor, operations and domain rules supply those obligations.

Figure A.1 is a selective reading of Chapter 2’s reservation structure. It specifies the multiplicities needed in the indicated direction; omitted opposite-end numbers are not claims about exclusive ownership.

Figure A.1. One coordinator uses one rules object and stores zero or more reservations; each reservation refers to one period. This is a diagram reference to Chapter 2, not another running source-code version. The appendix lab uses StudentRules to demonstrate an interface separately.

Read different diagram kinds differently

DiagramWhat its edges mean in this bookWhat not to infer
Class diagramStructural relationships or type dependenciesExecution order.
Sequence diagramMessages in a scenario, read down the page; alt separates alternativesEvery possible path or real network traffic unless stated.
State diagramPermitted transitions between statesA Java subclass for every state.
FlowchartSteps and decisions in a processAutomatically enforced source-code dependencies.
Package/dependency viewWhich part depends on which other part, as defined by the captionThe opposite direction merely because a callback returns control.

The three kinds below are the ones, besides class diagrams, that the book draws. Each has a symbol table (the Mermaid source, and how the same symbol is drawn by hand) and one small example. The examples are notation exercises, not part of the lending project’s design. Treat each diagram’s caption as part of its meaning: it says what an arrow stands for in that figure.

Sequence diagrams

A sequence diagram shows one scenario in time order, from top to bottom. It answers “who asks whom, and in what order?” and not “what classes exist?”. Chapter 8 introduces it; Chapters 9 and 10 use it again [11].

ElementMermaid sourceDrawn by handReading
Participantparticipant R as ReservationRulesA box at the top of the page, with a name.An object or role taking part. as gives it a short label for the lines below. The renderer repeats the box at the bottom; by hand the top box is enough.
Lifeline(the renderer draws it)A dashed vertical line under the box.That participant’s time line. Time runs downwards.
CallU->>R: mayRequest(2, 7)A solid line with a filled arrowhead, labelled with the call.The sender asks the receiver to do something.
ReturnR-->>U: trueA dashed line with an open arrowhead.The answer. In this book a return can also carry an exception.
NoteNote over U,R: Nothing is storedA note box across the participants it concerns.A comment on the scenario, not a message.
Alternativesalt … else … endA frame labelled alt, with a dashed line between the alternatives.Exactly one alternative happens in a given run.
Optional, repeatedopt … end, loop … endA frame labelled opt or loop.A block that may happen once or not at all, and a block that repeats. The book’s figures do not use them.

Figure A.2. A sequence-diagram notation example. The caller asks the rules object one question and receives one of two answers. The note says what does not happen.

Do not read a sequence diagram as a complete specification. It shows the scenario its author chose, and a path that is missing is not a claim that the path cannot happen (Figure 8.2 leaves out malformed provider data to stay readable). The vertical order is time order. It is not the order of the classes in the source code.

State diagrams

A state diagram shows the positions an object can be in and the events that move it between them. It says nothing about how the states are implemented. Chapter 9 introduces it [12].

ElementMermaid sourceDrawn by handReading
StateAVAILABLEA rounded rectangle with a name.A situation the object can be in.
Start[*] --> AVAILABLEA filled circle with an arrow to the first state.Where a new object begins.
TransitionAVAILABLE --> RESERVED: reserveAn arrow labelled with the event.When the event happens in the first state, the object moves to the second.
GuardAVAILABLE --> RETIRED: retire [no open reservation]A label of the form event [condition].The transition fires only if the condition holds. The reservation lifecycle of Chapter 9 has no guards.
EndRETIRED --> [*]A circle with a filled centre.The object’s life ends here.

Figure A.3. A state-diagram notation example for an equipment item. It is not the reservation lifecycle of Chapter 9 and not a design for the project.

To read one, take each state and each event in turn and ask whether an arrow exists. A missing arrow means the model does not allow that event in that state. The diagram does not say what the program does when the event arrives anyway: it might throw, ignore it or report an error. That is a separate decision. A state diagram also does not require one Java subclass per state.

Flowcharts and dependency views

A flowchart is one Mermaid kind with several uses in this book. In a process flow the arrows mean “then” or “only if the previous step passed” (Figures 11.1 and 13.2). In a dependency view an arrow means that the code at its start may refer to the code at its end (Figure 10.1). In an object-assembly view a dotted arrow means “creates” (Figure 6.2). The caption always says which; never assume it.

ElementMermaid sourceDrawn by handReading
Step or partA["Check for overlap"]A rectangle with a label.An action, or a part of the system.
DecisionB{"Count below the limit?"}A diamond with a question.A choice. Each exit carries a label.
ArrowA --> BA solid arrow.What the caption says: “then”, “may refer to” or “passed to”.
Labelled arrowB -- "yes" --> CAn arrow with a short label.The condition or reason for that exit.
Dotted arrowA -. creates .-> CA dashed arrow with a label.A different relationship from the solid arrows; the label says which.
Directionflowchart TD or flowchart LR(the page layout)Top-down or left-to-right. It is layout only and carries no meaning.

Figure A.4. A process-flow notation example. Boxes are steps, diamonds are decisions and every exit of a diamond is labelled.

Figure A.5. A dependency-view notation example. An arrow means that code in the first box may refer to code in the second. A missing arrow means the reference is not permitted. The figure says nothing about the order of calls.

Formal UML has its own notation for the second use. A package diagram draws each package as a folder-shaped box, and a dependency is a dashed arrow with an open head from the package that uses to the package that is used. A component diagram draws each component as a box labelled «component» and shows its interfaces as a small ball (provided) and a socket (required). The book does not draw either; it draws the dependency view as a flowchart, because the only question is “who may refer to whom”. The reading rule is the same in both: the arrow starts at the code that refers and points to the code referred to. In a dependency view the arrow is not the direction of runtime calls. In Figure 10.1 the storage adapter refers to an application-owned contract, so the arrow points from the adapter to the application, although the coordinator calls the adapter at run time [9, 13].

To check a diagram: name its question, read every relationship aloud, justify each multiplicity, compare shown operations with their source, and trace any claimed order. Use top-down layouts for wider structures. A diagram is finished when it explains the intended relationship clearly, not when it contains every class.

A.9 A short verification activity

Complete D1–D9, then run the companion lab or trace it on paper. Select one mistaken assumption from your answers and explain which check exposes it. After Chapter 2, attempt D10 and compare your diagram with the solution. After Chapters 8 to 10, read the sequence, state and flowchart fragments in the companion, Section 4.

Optional AI activity, with an identical offline route. The following is an author-constructed candidate explanation:

“The list is final, so callers cannot clear it. Copying a list makes all its elements immutable. Every object created in a constructor should have a composition diamond.”

Classify its three claims and correct each using the code or the stated modelling rule. A live assistant may produce a different candidate if permitted, but is not required. Record the claim, your check and your conclusion. Do not use another unsupported explanation as the final evidence.

What you hand in at the end is a short personal readiness note: topics checked, one corrected explanation and any remaining revision. This is formative study guidance and adds no assessment requirement.

Sources and further reading

Official references checked on 13 October 2026. The explanations and exercises above are original; source examples have not been reproduced.

  1. Oracle, Java Language Specification, Java SE 17, Chapter 15: Expressions. Evaluation, reference equality, lambdas and switch expressions.
  2. Oracle, JLS 17, Chapter 8: Classes. Fields, constructors, modifiers and methods.
  3. Oracle, Java SE 17: List. List operations and unmodifiable copies.
  4. Oracle, JLS 17, Chapter 9: Interfaces. Interface declarations and implementation contracts at the language level.
  5. Oracle, Java SE 17: Record Classes. Generated members and compact constructors.
  6. Oracle, Java SE 17: Optional.
  7. Oracle, Java SE 17: LocalDate.
  8. Oracle, JLS 17, Chapter 11: Exceptions.
  9. Object Management Group, Unified Modeling Language 2.5.1. Standard terminology and semantics.
  10. Mermaid, Class diagrams. Renderer syntax, members, relationships and multiplicities.
  11. Mermaid, Sequence diagrams. Message and alternative-block syntax.
  12. Mermaid, State diagrams. States, transitions and the start and end markers.
  13. Mermaid, Flowcharts. Nodes, decisions, labelled and dotted links.