Date Topics Code Examples To do
This document is updated frequently, so remember to refresh your browser.

How to import the code examples below into an Eclipse project.

Week 14 (November 16 - November 20)
  • Exceptions
    • Reporting errors: the throw statement
    • Handling errors: try/catch blocks
    • Declaring errors: the throws clause (required for "checked" exception types only)
  • The Exception class hierarchy; "checked" vs "unchecked" exceptions
    • The "unchecked" exceptions are subtypes of RuntimeException
    • "checked" exceptions must be caught, or declared with throws, in order for the code to compile
  • An exception may occur in a method call that is farther up the call stack than the code containing the try/catch block
  • The exception "propagates" down the stack until a matching catch block is found
  • catch blocks are specific to the type of exception
  • In general, avoid catching an exception unless you can actually do something about it
    • e.g., catch (Exception e){...} is almost always a bad idea
  • zyBook Sections 10.1 - 10.4
  • "Unwinding" the call stack to find the first matching catch block
  • Cleanup: try/catch/finally and try/finally
    • Code in a finally block is guaranteed to be executed before the stack frame disappears, whether or not an exception occured
    • finally blocks are commonly used to ensure that files are closed or other OS resources are released in case of an exception
  • Exception handling in real life: using Sockets
  • More fun with sockets (realistic examples using try/catch and try/catch/finally)
  • Example: tracing some exception-handling code
  • Reviewing polymorphism
Here is the class hierarchy for the Animals example.
Week 13 (November 9 - November 13)
  • An interface is a purely abstract list of methods (no method bodies)
  • A class can declare that it implements an interface, which means it must provide implementations for all the declared methods
  • Creates a subtype relationship between the implementing class and the interface
  • A class can only extend one other class, but may implement many interfaces
  • You can think of an interface as a representation of a set of capabilities
  • Example: The Zoo can hold any kind of object, provided it has the capabilities represented by the Creature interface (returning its species, making noise)
  • Example: Our graphing calculator can plot any kind of function, provided it has the capability of returning a y-value for a given x
  • We say that GraphingCalculator is loosely coupled to the main method and the concrete function types
    • when we create new function types, we don't have to modify the GraphingCalculator
  • Example: Factoring the common code from SineFunction, CosineFunction, and TangentFunction into an abstract superclass AnyTrigFunction
(This is a complete Eclipse project you can import; alternatively you can create a new project and drag the packages into the src folder. There are main() methods to run in bad.GCMain and in good.GCMain.)
  • zyBook Sections 9.11 - 9.12
  • Understanding the String compareTo method and the Java Comparable interface
  • The Java Arrays.sort method can sort any type of object as long as it implements the Comparable interface
  • We say that a component A is tightly coupled to component B if making a change in A forces you to make changes in B
  • Interfaces are used to "decouple" components
  • For Arrays.sort, it cannot be tightly coupled to the classes being sorted
    • When the code was written, it would be impossible for the programmer to predict all the types of objects (such as our Contact type) that might need to be sorted
  • Another example: The Swing GUI framework can invoke any event handler in our code, provided that it implements the ActionListener interface
  • Another example: In lab 2, the plotter is tightly coupled to the RabbitModel class
    • When making a new kind of model, we had to modify the RabbitModel class itself
    • Better: have the plotter refer to an interface representing the capabilities it needs to plot the model (getPopulation, simulateYear, and reset)
  • Using the Comparator interface
  • Interfaces vs abstract classes
    • The main purpose of inheritance is to reuse code
    • The main purpose of an interface is to reduce coupling
    • Use an abstract class when you specifically need a partial implementation that can be extended by subclasses
    • Use an interface when you don't need a shared implementation
    • Interfaces are much more flexible, since a class can implement many interfaces without constraining its inheritance hierarchy
  • zyBook Section 9.13
  • Case study: redesigning the graphing calculator so that function types can report their own parameters and descriptions
    • Defining a Descriptor type for a parameter and string description
    • Adding additional capabilities to the SVFunction interface
    • Creating an abstract class for the common code among the function types
    • Options for subclasses to initialize the data in the abstract class
      • Constructors
      • Additional protected methods
  • Don't drink too much Kool-Aid
    • Inheritance isn't always the right solution
    • is-a vs has-a relationships
      • A Car is a Vehicle (suggests inheritance)
      • A Car has a SteeringWheel (suggests composition)
    • Composition is often more flexible and gives you better control
