You are on page 1of 175

Java/210 BCS Crash Course

Slides:
by Jonathan Lui & Spencer Lee
http://bit.ly/1n3fNh3

slides prepared by Jonathan Lui & Jeremy Goh


Code repository: https://github.com/SpencerLee/BCS210CrashCourse
Download: https://github.com/SpencerLee/BCS210CrashCourse/archive/master.zip

Extract the zip file to a location of your choice


and open using Intellij
What is Java?
● Object oriented language
- Objects: Car, Wheels, Engine
- use Java code to link them so they can work together
part of

moves

Car part of rotates

Wheel

Engine
What is Java?
● Code you write (.java) -> compiled to Java Byte code (.class) -> run by
Java Virtual Machine which converts it to native code run by your computer

Java code Java compiler Java program


(running on JVM)
What is Java?
● Statically typed language

OOPS!
What can be done with Java?
Make cool Physics simulations (PhET) Make Android apps Build Enterprise Software
How is Java different from Racket?
Your CPU does not understand Racket or Java, so how does it run these
programs?

Racket is an interpreted language:


● interaction window that allows live “interaction” with a running program
● the Racket interpreter is implemented with lower-level languages similar to
Java

Java is a compiled language:


● Java source code is “compiled” into byte codes which are translated into
CPU instructions by the Java Virtual Machine
● Java source code needs to be compiled
Running a Java Program
IDEs (Integrated Development Environment)

● IntelliJ - used in CPSC 210 currently


● Eclipse - used previous terms

features: code autocomplete, dependencies import, error checking, debugging..

Text Editors

● Sublime Text (for people who know what they are doing)
Variables
Now I want my program to remember the result of 1+1 and then multiply it by 2
Let’s create a variable:

(define x (+ 1 1)) int x = 1 + 1;


; defining x to be 1+1

Racket: But in Java, we have to tell the compiler that x


is a variable of type int (integer)
We did not have to tell DrRacket what’s
the type of x
= in Java is called the “assign operator”,
which is the same as define in Racket.
It is NOT the same as the equal sign in Math
Hello World!
//SomeClass.java

public class SomeClass {

public static void main(String[] args) {

System.out.println(“Hello world!”);

}
}
The Main Function
● The glue that ties the different parts of a Java program together
● The function that gets executed at the beginning of a Java program
● Used to call any other functions as needed
Hello World - Dissected
//SomeClass.java

class declaration
public class SomeClass { argument
function name type name
public static void main(String[] args) { function declaration

call a system
System.out.println(“Hello world!”); defined function
argument to function -
} the text to print
}
1+1=?
Okay, let’s have Java do something more useful than saying hello to the world

public class SomeClass {

public static void main(String[] args) {

System.out.println(1 + 1); // this will output 2

}
}
Arithmetic in Java is a little different than in Racket:
(+ 1 1) => 2 1 + 1 => 2
Variables - Mutable
Did I say variables can change?

int x = 5;
System.out.println(x); // outputs 5
x = 6; // re-assignment
System.out.println(x); // outputs 6

Also, note that once a variable has been declared (x is an int), you don’t have
to redeclare it (say it’s an int) in successive “reassigning” of the variable
Primitive Types - numbers
This brings us to the topic of data types:
Let’s start with numbers:

byte stores integers (both +ve and -ve) from -128 to +127

short stores integers (both +ve and -ve) from -32,768 to +32,767

int stores integer (whole) numbers (both +ve and -ve) from
-2,147,483,648 [-231] to +2,147,483,647 [2 31-1]

long stores integers (both +ve and -ve) from -263 to +263-1

Why short or long ? Memory considerations! (later, maybe..)


Primitive Types - numbers
What about Real numbers (3.141592653...............)

float (32-bit)

double (64-bit)

These two have different precision: 3.141593 or 3.1415926534.........

For now, just know there’s these types of number,


you will most likely just use int and double

Now, let’s see what we can do with numbers in Java.


Calculating the area of a circle
Let’s write a main Java program to calculate the area of a circle with radius 5

public class SomeClass {


public static void main(String[] args) {
double pi = 3.14159265;
int radius = 5;
double area = pi * Math.pow(radius, 2);
System.out.println(area);
}
}
Calculating the area of a circle
public class SomeClass {
public static void main(String[] args) {
double pi = 3.14159265;
int radius = 5;
double area = pi * Math.pow(radius, 2);
System.out.println(area);
}
}

A line in Java is an expression. This is different than Racket:


(* pi (expt radius 2))
In Racket, an expression is anything in between ( and )
Calculating the area of a circle
public class SomeClass {
public static void main(String[] args) {
double pi = 3.14159265;
int radius = 5;
double area = pi * Math.pow(radius, 2);
System.out.println(area);
}
}

Finish off a line (expression) with ;

Java codes are run line-by-line.


Calculating the area of a circle
public class SomeClass {
public static void main(String[] args) {
double pi = 3.14159265;
int radius = 5;
double area = pi * Math.pow(radius, 2);
System.out.println(area);
}
}
Assigning variable area with the result of the expression to the right of =
Evaluation:
(1) multiply (*) the value of pi by Math.pow(radius, 2)
(2) assign the result of (1) to variable area
Java Library functions
Wait.. so WHAT is this Math.pow(radius, 2)sorcery..

You have seen expressions like 1 + 2 or variable1 * variable2


+,-,*,/,... are called operators

Where is pow?
So someone extended the Java language by writing a library called Math which has a
function in it for calculating the power