See the ugly.GraphingCalculator for example using explicit type-checking with instanceof and downcasts. See the better package for a redesigned solution using an interface to describe the function parameters.
Here are some notes on our redesign of GraphingCalculator.
Here is the class diagram for the SVFunction hierarchy.
Week 12 (November 2 - November 6)
  • Introduction to inheritance
  • Extending a class (the extends keyword) to create a subclass or derived class
  • The subclass inherits the attributes and methods of the superclass
    • However, private instance variables or methods are still inaccessible
    • Use the protected access modifier to allow subclasses to use or override a method without making it public
    • protected is rarely used for variables, since that would break encapsulation
  • A subclass can re-implement a method from the superclass, called overriding
  • The class java.lang.Object is a superclass for every Java class
  • No multiple inheritance: Every class except Object has exactly one "parent" class (immediate superclass)
  • zyBook Sections 9.1 - 9.4
  • Inheritance, continued
  • When a subclass is constructed, the first thing that happens is that a superclass constructor is called
    • If the superclass has a default constructor (no arguments), the compiler can do this automatically
    • More often, the programmer has to explicitly invoke a superclass constructor using the super keyword
  • Polymorphism: a variable declared with type T can refer, at runtime, to an object that is a subtype of T
  • Every variable is associated with two types:
    • The declared type is the type in the variable declaration
      • never changes
      • is what the compiler sees
    • The runtime type is the type of the object that the variable actually refers to
      • may change from moment to moment as the code executes
      • cannot be seen by the compiler
  • The code that actually executes when a method is called depends on the runtime type
    • The VM starts at the runtime type, and searches up the class hierarchy until a matching method is found
    • This mechanism is called dynamic binding or dynamic dispatch, since it happens dynamically as the code executes
  • zyBook Sections 9.5 - 9.7
  • Downcasting an object
    • The compiler sees only the declared type of a variable
    • It is possible to insert a downcast to allow the compiler to treat a variable as though it had a different declared type
    • A cast doesn't change the type of an object (which cannot change)
    • A cast may fail at runtime with ClassCastException if runtime type is incompatible with the cast
    • Can check the runtime type before a cast using the instanceof operator or getClass
      • Explicit type-checking like this is needed only rarely in well-designed OO code
      • One place you do need it is when overriding the equals() method of Object
  • Abstract classes
    • An abstract method has no body
    • If a class contains one or more abstract methods, then it must be declared abstract as well
    • Abstract classes cannot be instantiated
    • An abstract class usually has protected constructors, since only subclasses can call them
    • An abstract class is a partial implementation that needs to be extended
    • Use an abstract class for code that is common to two or more subclasses when it doesn't make sense for those classes to extend each other
      • Neither Cat extends Dog nor Dog extends Cat makes any sense
      • Instead, Cat and Dog can extend an abstract class Pet with the common code
  • More about superclass constructors:
    • Never re-declare instance variables in a subclass
      • Use the superclass constructor to initialize them
      • Use the public API methods to access them
      • Add protected accessors if needed
  • zyBook Sections 9.8 - 9.9
Week 11 (October 26 - October 30)
  • Tail recursion is when the recursive call is the very last thing that happens in the method
    • Local variables in the call stack will never be used again, so...
    • ...it is easy to replace the recursion with a loop that just updates the local variables
    • See the nonrecursive version of binary search
  • When not to use recursion
    • Calculating fibonacci numbers recursively requires the same previous values to be recalculated over and over again
    • Dynamic programming is the technique of converting a recursive algorithm to an iterative one by building up a table of previously calculated values
  • Introduction to sorting
    • In practice, we use the built in library methods (such as Arrays.sort or Collections.sort)
    • Sorting algorithms continued to be actively studied because they are good examples of algorithm design and analysis
  • Two examples of easy but inefficient sorting algorithms
    • Selection sort
    • Insertion sort
  • zyBook Sections 6.19, 6.20, 8.10
  • Using a divide-and-conquer strategy for sorting
  • Implementing a merge algorithm
  • The merge sort algorithm
  • Introduction to algorithm analysis
    • Running time of selection sort is proportional to n2, where n is the size of the array
    • Running time of merge sort is proportional to n log n
  • zyBook Section 8.11
  • No class