Where to find libraries and documentation?

Java docs
Numbers and Functions - 1
Let’s start bringing together the things we’ve learned so far

We’ll write a program that prints the result of all of the following:

● 32 multiplied by 134
● 76 multiplied by 134
● 134 multiplied by 134
Numbers and Functions - 1
Of course, we can do this:
public static void main(String[] args) {
System.out.println(32 * 134);
System.out.println(76 * 134);
System.out.println(134 * 134);
}

Or even better yet:


public static void main(String[] args) {
int multiplier = 134;
System.out.println(32 * multiplier);
System.out.println(76 * multiplier);
System.out.println(134 * multiplier);
}

both programs print out the results in the console.


Numbers and Functions - 2
WAIT! Since we’re CPSC 110 graduates, we know that abstracting repetitive
codes using functions is the way to go!
So, let’s write a function to help us multiply given number by 134!

Think back to 110: what do you need to write a function?


Signature, Purpose, Stub, Template, Function body
;; Integer -> Integer
;; produces n multiplied by 134
(define (multiply-by-134 n) 0) ; stub

In Java, we incorporate the signature into the function declaration


static int multiplyBy134( int n) {
return 0; // stub
}
Numbers and Functions - 2
return type fn. name input type & argument name

later.. static int multiplyBy134( int n) {


return 0; // stub
}
the value/variable
to return

The code between { and } specifies the body of the function


return ______ ; specifies the result of the function
Done!

public static void main(String[] args) {


System.out.println(multiplyBy134(32));
System.out.println(multiplyBy134(76));
System.out.println(multiplyBy134(134));
}

static int multiplyBy134( int n) {


return n * 134; // stub
}
More arguments
static int multiplyBy134AndAdd( int n, int m) {
return n * 134 + m;
}

Number operators follow PEMDAS, or “order of operations”, like the way you learned Math in grade
school.

For your own peace of mind, you can add (redundant) brackets to prioritize operations:

(n * 134) + m; // same as above

Or if you are deviating from the default order of operations:

n * (134 + m); // whatever in ( ) is executed first


void functions
Now let’s look at a function which does not return a result.
Using the same kind of code as in the Hello World example , let’s put

System.out.println(someStr);

into a function

public class SomeClass {

public static void main(String[] args) {


helloWorld(); // calling helloWorld with no argument
}

//<INSERT YOUR CODE HERE>


}
void functions
Again, let’s start with the function declaration:

doesn’t function doesn’t


return consume any
anything arguments
static void helloWorld() {
System.out.println(“Hello World”);
}

In Java, it’s OK for a function to not return anything, just specify void as the
return type
Done!
public class SomeClass {

public static void main(String[] args) {


helloWorld();
}

static void helloWorld() {


System.out.println(“Hello World”);
}

}
Back to variables
● Variables are just short form ways of remembering previous results
○ Try computing 4! (i.e. 4*3*2*1)
Example 1 - Variables
● Variables are just short form ways of remembering previous results
○ Try computing 4! (i.e. 4*3*2*1)

You probably did this by keeping track of the result so far, modifying it as you
went along

Maybe it looked something like this


result = 4*3
result = result * 2
result = result * 1
result
Why use variables?
● Variables are the building blocks of many programming languages

● They help remember computation


○ just like in the previous example, it is way faster if you know/remember
the answer to 4! = 24, than if you had to compute it

● Variables use memory

● Memory is finite
Declaring a variable
● To declare a variable in Java you need
○ variable type
○ variable name

e.g.
int myFirstVariable;

This will declare a variable named myFirstVariable of type int

*Note: In Java, the convention is to name variables and functions in camelCase


Initializing a variable
Initialization is the first assignment of a variable

We’ll often want to declare a variable and initialize it in one step

int myFirstVariable = 3;

is the same as

int myFirstVariable; // declaration


myFirstVariable = 3; // initialization
Default values
If we don’t initialize the variable to a value, we’ll get a compiler error.

int myFirstVariable;

System.out.println(myFirstVariable); // ERROR

However, static variables (more on this laster) do have a default value. And for
number types, this is 0

static int myFirstStaticVariable;


//…
System.out.println(myFirstStaticVariable);
More Types - String
String declaration:

String s = “hello”;
here, the + operator serves to combine two strings
Appending two strings: together - this is called concatenation

String s = “hello” + “world”; // s => “helloworld”

Yes, this is a little weird. But wait until you see this:

String s = “hello” + 1; // s => “hello1”

+ing String and a number (int, double) gives you a String


More about String
Operations on the String type:

String s = “hello”;

s += “world”; // s => “helloworld”

int len = s.length(); // len => 10

String sub = s.substring(1,5); // sub => “ello”

the dot means we are calling the function


substring which is specific to String variables
String is not primitive!?
Unlike int, String is NOT a primitive type, instead String are Objects.
More on Objects later.

Objects have a default value of null

Declaring a static variable of type String with no value would make the
variable null:

static String s;
//….
System.out.println(s);

Exception in thread "main" java.lang.Error: Unresolved compilation problem:


The local variable s may not have been initialized
null
● default value for objects (but must be static or else compiler error)

● is not itself a type

● usually used to denote the absence of an object


boooooooleans
Is a primitive type like int

boolean myBoolean = true;


myBoolean = false;

Default value is false, so an uninitialized boolean is false

boolean myBool; // myBool => false


if - else if - else
● conditional logic based on some boolean result
● determines which block of code executes

if (<condition1>) {
//executes if condition1 is met
} else if (<condition2>) {
//executes if condition1 is NOT met
// and if condition2 is met
} else {
//catches everything else
//i.e. neither condition1 nor condition2 met
}
Conditions
So what is a condition?

Has to be an expression that returns a boolean, e.g.

x < 0 // x is negative
x >= 42 // x is greater than or equal to 42
x == 134 // x is equal to 134 note the double ==
x != 134 // x is not equal to 134

s.equals(“hello”) // s is the String “hello”


!s.equals(“hello”) // s is not “hello”
== vs .equals()
You might notice that we used a.equals(b) here instead of ==

== is used to compare two primitive types (int, boolean, char)

.equals() is an object method. It is used to compare two objects for equality


Example of an object is Strings (notice the capital!)

Objects (and classes) are discussed later.


Boolean Operators
Combining two or more boolean expressions:

&& (and) || (or)

int x = 42;
String s = “hello”;

x > 0 && s == “hello” // true


x < 0 && s == “hello” // false
x < 0 || s == “hello” // true
x == 42 && s == “hello” && s.length() == 5 // true
x != 42 || s != “hello” // false
Number Checker
Write a program which prints “POSITIVE” if the number is positive,
“NEGATIVE” if the number is negative, or “ZERO” if the number is 0

- live code
Number Checker - Solution
public static void main(String[] args) {
numberChecker(13);
}

public static void numberChecker(int x) {


if(x > 0) {
System.out.println(“POSITIVE”);
} else if (x < 0) {
System.out.println(“NEGATIVE”);
} else {
System.out.println(“ZERO”);
}
}
If..else exercise
String Length Checker

Design a method that takes in a String.

If the string is less than 4 characters long, print the whole string.
If the string is 4-8 characters long, take the first 4 characters and add ‘...’ after.
If the string is more than 8 characters long, print out “String too long”

For example:
lengthChecker(“abcd”) // => “abcd”
lengthChecker(“hello”) // => “hell...”
lengthChecker(“helloworld”) // => “String too long”
Length checker - solution
public static void lengthChecker(String s){
if (s.length() < 4){
System.out.println(s);
}
else if(s.length() >= 4 && s.length() <= 8){
System.out.println(s.substring(0,4) + "...");
}
else{
System.out.println("String too long");
}
}
Iteration vs Recursion
● In Racket, we achieved repetitive behaviour in code using Recursion

● for Java, recursion still exists, but we will be mainly focusing on Iteration

For example:
System.out.println(“hello world”);

Having this line allows us to print out hello world once.


What to do if we want to print out 3 times?
System.out.println(“hello world”);
System.out.println(“hello world”); This works!

System.out.println(“hello world”);
Iteration
But what about 10 times? or 42 times?

There’s no point just typing the same codes 42 times.

We use iteration!

for (int i = 0; i < 42; i++) {


System.out.println(“hello world”);
}

This is a for loop.


for loop
for (int i = 0; i < 42; i++) {

specifies the condition required for the loop to continue


int i = 0; initialize a counter variable
i < 42; as long as this is true, execute the code inside the block
i++; executed after each loop (iteration)

System.out.println(“hello world”);
}
for loops - live code
Write a program to print only the even numbers from 1 to 50

Hint: You can use the counter variable i inside the body of your loop
for loop - solution

for (int i = 1; i <= 50; i++) {


if (i % 2 == 0) { // i is even
System.out.println(i);
}
}

% is the modulo operator - returns the remainder of i divided by 2


another for practice
Write a function that takes in 2 String parameters s, c:

static int countOccurrence(String s, String c)


// given c is a 1-character string

returns an int of how many times c appears in s:

countOccurrence(“string”, “a”); // returns 0


countOccurrence(“world”, “l”); // returns 1
countOccurrence(“hello”, “l”); // returns 2
countOccurrence - solution
static int countOccurrence(String s, String c) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.substring(i, i+1).equals(c)) {
count++;
}
}
return count;
}

count++; is the same as count = count + 1; Also: count += 1;


lexical scoping
Let’s revisit countOccurence():

for (int i = 0; i < s.length(); i++) {


int count = 0;
if (s.substring(i, i+1).equals(c)) {
count++;
}
}

What is the result of count at the end of the for loop?


lexical scoping
Want a variable that can be used both inside AND outside a for block?

Declare and initialize it first outside the block!

static int countOccurance(String s, String c) {


int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.substring(i, i+1).equals(c)) {
count++;
}
}
return count;
}

Same idea for if-else if-else block (and others)!


Another loop: while
Syntax:
while (condition) {
// code to execute if condition evaluates to true
}

Logistic:
● expressions within the block will be executed while condition is true
while - practice 1
Let’s rewrite our first for code using while

for (int i = 0; i < 42; i++) {


System.out.println(“hello world”);
}
while - solution 1
int i = 0;
while (i < 42) {
System.out.println(“hello world”);
i++;
}
while - practice 2
Rewrite countOccurence(String s, String c) using while

static int countOccurence(String s, String c) {


int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.substring(i, i+1).equals(c)) {
count++;
}
}
return count;
}
while - solution 2
static int countOccurance(String s, String c) {
int count = 0;
int i = 0;
while (i < s.length()) {
if (s.substring(i, i+1).equals(c)) {
count++;
}
i++;
}
return count;
}
breaking and early returns
while (true) {
...
}

What happens when this is executed? Infinite loop!

Pretty neat if we have a way to exit the loop early, right?