Week 10 (October 19 - October 23)
  • Recursion is when a method calls itself.
    • Every method call has its own local variables
    • Local variables live in an activation frame on the call stack
    • The frame includes a "return address", where to resume execution when the method returns
  • Thinking recursively
    • Reduce the problem to a smaller instance
    • Identify a base case
    • Believe that it will work
  • Our initial examples of recursion are simple problems that we could easily solve with loops...
  • ...however, it turns out to be a powerful problem-solving technique for many problems that are very difficult to solve with loops
  • Infinite recursion and StackOverflowError
  • Using extra parameters in PalindromeChecker to keep track of the start and end of the substring
Step through the countUp method in the debugger (or pythontutor) to visualize the frames in the call stack.
  • zyBook Sections 8.1, 8.2, 8.3, 8.8
  • Some problems that are very hard to write with loops are very simple using recursion
  • Towers of Hanoi
  • Listing permutations
  • Searching a file hierarchy
  • zyBook Sections 8.4 - 8.7
  • More file hierarchy examples - using an extra parameter to keep track of "depth"
  • Recursion with arrays
  • The divide-and-conquer strategy
    • Split the problem into two parts
    • Solve each part (usually using recursion)
    • Combine the parts into a solution
Week 9 (October 12 - October 16)
  • The class ArrayList
  • Generic type parameters in Java classes
  • Using an ArrayList for reading input
  • Comparing arrays and ArrayLists
  • Wrapper classes for primitive types, autoboxing
  • zyBook Sections 6.14 - 6.16
  • How an ArrayList works
    • behind the scenes it's a partially filled array
    • when no more room, a new backing array is created that is twice as big
  • More examples of array modification
    • Returning a new array vs modifying a given array
    • Doing deletions while iterating is tricky
    • In some cases (e.g. moving even numbers to front) the modification can be done "in place" (without creating a temporary array)
    • Shifting even numbers to front, odd numbers to end: to avoid clobbering all the odd numbers, can use an auxiliary ArrayList to store them
  • zyBook Sections 6.10 - 6.13
  • Two-dimensional arrays
    • The first index is always the row!
    • In Java, a 2D array is really an array of arrays
    • Each element is one row (a 1D array)
    • The number of rows is arr.length
    • The number of columns is arr[0].length
  • Making a copy of an array
    • shallow copy - copy array values only
    • deep copy - make copies of the objects they refer too as well
    • (an assignment never makes a copy of anything in Java)
  • Methods such as Arrays.copyOf always make a shallow copy
  • To make a deep copy, you generally have to use a constructor to make a duplicate of each object in the array
  • Don't use Arrays.copyOf for 2D arrays!
  • zyBook Section 6.7
Week 8 (October 5 - October 9)
  • Reading text files is just like reading input from a string or any other input stream
    • 1. Opening a file means asking the operating system to find the device and start buffering the data
      • Two ways to open a file
        • Construct a Scanner from a File object representing the path to your file, or
        • Create a FileInputStream object using the path to your file (and then construct a Scanner from it)
    • 2. Method that opens file needs the declaration throws FileNotFoundException (or throws IOException)
    • 3. Remember to close the Scanner when working with files!
  • A File object isn't actually a file, but is a Java object with methods for working with file names and paths
  • An exception like FileNotFoundException that requires the throws declaration is called a "checked" exception
    • the declaration says, in effect, "this method might cause this type of exception to occur"
  • Finding files
    • A program always has a working directory
    • For Java programs run within Eclipse, the working directory is always the project directory
    • To open a file that is not in the working directory, use a relative path or absolute path to the file
  • Text files are usually organized into lines ended by one of the platform-dependent line termination characters
  • To read a file line by line, use the scanner methods hasNextLine() and nextLine()