once you have the answer, no need to do remaining computation


Early return - Example
Write a function that finds the first number between 1 and 100 which is divisible
by 3, 4 and 5, if no such number exists, return -1

static int divisibleBy345() {


return -1; // stub
}
Early return - Example
static int divisibleBy345() {
int i = 1;
int result = -1;
while (i <= 100) {
if (i % 3 == 0 && i % 4 == 0 && i % 5 == 0) {
result = i;
}
i++;
}
return result;
}
What if we extend the search to all positive integers?
while (true) { ... }
Early return
static int divisibleBy345() {
int i = 1;
int result = -1;
while (true) {
if (i % 3 == 0 && i % 4 == 0 && i % 5 == 0 ) {
result = i;
}
i++;
}
return result;
}

What’s the problem with this code?


Early return
When the execution reaches the return keyword, all subsequent codes are
ignored.

How can we use this to our advantage?


static int divisibleBy345() {
int i = 1;

while (true) {
if (i % 3 == 0 && i % 4 == 0 && i % 5 == 0) {

return i;
} this is called early return
i++;
}
}
break
What if there are other things we want to do before returning a result for our
function?
static int divisibleBy345() {
int i = 1;
int result = -1;
while (true) {
if (i % 3 == 0 && i % 4 == 0 && i % 5 == 0) {
result = i;
return result;
}
i++;
}
System.out.println(“The result is ” + result);
}
What’s the problem with this code?
When a result is found, return exits the function
break
break works like return, but it does not exit the function, it only exits the
code block it’s in
static int divisibleBy345() {
int i = 1;
int result = -1;
while (true) {
if (i % 3 == 0 && i % 4 == 0 && i % 5 == 0) {
result = i;
break;
}
i++;
}
System.out.println(“The result is ” + result);
}

... works as expected!


continue
continue skips the remaining lines within the loop block, and continues to the
next iteration. Another way to write divisibleBy345()
static int divisibleBy345() {
int i = 1;
int result = -1;
while (true) {
if (!(i % 3 == 0 && i % 4 == 0 && i % 5 == 0)) {
i++;
continue;
} else {
result = i;
break;
}
}
System.out.println(“The result is ” + result);
}
http://bit.ly/1I9FF0o
● A warm up question in interviews
● Write a program which takes in a number, and prints for each number, x, from 1 to
that number, ONE of the following

○ fizz if x is divisible by 3
○ buzz if x is divisible by 5
○ fizzbuzz if x is divisible by 15
○ x otherwise

e.g. fizzbuzz(3) // => outputs


1
2
fizz
Fizzbuzz - Answer
public static void fizzbuzz(int n) {
for (int i = 1; i <= n; i++) {
String output = “”;
if (i % 3 == 0) {
output += “fizz”;
} else if (i % 5 == 0) {
output += “buzz”;
} else {
output = Integer.toString(i);
}
System.out.println(output);
}
}
Arrays - arbitrary-sized data
int[] myArray = new int[10];

Arrays in Java are like lists in Racket, except:


● Once declared, it has constant size
● All elements in the array must be the same type
● Positional access:

myArray[0] = 10; // setting 0-position to be 10


myArray[0]; // return 10
myArray[9] = 42; // setting 9-position to be 42

myArray[5]; // should output default value for int: 0


Arrays as arguments to fn
You can pass arrays around as arguments to functions:

static void fnThatAcceptsArray(int[] arr) {


// do something with arr
}
“Iterate” over arrays
Now, how do we access every item in a given array?
Using for loops!

static int[] fnThatAcceptsArray(int[] arr) {


for (int i = 0; i < arr.length; i++) {
arr[i] = 42;
}
return arr;
}

This function returns an array with all elements set to 42


Arrays - practice
Write a function which accepts an int array and produces the number of positive
integers in the array.

static int countPositives(int[] arr) {

}
Summing up...
Variables
● are mutable - but must remain in the same type
● must be declared with type (int, String, boolean...) and name
Functions
● must specify return type and types and names of input arguments
● early return
Conditional
● if / else if / else statements
Arrays
● get and set using index number
Loops
● for
● while
Project: hangman
Design a hangman game with Java:

Description:
(1) The program starts with accepting an input for the word to guess (e.g. java)
○ have your partner type in this word
(2) Type a character for your guess
(3) If the character matches one from the guessed word, display it like this:
○ User input: a output: _ a _ a
(4) Repeat (2) - (3) until the whole word is revealed
○ output: java - You guessed it, congratulations!
Bonus: also keep track of attempts, and let player know their score!

Google how to accept user input!


Intro to Classes and Objects
A Class defines the “concept” of an object
What is a Pen?
- it has properties: ink colour, thickness, brand
- it has interaction methods:
- toWrite()
- toSpin()
There can be only one Class or “concept” of what a pen is

An Object is an instance of a Class - e.g. : the many pens that exists in the world
- all Objects of a Class gets its defined properties and methods

There can be many instances or objects of a class


Class
A Class is the blueprint or concept of an Object.
Now, let’s define our blueprint:

public class Dog {

We now taught Java the concept of a Dog.


But all it knows is the name Dog - nothing more, yet..
Object
// Somewhere else outside the Dog class definition

Dog myDog = new Dog();

Looks familiar?
Instead of making a variable with primitive type, we make the variable myDog
belong to the class Dog

new - it’s a Java keyword that creates an instance of the class that follows

Dog() - is the constructor for the class Dog, which creates a Dog object
Class - fields
Now let’s expand our Dog class to include more:

public class Dog {

private String breed;

private String name;

This class has 2 fields - essentially the properties of the object - called breed
and name, both of which are Strings
Class
This is very much like Racket’s struct:

;; Dog is (make-dog String String)


(define-struct dog (breed name))

and the constructor is comparable to:

(make-dog “Cocker Spaniel” “Fido”)

Except:
our default Dog() constructor doesn’t take in any arguments
- we can’t specify values for breed and name of myDog ... YET!
Class - constructor
public class Dog {
private String breed;
private String name;

// totally optional
public Dog() {
// this executes when creating new object
}

This is the constructor. It creates a new instance (object) of the class. This
default, no argument constructor, does not explicitly need to be defined
this
● the keyword this, when used within a class refers to an instance of the
object

● we use dot notation to call a function on an object AND to access its fields
○ this.someField
○ this.someMethod()
Class - constructor
public class Dog {
private String breed;
private String name;

public Dog(String breed, String name) {


this.breed = breed; //referring to instance’s value
this.name = name;
}

Treat the constructor as a function - a special one, thus it can accept any
arguments you desire.
Class - constructor
Creating a new object:

Dog fido = new Dog(“Yorkshire Terrier”, “Fido”);


Methods
Methods are functions which are

● called on an object using dot notation

● defined in the object’s class (or one of its superclasses)


Defining a Method - 1
public class Dog {
//...

public void speak() {


System.out.println(“Woof”);
}

And to call it:

Dog fido = new Dog(“Yorkshire Terrier”, “Fido”);


fido.speak();
Defining a Method - 2
Try writing a method which prints out a dog’s name

public class Dog {


//...
public void speak() {
System.out.println(“Woof”);
}

public void printName() {


System.out.println(this.name);
}

}
Challenge... BST!
Since we are recent 110 graduates... let’s represent a Binary Search Tree
using a Class in Java
2
Recall:
;; BST is one of
;; - false ; if its a leaf
;; - (make-node Integer String BST BST)
; key ;value ;l ;r 1 3

5
BST
public class BST {
private boolean isLeaf; // used instead of “false”
private int key;
private String value;
private BST left; // YES! you can have fields of the same class!
private BST right;
//INSERT CONSTRUCTOR HERE
private String findNode(int key) {
// some recursive/iterative codes to find child
node with key
}
}
But, don’t worry about data structures for 210, you will likely never see them
Members
The fields of a class and its methods are called its members
Access Modifiers - 1
● We can use dot notation to call a method on an object but why not access
its properties

● Why can’t we do this?

public static void main(String[] args) {


Dog fido = new Dog(“Yorkshire Terrier”, “Fido”);
System.out.println(fido.breed); //ERROR!
}
Access Modifiers - 2
Exception in thread "main" java.lang.Error: Unresolved
compilation problem:
The field Dog.breed is not visible

at Test.main(Test.java:7)

● The problem is that we denoted breed as a private field


● private, protected, public are access modifiers which determine how a
class, field or method (i.e. its members) can be accessed
Access Modifiers - Members

This explains why we could use access the breed field in its class but NOT
outside it
Encapsulation
Why do we want to make fields private?
● modular
● more maintainable
● prevents unwanted modifications by code which other people write (or our
own code!)
● abstraction
○ interface
Encapsulation - Example
Q: Let’s say you want to write a program that models a thermometer and
returns its temperature various units of measurement?
Encapsulation - Example
Q: Let’s say you want to write a program that models a thermometer and
returns its temperature various units of measurement?

A: You’d need
● a Thermometer class
● a temperature field

But how would you represent its temperature?


Encapsulation - Example
Whichever unit you choose (Celsius, Kelvin, Fahrenheit), you’ll want to
transform it before returning it

● getFahrenheit()
● getCelsius()
● getKelvin()

Since our implementation of the above methods depends on how we store


temperature in the first place, we don’t want other people’s code to modify it.

We make the temperature field private


private double Temperature
Encapsulation - Example
With this access modifier, developers using our code

● don’t need to know how temperature is stored in our Thermometer class


● can rely on certain public methods to get temperature in various units

This makes the Thermometer code more

● modular
● maintainable
Getters and Setters
We’ll generally want to make fields private

But what if want to provide third party code with a means to alter or get these
properties?

We use GETTERS and SETTERS


Getters and Setters
So if we wanted a way to modify the temperature of a Thermometer, we would
use these methods:

public double getTemperature() {


return this.temperature;
}

public void setTemperature(double someNewTemperature) {


//<SOME CONDITIONAL LOGIC HERE?>
this.temperature = someNewTemperature;
}
static
● the static keyword determines whether a member is associated with an
instance of an object or the class itself
○ class variables

○ class functions
Class Variables - 1
● a variable can be associated with a class

● Generally used for


○ default values of an object’s fields

○ constants
Class Variables - 2
public class Dog {

//note the absence of an access modifier


static int defaultNumberOfLegs = 4;

We call a class variable using dot notation but on the CLASS

Dog.defaultNumberOfLegs
Class Variables - 3
TASK: Add a number_of_legs field to your Dog class and have it set to the
default number of legs in the constructor
Class Variables - 4
public class Dog {

static int defaultNumberOfLegs = 4;


private int numberOfLegs;

public Dog(String breed, String name) {


this.breed = breed;
this.name = name;
this.numberOfLegs = defaultNumberOfLegs;
}

}
Constants
● Declared in the same way except we use the final keyword to denote its
cannot be changed after initialization

● Use SNAKE_CASE

e.g. the scientific name of a dog will never change (nor will the default number
of legs, I’m sure!)

public static final String SCIENTIFIC_NAME = “Canis lupus familiaris”;


Class Functions
● We’ve been using these already - the main method!
● We didn’t need to create an instance of SomeProgram to call main

public SomeProgram {

public static void main(String[] args) {

}
}
Class Variables and Functions - 1
Class functions are often used to access class variables

TASK: Create a PlayStation class with a class variable specifying its brand
name (make it private), and define a class function that prints its brand name

Q: Why might we want the brand name private?


Class Variables and Functions - 2
public class PlayStation {
private static String brand = “Sony”;

public static void getBrandName {


System.out.println(brand);
}
}

● We make brand private because its not something other classes should be
able to change directly
● Maybe the brand could change, but there should be some checks
around that - so create a setter
array: more
Let’s go back to talking about array:

Problem:
Given an array of int[], insert the number 42 to the last non-empty position

add it here

4 6 15 0 0 0 0 0 0 0

Just iterate through the array and find the first 0.


What’s wrong with this?
ArrayList
Introducing... the ArrayList class

ArrayList acts as an Object wrapper to a Java array.

Since it’s an Object, ArrayList gets (very useful) methods.

ArrayList<String> countries = new ArrayList<String>();

<...> encloses the type parameter passed to the class ArrayList.


- specifies that this ArrayList is restricted to String elements
ArrayList
ArrayList<String> countries = new ArrayList<String>();

countries.add(“Canada”); // adds element to end of list


countries.add(“US”);

countries.contains(“Canada”);//returns true if list contains given element

String first = countries.get(0);


// returns the element at index/position 0

String removed = countries.remove(1);


// removes and returns the element at index/position 1
ArrayList - for each
Special flavour of the for loop: for each

for (String name : names) {

System.out.println(name);

Note: for each does not work with primitive array


Java Collection
ArrayList is part of Java Collections - there are more implementation of storing
arbitrary-sized data, each has different properties and efficiencies.
Lists
- positional access

Sets
- no duplicate elements
- no positional guarantee

Queue
- First-in-first-out
Inheritance - 1
● The aim is always to write DRY (Don’t Repeat Yourself) code

● Inheritance helps us DRY out duplicated code across classes

● It also helps us model relationships between classes


Inheritance - an example
TASK: Create a Mac class and a PC class.

For both PC and Mac:


Create a constructor which takes in a screen size. Also create an associated
getter.

PC:
Have the constructor also take in a windows version define associated getter

Mac:
Have the constructor also take in an OS X version, define associated getter
Inheritance - an example
public class Mac {
private double screenSize;
private double OSXName;

public Mac(double screenSize, String OSXName) {


this.screenSize = screenSize;
this.OSXName = OSXName;
}

public double getScreenSize() {


return this.screenSize;
}

public String getOSXName() {


return this.OSXName;
}
}
Inheritance - an example
public class PC {
private double screenSize;
private double WindowsName;

public Mac(double screenSize, String WindowsName) {


this.screenSize = screenSize;
this.WindowsName = WindowsName;
}

public double getScreenSize() {


return this.screenSize;
}

public String getWindowsName() {


return this.WindowsName;
}
}
Inheritance - an example
Consider our two classes, Mac and PC, they both have things in common

● They are computers


● Have a screen size (and lots of other properties in common like processor,
brand, etc.)
● Methods associated with these properties are likely to be repetitive (e.g.
getting the screen size)
● They also have their own unique properties - WindowsName and
OSXName

We should create a Computer class to DRY out our code!


Inheritance - an example
This involves:
● creating a Computer class
● bringing up the screenSize property from Mac and PC and just having it in
the Computer class
● modifying the Mac and PC constructor
Inheritance - an example
public class Computer {
//...
} Computer

public class Mac extends Computer {


//... extends
}
Mac PC
public class PC extends Computer {
//...
}
Inheritance - an example
public class Computer {
private double screenSize;

public Computer(double screenSize) {


this.screenSize = screenSize;
}

public double getScreenSize() {


return this.screenSize;
}
}
Inheritance - an example
public class Mac extends Computer{
private String OSXName;

public class Mac(double screenSize, String OSXName) {


super(screenSize);
this.OSXName = this.OSXName;
}

public String getOSXName() {


return this.OSXName;
}
}
extends
● extends is the keyword used to define an inheritance relationship

public class Mac extends Computer{


//...
}

● We say that Mac is a subclass of Computer


● Or conversely, that Computer is a superclass of Mac
● We also sometimes refer to the relationship as
parent(Computer)-child(mac)
○ NOTE: We can have lineages so parent includes grandparent and
great-grandparent etc.
super
● super is used to call the constructor or method of the superclass
public class Mac extends Computer{
//...

public Mac(double screenSize, String OSXName) {


super(screenSize);
this.OSXName = OSXName;
}

● super sets the superclass’s field


Exercise
TASK: Now try making the changes in the PC class. You’ll need to define the
Computer class as well
Inheritance and Variables - 1
● But wait, how do we actually use variables with inheritance?

● If we wanted to create a Mac object, the variable referring to it could be


either a Mac or Computer!

e.g.

Mac m = new Mac(13.3, “Snow Leopard”);

Computer c = new Mac(13.3, “Snow Leopard”);


Inheritance and Variables - 2
● The type of a variable, its apparent type, determines what methods can be
called on it

c.getScreenSize(); //all good!

m.getScreenSize();
//works through inheritance since a mac is a
//computer
Inheritance and Variables - 2
but if Computer didn’t have a getScreenSize() method
m.getScreenSize(); //works as method in mac class
c.getScreenSize();
// no method since not all computer may be Macs and
// therefore might not have the getScreenSize
method!

● the type of an object, i.e. what is used to construct it, is its actual type, and
determines which implementation of a method (amongst the containing
class itself and its superclasses) gets called
Dispatching - 1
But wait, what if we defined a getScreenSize method for our Mac class

public class Mac extends Computer {


//..
@Override // need this if superclass has same method
public double getScreenSize() {
//<some logic>
}
}

Which method would get called?


Dispatching - 2
● Dispatching is the process by which the compiler determines which
methods of an object get called

● Java has dynamic dispatching

● apparent type determines which methods can get called on it

● actual type determines the implementation of the method called on it


(looking up its inheritance change, until it finds an implementation in a
superclass)
Dispatching - 3
Q: So which implementation of getScreenSize gets called?

Mac m = new Mac(13.3, “Snow Leopard”);


m.getScreenSize();

vs

Computer c = new Mac(13.3, “Snow Leopard”);


c.getScreenSize();
Dispatching - 4
Q: So which implementation of getScreenSize gets called?

Mac m = new Mac(13.3, “Snow Leopard”);


m.getScreenSize(); //implementation in Mac class

vs

Computer c = new Mac(13.3, “Snow Leopard”);


c.getScreenSize(); //implementation in Computer class
Dispatching 5
Q: What if the Mac class didn’t have an implementation of getScreenSize,
which implementation would get called now?

Mac m = new Mac(13.3, “Snow Leopard”);


m.getScreenSize();

vs

Computer c = new Mac(13.3, “Snow Leopard”);


c.getScreenSize();
Dispatching 5
Q: What if the Mac class didn’t have an implementation of getScreenSize,
which implementation would get called now?

Mac m = new Mac(13.3, “Snow Leopard”);


m.getScreenSize(); //Computer version!!!

vs

Computer c = new Mac(13.3, “Snow Leopard”);


c.getScreenSize(); //Computer version
Overriding
● Overriding is when there is a method with the same signature in the
subclass as in a superclass, and the subclass’s implementation modifies it
in some way
○ either adds to it
○ or replaces it altogether
Overriding - In Practice
● Overriding will come into play when you call a method on a variable typed
to the superclass but referencing an object with the subclass type

SuperClass someObject = new SubClass();

someObject.someMethod();

Even though SuperClass may have a definition for someMethod, the


implementation in SubClass will override it and be the one that gets called
Overriding example
public class Mac extends Computer {
//..

//overriding method
public double getScreenSize() {
//<some alternate logic>
}
}
Overriding Example
So now both Computer and Mac have an implementation of
getScreenSize(), which implementation is called in the following code?

Mac m = new Mac(13.3, “Snow Leopard”);


m.getScreenSize();

vs

Computer c = new Mac(13.3, “Snow Leopard”);


c.getScreenSize();
Overriding Example
So now both Computer and Mac have an implementation of getScreenSize(), which
implementation is called in the following code?

Mac m = new Mac(13.3, “Snow Leopard”);


m.getScreenSize();

vs

Computer c = new Mac(13.3, “Snow Leopard”);


c.getScreenSize();

A: The Mac version of getScreenSize is called in both examples. But in the second
example, we say the Mac version overides the Computer version of the method
Overriding and super
super can be used to call the parent’s implementation of some method (same
signature)

We use it when we want to use the parent’s implementation of a method as the


base for the child’s overriding implementation
super - Example
So now we just use super and supplement Computer’s implementation of the
method

public class Mac extends Computer {


//..

public double getScreenSize() {


System.out.println(“I overrode it!”);
return super.getScreenSize();
}
}
Overriding vs Overloading
A typical interview question:

Overloading is when you have multiple functions with the same name but
different argument lists (different types, number of arguments but NOT
argument type)

Overriding is an aspect of OOP which allows a child to provide a different


implementation of a method which is defined in its parent. Both methods must
have the same signature (argument lists, name, return type)
Overloading - 1
● Overloading is when you have methods with the same name but different
parameter lists
○ different number of arguments
○ different types

● Can be used for constructors as well


Overloading - 2
Example

public class Dog {

public void speak() {


System.out.println(“Woof”);
}

public void speak(String name) {


System.out.println(“Woof. Hello to you, “ + name;
}
}
Single vs Multiple inheritance
● Java only provides for single inheritance

● This means that a subclass cannot have two parents at the same
“generation” level, any inheritance relationship must be sequential

A A B

X X

OK in Java OK in C++
Multiple inheritance
Q: What might be some of the problems with multiple inheritance?
Multiple inheritance
Q: What might be some of the problems with multiple inheritance?

Assume that classes B and C define


someMethod()

A myObject = new D();

D.someMethod()

Which version of someMethod gets called?

The diamond problem


Abstract Classes
public abstract class Animal {

An abstract class is a class that cannot be instantiated.


➔ new Animal() doesn’t work.

This is intentional. Because we want objects like Dog, Cat, Whale


not its superclass Animal

But still, we want these animals to share some properties and methods,
hence the use of an abstract class
Class vs Abstract Class
class when you want objects for that class
abstract class when it has some subclass that you want objects for.

An abstract class contains:


● fields
● methods

These are inherited by all its subclasses.


Abstract class: example
public abstract class Animal {
protected boolean hasHair;
protected String eyeColor;

// given current x-pos, produce next x-pos that this runs to


protected abstract int runAlongX(int currentPos);

// animals produce sound


protected void produceSound() {

}
}
Interfaces
Specifies some methods that an Class is required to implement.
<<interface>>
Edible

<<abstract>> <<abstract>>
Plants Animal

Broccoli Chicken Dog


Interface
public interface Edible {
public int getDietaryCalories();
}

Interfaces have
● methods with a signature and no implementation (like an abstract method)
● NO fields

Abstract methods are methods that have no implementation when it’s declared,
waiting to be implemented in a subclass and a class that implements its
interface.
implementing interface
public class Chicken extends Animal implements Edible {

@Override
public int getDietaryCalories() {
return 500;
}

}
Multiple interfaces
A class can implement multiple interfaces!
<<interface>> <<interface>>
Edible Friable

<<abstract>>
<<abstract>>
Plants
Animal

Broccoli Chicken Dog


Multiple interfaces
public class Chicken extends Animal implements Edible, Friable {

@Override
public int getDietaryCalories() { // from Edible
return 500;
}

@Override
public void fry() { // from Friable
System.out.println(“Deep frying...”);
}
}
Abstract Class vs Interface
Remeber:

A class can only inherit from one class (abstract/non-abstract)


A class can implement multiple interfaces.

Use class/abstract class when it’s logically the higher hierarchy of a class.

Use interfaces for specifying what the objects of the class can do.
Example Java built-in interfaces: Sortable, Iterable, Collection (next)
Error (Exception) Handling
Error arises from programs all the time. Consider this program:

public static double divide(int dividend, int divisor) {

return dividend / divisor;

Hmm.. what if we get a divisor of 0

What should we produce?

“error: division by 0” OR... false OR... -1?


Error (Exception) Handling
public static double divide(int dividend, int divisor) {
if (divisor == 0) {
return // INSERT YOUR CODE HERE
} else {
return dividend / divisor;
}
}
What’s wrong with:

“error: division by 0” nope! method’s suppose to return a double


false same
-1 possible, but is it a good idea?
throw Exception
Java provides a way of producing an error:

public static double divide(int dividend, int divisor) {


if (divisor == 0) {
throw new RuntimeException();
} else {
return dividend / divisor;
}
}

throw stops the execution of the method and spits out the Exception.
But. what to do with the exception?
try/catch block
Let’s say we have a code that calls the divide method:
//...
double result = divide(5, 0); // division by 0
System.out.println(result);

If we do nothing about it, we will receive an Exception (or stack trace) that
identifies the place where the exception was thrown.
try/catch block
To make it produce a more user friendly error:

we “try” to run the code and “catch” the exception thrown

try {
double result = divide(5, 0);
System.out.println(result);
} catch (Exception e) {
System.out.println(“Cannot divide by 0”);
}
Exception vs RuntimeException
RuntimeException is a subclass of Exception.

So when to use each?

Exception is checked - any method that throws an unchecked Exception


must declare that it throws the Exception and it must be caught using a
try/catch block further upstream. (next)
Use when you want to require a user of your method to handle it properly.

RuntimeException is unchecked - these are errors that arise from a


programming error in the part of the user of your method.
Use when the user is not expected to recover from the problem.
NullPointerException, ArithmeticException...
checked Exception example
private int balance;

static void withdraw(int amount) {

// reduce the balance by amount, if new balance is < 0


// throw checked Exception

}
checked Exception example
public class Account {
private int balance;
static void withdraw(int amount) throws Exception {

if (balance - amount < 0) {


throw new Exception();
} else {
balance -= amount;
}

}
}
Caller to this function is required to try/catch the exception
checked Exception example
// create new account with initial balance 500
Account myAccount = new Account(500);

try {
myAccount.withdraw(600);
} catch (Exception e) {
System.out.println(“Insufficient funds.”);
}
Exception subclass
What if we want a more specialized Exception for our method?

● Exception could mean anything. It doesn’t tell us if the account is necessarily


in insufficient balance.

Exception is a class.
We can extend the class with a more specialized subclass for our purposes:
InsufficientFundsException
public class InsufficientFundsException extends Exception
{
private int balanceAfterWithdrawal;

public InsufficientFundsException(int afterBal) {


super(“Insufficient Funds.”);
this.balanceAfterWithdrawal = afterBal;
}

// getter and setter for balanceAfterWithdrawal

}
InsufficientFundsException
static void withdraw(int amount) throws
InsufficientFundsException {

int newBal = balance - amount;


if (newBal < 0) {
throw new InsufficientFundsException(newBal);
} else {
balance = newBal;
}

}
InsufficientFundsException
Account myAccount = new Account(500);

try {
myAccount.withdraw(600);
} catch (InsufficientFundsException e) {

System.out.println(e.getMessage());
System.out.println(“After withdrawal balance:” +
e.getBalanceAfterWithdrawal());

}
Advice - Doing well in CPSC 210 and
Beyond
● Write CODE!!! - start a personal project
● Read API documentation
● Read other people’s code
● Code with other’s (when your code gets inadvertently changed, you’ll
realize the importance of access modifiers!)
● Write MORE code!!!

If you need help:

● Feel free to contact us, we would like to help if we can.


● BCS tutors: Eric, Shaylene
● Steve Wolfman’s BCS Office hours
● CPSC 210 resources

You might also like