(For the examples above you'll need a text file in the project directory containing some data to read, e.g. nums.txt and
  • zyBook Sections 7.1 - 7.4
  • Arrays!
    • An array is a sequence of elements that can be accessed by index (like characters in a string)
    • Can be of any Java type
    • Fixed in length (but length can be computed during runtime)
    • Mutable
    • Arrays are objects and are created with the new keyword
    • A newly created array has default values for all elements (zeros or nulls)
    • There are no useful built-in methods, use the .length attribute to get the length
  • The Arrays class has many static methods for working with arrays, such as toString and sort
  • zyBook Sections 6.1, 6.2, 6.3, 6.8
  • Why we can't write a method to swap two ints
  • Primitives are always passed to a method by value
  • Objects are always passed to a method by reference
    • A non-primitive method parameter is always an alias, and the object it refers to can be modified by the method
    • However, modifying the parameter itself has no effect outside the method
  • Copying arrays of objects
    • A shallow copy makes a new array and copies over the references
    • A deep copy makes a new array and creates a copy of each object that the references point to
    • Java methods such as Arrays.copyOf only make a shallow copy
  • Using an array as a collection of related variables
  • zyBook Sections 6.4, 6.5, 6.6, 6.9
Week 7 (September 28 - October 2)
  • The for statement
    • Initialization, condition, and the "update" step are all moved onto one line
    • You can see at a glance how the loop is being controlled and how many times it will execute
  • Scope of variables declared within a block
  • Hand-tracing a loop
  • The idea of a "search" problem
    • Once you find something, don't un-find it!
    • Ask yourself: do I need to examine all the data, or can I stop once I see what I'm looking for?
  • Using a return statement to exit a loop
  • Using the debugger to diagnose an exception
  • zyBook Sections 5.3, 5.4, 5.5
  • Recap: when writing a loop
    • Am I iterating over a fixed sequence or range of values (use a for-loop) or is the number of iterations difficult to bound (use a while-loop)
    • Do I need to examine all the input, or can I stop when I find what I'm looking for (this is a "search" type of problem, potentially use an early exit)
  • Exiting a loop early using the break statement
    • unconditional jump to end of loop
    • not evil, but use sparingly
    • harder to analyze loop because early exit bypasses loop condition
  • The continue statement
    • unconditional jump to beginning of loop
    • mostly evil, try to avoid, difficult to use correctly
    • may, or may not, bypass the "update" step of the loop
  • Using the debugger to break into an infinite loop
  • Using a Scanner to parse a string
  • The methods hasNext, hasNextInt, etc
  • A loop to read input almost always has the form
          while there is still another item in the input stream
              get the item
              do something with it
  • zyBook Sections 5.6, 5.8
  • Reading input from the console
    • Can't detect end of input using hasNext or hasNextInt, because the method won't return until something is entered!
    • Need a recognizable "sentinel" value for console input
  • Nested loops
  • The break statement with nested loops
  • zyBook Sections 5.6, 5.7
Week 6 (September 21 - 25)
  • Using an "early return" from a conditional
  • Boolean operators, continued
  • De Morgan's Laws
  • Short-circuiting
  • zyBook Sections 4.6, 4.7, 4.8
  • Loops!
  • The while statement
  • Identifying initialization, condition, and body of a loop
  • While-loops vs. for-loops
    • Use for-loops when counting with an index or iterating over a fixed sequence of items
    • Use while-loops when the number of iterations is unknown or difficult to compute
  • zyBook Section 5.1
  • No class
Week 5 (September 14 - 18)
  • Conditional statements in Java
  • Condition must be a boolean expression
  • Relational operators for comparing numbers
  • Problem-solving strategy:
    • Do an example by hand
    • Write down the basic logic in pseudocode
  • zyBook Section 4.1
  • Nested conditionals, con't
  • Using helper methods to simplify code
    • "procedural decomposition" again
  • Use if...else if...else if...else.... for mutually exclusive actions
  • Use sequential if statements when you want all conditions to be checked
  • When to use else vs. else if at the end
  • The switch statement
  • zyBook Sections 4.2 and 4.3
  • Using == for objects only tests for identity, not "sameness".
  • When to use == (or !=)
    • For integer and char types
    • Checking whether an object reference is null
    • For enum types (we'll see them later on)
  • Use Math.abs(d1 - d2) < ERR to test whether two double values are the "same"
  • Use .equals() for Strings
    • or .equalsIgnoreCase(), or .startsWith(), or .endsWith(), or .contains()
  • Using == or != for booleans is almost always redundant!
    • if (isResident == true) {...} should be written
      if (isResident) {...}
    • if (isResident == false) {...} should be written
      if (!isResident) {...}
  • The boolean operators  &&  (and),  ||  (or), and ! (not)
  • zyBook Sections 4.4, 4.5, 4.6
Week 4 (September 7 - 11)
  • Client view: the public API
  • Developer view: instance variables, method implementations (private)
  • Encapsulation: data and implementation details are hidden from clients
    • Clients only depend on the public API
  • Incremental development, con't
    • Start with simple, concrete examples that you can do on paper (or on your fingers)
    • The steps of a simple example show you how to write the code
    • You can use your examples for test cases too
  • An object can have instance variables that are also objects
    • ...remember to initialize them!
    • A NullPointerException is thrown when you try to invoke a method on an object reference that is null
    • This is usually caused by forgetting to initialize something in your constructor
  • Introducing the JUnit framework for unit tests
  • zyBook Section 3.7
  • Guidelines for instance variables:
    • Instance variables store the "permanent" state of an object. Use local variables for temporary values within methods.
    • Avoid redundant instance variables
    • Make sure every instance variable is documented and initialized in the constructor
    • All instance variables should have consistent and correct values at the end of each method
    • Accessor methods should never modify instance variables
    • Avoid shadowing (don't name a local variable the same as an instance variable)
  • Don't use the static keyword when defining instance variables (we use static for constants, and sometimes for methods, but almost never for variables)
  • The this keyword
    • is usually redundant
    • can be used to distinguish between an instance variable and a local variable with the same name (See the first constructor for GasTank2.java)
    • can be used to call one constructor from another (See the second constructor for GasTank2.java)
    • can add clarity to a method that interacts with another method of the same type (See the stealFrom method of GasTank2.java)
  • The static keyword
    • In general, a static attribute is associated with the class, rather than with instances of the class
    • A method may be declared static if it does not refer to any instance variables (result is just calculated from arguments)
      • Example: utility methods such as Math.max
    • We usually declare constants to be static final
    • Using static for variables is usually a mistake (See BadCashRegister.java.)
  • The final keyword
    • A final variable's value can't change
    • Final instance variables must be initialized in the constructor
  • zyBook Section 3.8 and 3.10
Week 3 (August 31 - September 4)
  • Constructing objects
  • Strings are unusual in Java because
    • They do not have to be constructed using the new keyword
    • They are immutable
  • Exploring a simple class - java.awt.Rectangle
  • In the code Rectangle r = new Rectangle(10, 20), the new keyword:
    1. Allocates a blank chunk of memory
    2. Runs the constructor code to initialize it
    3. Returns a reference to it
  • Implementing our own class!
    • Instance variables represent the object's state (also called fields, attributes, or member variables)
    • Constructors initialize the instance variables
    • Methods provide the operations we want
  • Mutator vs accessor methods
    • Accessor methods return information about the object's state (but do not modify it)
    • Mutator methods modify the object's state (and usually return void)
    • A method can be both, but it's rare (Example: the Scanner methods such as next, nextInt, etc.)
  • A class with no mutator methods is called immutable
    • (Example: the class String)
  • zyBook sections 3.1 - 3.3
  • Recap: a typical class definition has
    • Instance variables - the object's state
    • Constructors - initialize the instance variables
    • Methods - the operations we want
  • Methods are usually either
    • Accessors - return information about the object's state (without modifying anything)
    • Mutators - modify the object's state (usually return void)
  • Instance variables vs. local variables
    • An instance variable is declared outside of all methods and represents a "permanent" part of the object's state
    • A local variable is declared within a method and is used for temporary calculations within that method
  • Typical steps for defining a class
    1. Design the public API
    2. Write stubs for the methods and constructors, and document them
    3. Write some unit tests or usage examples
    4. Start thinking about instance variables
      • Look at the accessor methods for inspiration
    5. Make sure each instance variable is initialized in the constructors
    6. Write the method bodies
    7. Create further tests
  • Steps 4 - 6 may need to be iterated many times
  • Always start with simple test cases or usage examples before writing too much code!
  • zyBook sections 3.3, 3.4, and 3.9
  • Encapsulation: An object's data and implementation details are hidden from clients
    • In particular, we almost always make instance variables private
  • Why encapsulation?
    • Code needs to evolve for bug fixes, performance improvements, feature requests
      • Example: adding a method getTaxableSubtotal to our CashRegister, we eliminated the subtotal instance variable
    • If instance variables are accessible to clients, we can no longer guarantee correctness and consistency of the internal data
      • Example: the tax added should always be consistent with the taxable items entered; if clients can access the tax instance variable, they could (accidentally or maliciously) make the tax inconsistent with the taxable items
  • Unlike local variables, instance variables have default values
    • Numeric variables (including char) default to zero
    • Boolean variables default to false
    • Object variables default to null
  • Instance variables can also be initialied inline using field initializers, if the value does not depend on the constructor parameters
  • zyBook sections 3.5, 3.6, 3.11
Week 2 (August 24 - 28)
  • More about floating point numbers
  • Rounding vs casting
  • Using Integer.parseInt to convert String to number
  • Mathematical methods (functions) from the class Math
  • Calling methods
    • Parameters are the variables appearing in the method declaration
    • Arguments are the values you pass in when calling the method (can be any expression of compatible type)
    • Arguments must match parameters in number, order, and type
  • A method is overloaded if it has multiple versions with different parameters
    • This is how Java gets the effect of "optional" method arguments
  • zyBook sections 2.6 - 2.8
  • Defining constants as public (or private) static final
    • Avoid embedding mysterious literal values in code
  • Instance methods vs static methods
    • A static method is one whose result depends ONLY on the method's arguments
      • Invoked using the class name, as in Math.sqrt(25)
    • An instance method is one whose result depends on the method's arguments AND on the internal state of the "target" object
      • Invoked using an object reference (the "target"), as in name.charAt(3), where name is a String variable
  • Experimenting with String methods
  • Using a Scanner to parse strings
  • Void vs non-void methods
    • Some methods are defined to return a value to the caller, such as Math.sqrt or the String charAt method
    • Some methods are defined to produce a "side-effect" (change the state of the world somehow), such as System.out.println
      • These methods are declared with a return type of void
  • Defining our own static methods
  • zyBook sections 2.9 - 2.12
  • Developing methods incrementally
  • Start with simple, concrete examples
  • Create method stubs for your API
    • Write a simple description for each one
  • Write a few test cases
    • Test early, test often!
  • Use helper methods to reduce duplicated code
  • zyBook sections 2.9 - 2.12
Week 1 (August 17 - 21)
  • Introduction
  • Who should take Com S 227?
  • Syllabus overview
Powerpoint slides from first day
  • Log in to Canvas!
  • Read the syllabus!
  • Check out the zyBook!
    • Read section 1.1
  • Try Piazza!
  • Syllabus overview, con't
  • Role of the compiler and the Java Virtual Machine (Java runtime)
  • A first Java program
  • zyBook sections 1.2 - 1.5
  • Introduction to Eclipse
  • A class is a definition for a type of object
    • In our "Hello, World" example, the class itself serves no purpose except as a container for the main method
    • This is not typical of Java classes!
  • Primitive types vs object types
  • Picturing variables: stack frames and the heap
  • Visualizing code execution with Pythontutor
  • Arithmetic operators
  • Integer division and the mod operator %
  • zyBook sections 2.1 - 2.5