You are on page 1of 68

IBU CEN 221 | Object-Oriented

International Burch University


Programming with Java

Becir Isakovic
Lectures Schedule #1
Week 1 - User input, Printing on screen & Conditional statements

Week 2 - Loops & Basics of methods

Week 3 - Methods, ArrayList data structure, Streams and connecting to the database - Quiz 1

Week 4 - Basics of objects, Encapsulation and Inheritance

Week 5 - More on objects, Abstraction and Polymorphism - Quiz 2

Week 6 - Tables, Sorting & Searching, HashMap data structure, Generics

Week 7 - Lambda functions, Records, Optionals , final keyword, & Preparation for the Midterm Exam -
Quiz 3
Lectures Schedule #2
Week 8 & 9 - MIDTERM

Week 10 - Regular expressions, File Manipulation, Iterators, Reflection & Custom Annotations

Week 11 - Exceptions and Unit Testing

Week 12 - Design Patterns (Quiz 4)

Week 13 - Network Programming & Threads

Week 15 - Graphical user interface (GUI) - (Quiz 5)


Your comments :)
- Professor is expecting us to learn everything in 7 weeks. He kept saying that he will fail us on makeup
exams. He is yelling and demotivating us during lectures. During labs we are not doing anything.
- The professor raises his voice at us in the lecture, the labs are not connected to the lectures, and
therefore we do not have material for exercise to prepare for the quiz or exam because the tasks will not
be similar to the labs and lectures, it is also not fair that the lab groups are on Tuesdays, Wednesdays and
Thursdays , and the last two groups get an identical quiz as the first, where it is to the disadvantage of
those who work on Tuesdays because they do not know what to expect. It would be nice If we could
have some kind of question bank like we had it in the 1st year so it is actually possible to pass the
subject.
Your comments :)
- The test was impossible to do well, too many questions both theory and practical. The tasks from the lab
were pretty much useless. The quiz was also unfair because the first group would have it on Tuesday and
then the last group on Thursday, meaning they got all the answers by that time which were not even
slightly changed.
- The teaching and labs were fine and sufficent for the exam, but since the lms integrated compliers
version is lower than the version that we practice on, we couldnt use some functions like streams which
we did in the lectures and labs and professor emphasized that it will be on the exam and very important,
but we couldnt even use it. The other task was about mysql connection with java, and although sql
injection prevention is a standard i thought it wouldnt be nessesary to do it in exam, and the professor
thought that it was implied and DID NOT say it in the task specifically.
Your comments :)
- The exam was not so hard except a few questions which were not well covered during the lectures, and
on the labs we do not even cover them together we just do them by ourselves and ask for help if needed,
which i think is okay if we are doing th logic stuff and syntax or something.. But on the exam was a
question regarding connecting to database, which was not well covered and explained. The code is not
logical and has to be learnt by heart which i think is nonsense. There was also a lot of tasks for a little
period of time. I had a “ cannot find symbol “ error which is not that big of a mistake, and i got 0 points,
I also think that could be fixed in the future in the sense that the tasks could be partially graded.
Exceptions

- An exception is an event that disrupts the normal flow of the program's


instructions during execution.
- When an exceptional situation arises, an object representing that exception is
thrown, and the normal flow of the program is interrupted.
- This object is an instance of a class that is derived from the java.lang.Throwable
class.
Exception types

- There are two main types of exceptions in Java:


1. Checked Exceptions: These are exceptions that the Java compiler forces you to
handle, either by using a try-catch block or by specifying in the method signature
that the method may throw the exception using the throws keyword. Examples of
checked exceptions include IOException, SQLException, and
FileNotFoundException
Exception types cont.

1. Unchecked Exceptions (Runtime Exceptions): These are exceptions that the


compiler does not require you to handle explicitly. They typically represent
programming errors, such as attempting to access an array index that is out of
bounds or dividing by zero. Examples of unchecked exceptions include
NullPointerException, ArrayIndexOutOfBoundsException, and
ArithmeticException.
Checked exception example

- If we try to to read from a file we will be forced by the compile to handle the
exception that could be returned when reading from file
- We have to handle this exception in order to get rid of the compile time error
- Checked exceptions are those that Java makes you handle at the compile time
(before the program even compiles)
Checked exception example

- There are two ways to handle the checked exception


- By using the try-catch block
- By adding the throws keyword in the method signature
- In first approach we are actually dealing with the exception while in the second
approach we are just saying to Java: “Yes, I’m aware that this code can throw the
exception, but I don’t care, I’m not going to handle it, however I will warn you
that can happen”
- Now, the responsibility of who has to handle the exception, is passed to the
method that called the method that can throw the exception
Checked exception example
public static void main(String[] args) throws FileNotFoundException {
readFile("becir");
readFileThrowable("becir");
}

public static void readFile(String fileName) {


try {
FileReader reader = new FileReader(fileName);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void readFileThrowable(String fileName) throws FileNotFoundException {
FileReader reader = new FileReader(fileName);
}
Unchecked exceptions example

- Let us define a function that will accept a String parameter and print its length
and let us call this function with some parameter
public static void printLength(String myString){
System.out.println(myString.length());
}
public static void main(String[] args) {
printLength(null);
}
Unchecked exception example cont.

- We have called this function with a null value and if we run it it will return us the
NullPointerException
- But we do not have to handle this exception or add the throws declaration to the
method signature as the NullPointerException is the unchecked exception
- The NullPointerException is the subclass of the RuntimeException class and all
subclasses of the RuntimeException class and that class itself are of the
unchecked exception type
Exception cont.

- Let us give the example of an exception


int number = Integer.parseInt("myint");

- The parseInt method expect the parameter of type string that is actually an
number that Java can parse
- However we are sending the text instead of string number and this will cause an
NumberFormatException
Exception cont.

- First and foremost, it is extremely important to develop the habit of reading the
exceptions and figuring out what went wrong in your program
- The debugging is also one of the ways to dive deeper into the program, stop the
program execution and figure out what went wrong with the program
- This is a MUST skill for every software developer
- Even if you the best coder in the world, without being able to interpret the
response returned by a compiler or a Java program, your skills are useless
Exception handling

- So in the previous example, whole program just ‘blow away’


- Exception handling is a mechanism in programming languages, including Java,
that allows developers to deal with unexpected or exceptional situations that may
occur during the execution of a program.
- Exceptions represent runtime errors or exceptional conditions that disrupt the
normal flow of a program.
- Instead of allowing the program to terminate abruptly, exception handling
provides a way to gracefully handle these errors and take appropriate actions.
Exception handling

- So in the previous example, whole program just ‘blow away’


- Exception handling is a mechanism in programming languages, including Java,
that allows developers to deal with unexpected or exceptional situations that may
occur during the execution of a program.
- Exceptions represent runtime errors or exceptional conditions that disrupt the
normal flow of a program.
- Instead of allowing the program to terminate abruptly, exception handling
provides a way to gracefully handle these errors and take appropriate actions.
Exception handling cont.

- The mechanism we are using in order to handle the exceptions is the try-catch
block
- We will put the code that might throw the exception in the try block, and if some
exception occurs, we will handle the exception in the catch block
- If you can recall, from our previous example, once the Java was not able to parse
the string to an integer, the exception was thrown, causing the whole to abort the
execution
- Now, by using the try-catch block, the program will not abort as the exception
was handled
Exception handling cont.

- Example:
try {
int numberParsed = Integer.parseInt("myint");
} catch (NumberFormatException exception){
System.out.println("Unable to cast");
}
- If we run the program it will print to the console: "Unable to cast", but it will not
cause the whole program to crash
- Of course, if the exception is not thrown, the catch block will never execute
Exception handling cont.

- It is important to note that the parameter in the catch block (type of the exception
we are trying to get) uses something called Exception Hierarchy
- This means that your catch block will only catch the exceptions that are of that
particular type or the exceptions that are the subclass of that exception class
- So often, in the catch block you will see that instead of specific exceptions, many
programmers are passing the exception of type Exception
- This will work as all of the exceptions are subclasses of the Exception class
- Let us rewrite our previous example
Exception handling cont.

- Example
try {
int numberParsed = Integer.parseInt("myint");
} catch (Exception exception){
System.out.println("Unable to cast");
}
- So if we go to the official Java documentation for the class
NumberFormatException you will see that this class is extending from the
Exception class
Exception handling cont.

- We refer to the previous example exception handling as an Pokemon Exception


because you gonna catch them all :D
Exception handling cont.
- What is important to note that all Exceptions are also inheriting something called
Throwable
- And there are two types of Throwable:
- Exceptions
- Errors
- Error, usually indicates serious problems that are beyond the control of the
application. Examples include OutOfMemoryError and StackOverflowError.
- In general, application code should not try to catch or handle Error instances as
they indicate the important coding problem that should be addressed.
Exception handling cont.
- When the exception is not handled right immediately where it can cause an error
the exception is passed to the method that called the method that throws an
exception
- We refer to this as an call stack, and the exception goes up in the call stack until it
is eventually handled by the try-catch block
- So now, we will extract the logic for parsing an string to an int into another method,
but the exception handling will not take place into that method, rather we will
handle the exception in the caller method as shown in the following example
Exception handling cont.
public static void main(String[] args) {
try {
int numberParsed = getParsedInt("myInt");
} catch (NumberFormatException exception){
System.out.println("Unable to cast string to integer");
}
}

public static int getParsedInt(String stringNumber){


int numberParsed = Integer.parseInt(stringNumber);
return numberParsed;
}
Exception handling cont.
- Another thing that is useful and important is that you can have as many of the catch
blocks as you need for different types of the exceptions
- This allows us to have the different behaviour based on the type of the exception
that was thrown
- But if you want to have the same behaviour for different types of exceptions you
can use the so called: “multi-catch statement”
- This means that by using the pipe symbol, you can catch multiple exceptions in one
single catch block as shown in the example
Exception handling cont.
- Another thing that is useful and important is that you can have as many of the catch
blocks as you need for different types of the exceptions
- This allows us to have the different behaviour based on the type of the exception
that was thrown
- But if you want to have the same behaviour for different types of exceptions you
can use the so called: “multi-catch statement”
- This means that by using the pipe symbol, you can catch multiple exceptions in one
single catch block as shown in the example
Exception handling cont.
public static int multiCatchParse(String stringNumer) {
try {
int numberParsed = getParsedInt("myInt");
return numberParsed;
} catch (NumberFormatException | NullPointerException e){
System.out.println("Problem happened");
}
return 0;
}
Finally, let us talk about the finally :)
- We can also have something called finally block combined with the try catch block
- The finally block is a code block, that gets executed no matter whether the
exception was thrown or not, it will always execute
- This is extremely useful, for example we want to close our file, no matter if the
write was successful or not
- Also, let us say we are opening the database connection and no matter whether or
not the communication with the database was successful we want to close the
connection
Finally example
public static void main(String[] args) {
try {
int numberParsed = getParsedInt("myInt");
} catch (NumberFormatException nfe){
System.out.println("Unable to cast string to integer");
} catch (NullPointerException npe) {
System.out.println("The NullPointer has been thrown");
} finally {
System.out.println("I'm always executed");
}
}
Exception code execution
- One more important thing to remember is that when certain line of code throws the
exception, the program execution is directed to the catch block and the rest of the
code is not being executed
public static void main(String[] args) {
try {
int numberParsed = getParsedInt("myInt");
System.out.println("This will not be written to the console");
} catch (NumberFormatException nfe){
System.out.println("Unable to cast string to integer");
} catch (NullPointerException npe) {
System.out.println("The NullPointer has been thrown");
} finally {
System.out.println("I'm always executed");
}
Exception code execution
- So the exception was caused by the following line of code
int numberParsed = getParsedInt("myInt");

- And the line after that


System.out.println("This will not be written to the console");

- will not be executed as the program execution was restored at the catch block
Finally
- Finally will be executed no matter what you put in your code
- Even if, in the try or catch block, you return a value, the finally block will be
executed
try {
int numberParsed = getParsedInt("myInt");
System.out.println("This will not be written to the console");
return;
} catch (NumberFormatException nfe){
System.out.println("Unable to cast string to integer");
} catch (NullPointerException npe) {
System.out.println("The NullPointer has been thrown");
} finally {
System.out.println("I'm always executed");
}
Finally example
- So based on the previous knowledge what would be the output of the following
program
public static int finallyExample(){
try {
return 1;
return 1; } catch (Exception e){
return 2;
} finally {
return 3;
}
}
Custom exceptions
- What if we want to throw exception to the user from our code
- We will use the throw syntax with respective exception type
- Let us say we want to build a method that will accept the age: int parameter and
throw the exception if the age is negative

public static void validateAge(int age){


if(age < 0)
throw new InvalidParameterException();
}
Custom exceptions
- We can also pass the message to the generic Exception class if we want to make the
error more readable to anyone who encounters it

public static void validateAge(int age) throws Exception {


if (age < 0)
throw new Exception("Age is less then 0!");
}
Custom exceptions cont.
- Java does have dozens of pre-defined exceptions but sometimes you want to write
your own exceptions like in this case
- We have to create a new class
- The class name should be descriptive (this is the exception that we will be
throwing)
- By the standard, the custom exception class should have the suffix Exception but it
does not have to have it although it is heavily recommended
Custom exceptions cont.
- Let us create our own custom exception and throw it
public class AgeLessThenZeroException extends RuntimeException{}
public static void validateAge(int age) throws AgeLessThenZeroException {
if(age < 0)
throw new AgeLessThenZeroException();
}
- That is it, you have created your custom exception
- One problem is, you cannot pass the custom message as the constructor parameter
Custom exceptions cont.
- If we want to be able to pass the message to our exception we have to implement
the constructor in our exception class
- As we are extending the Exception class we will call its constructor with the
message we are passing to our custom exception constructor as follows
public AgeLessThenZeroException(String message){
super(message);
}
public static void validateAge(int age) throws AgeLessThenZeroException {
if(age < 0)
throw new AgeLessThenZeroException("Hey man, what are you doing");
}
Custom exceptions cont.
- One more useful constructor for our custom exception is one that accepts the cause:
Throwable and again call the parent class constructor with this parameter
- This is particularly useful when the custom exception that you are creating can be
caused by some other exception
- Now, when that happens, and you are throwing your custom exception you can pass
in the Throwable that actually caused this exception to occur
- And whenever our exception gets printed out, it also prints out the root cause for
this exception to happen
Throwable example
- Let us create the constructor in our AgeLessThenZeroException class

public AgeLessThenZeroException(Throwable cause){


super(cause);
}

- Let us say that our AgeLessThenZeroException was caused by the


RuntimeException
public static void validateAgeThrowable(int age) throws
AgeLessThenZeroException {
if(age < 0)
throw new AgeLessThenZeroException(new RuntimeException());
Throwable example
- Now if we run our code, we will see the exception that we throw and also we will
see the throwable (all exceptions are extending the Throwable) that caused our
exception to be thrown
Custom exceptions
- We can also write a constructor that will take both of these as a parameters
message: String, cause: Throwable in case we need a descriptive message and the
cause of the exception as follows
public static void validateAgeThrowableMessage(int age) throws AgeLessThenZeroException {
if(age < 0)
throw new AgeLessThenZeroException("Problem with age again", new RuntimeException());
}
Custom exceptions dilemma
- One more thing is, do we have to extend the Exception class when creating a
custom exceptions? Can I extend the Throwable?
- The answer is yes, you can, but you should not as the convention for it is to extend
the Exception unless you have a really good reason not to
- The conventions are important, so the code is readable to guys who sees it first time
- Sometimes, you will be extending the RuntimeException so you are creating an
unchecked exception but never extend Throwable or Error
- In our example, we should extend the IllegalArgumentException as it is the closest
one to what we are doing
Custom exceptions example
public class AgeLessThenZeroIllegalException extends IllegalArgumentException{
public AgeLessThenZeroIllegalException(String message){
super(message);
}
public AgeLessThenZeroIllegalException(Throwable cause){
super(cause);
}
public AgeLessThenZeroIllegalException(String message, Throwable cause){
super(message, cause);
}
}
Unit testing
- Unit Testing is a type of software testing where individual units or components of a
software are tested. The purpose is to validate that each unit of the software code
performs as expected.
- Unit Testing is done during the development (coding phase) of an application by
the developers.
- Unit Tests isolate a section of code and verify its correctness. A unit, in the OOP
sense may be an individual function, method, procedure, module, or object.
Unit testing cont.
- Unit Testing is important because software developers sometimes try saving time
doing minimal unit testing and this is myth because inappropriate unit testing leads
to high cost Defect fixing during System Testing, Integration Testing and even Beta
Testing after application is built.
- If proper unit testing is done in early development, then it saves time and money in
the end.
Unit testing cont.
- First thing to do, is to download the dependency (library) that we will be using for
performing the unit tests
- There are many different libraries that you can use, but the most widely used is the
JUnit and in order to add it to your project you have to paste following dependency
to your pom.xml file and fetch it from maven repository
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
Unit testing cont.
- In order to add the unit tests to you program you have to do the following:
- Go to the method or the class that you want to test
- Right click in the respective unit you want to test Generate -> Test and popup will
be shown
- Import the needed modules:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

- Next thing is to add the new method for each unit you are testing
Unit testing cont.
Unit testing cont.
- As you might see, the code we are writing is under src/main/java/… while the tests
are in the folder /src/test/java/… and that is the right convention that you will
always be using
- In JUnit a unit test is just a method that is annotated with the @Test annotation
- We always unit that our unit test is a single-purpose test, meaning that it should
only be testing one single thing at a time
- Let us write the test to verify that our sample method add will return us 4 if we
pass add(2, 2) as an arguments
Unit testing example
public class SimpleCalculator {
public int add(int numA, int numB) {
return numA + numB;
}
}

@Test
public void twoPlusTwoEqualsFour() {
SimpleCalculator calculator = new SimpleCalculator();
assertEquals(4, calculator.add(2, 2));
}
Unit testing cont.
- The methods in the unit tests should not be public and always that should be of void return type
- The name of the methods can be whatever you want but in order to obey the convention rules and
should be descriptive and anybody who is reading the method name should be aware of what method
accepts and what is the result of the test
- One note is that the Java for the version 10 does have something called Local Variable Type
Inference that means that it can infer the type without explicitly defining a type by using the var
keyword
- This means that instead of
SimpleCalculator calculator = new SimpleCalculator();
- You can say
var calculator = new SimpleCalculator();
Unit testing cont.
- Each unit test will have one or more assert statements and we will be using them
- If you want to run your unit test, just press the run button next to your test as shown
in the image below
Unit testing fails
- If your unit test fails it will output what was expected assertion and what was
actually returned by the method call
- Let us say that, instead of the + sign in our add method, we put - sign
- The test will fail and we will have the explanation of what happened
JUnit Assertions
- There are many different assert methods that are being used, let us show some of
them
- assertArrayEquals - verifies that the expected and actual arrays are equal
- assertEquals and assertNotEquals- verifies expected input and actual output are equal or not
- assertTrue and assertFalse - verify the supplied conditions are true or false
- assertNull and assertNotNull - verify the supplied conditions are null or not
- assertSame and assertNotSame - verify the supplied inputs are same Objects
- assertAll - This assertion allows the creation of grouped assertions, where all the assertions are
executed and their failures are reported together by using lambdas
- assertThrows - assert if an executable throws the specified exception type.
JUnit Annotation
- The most common annotation that you have to use above every method is @Test
that marks a method as a test method. Without that annotation the method will not
be recognized as a test method.
- @BeforeAll / @AfterAll - methods that will be executed before/after other
methods
- @BeforeEach / @AfterEach - methods that will be executed before/after each
test in the class
- @Disabled - disable the test execution
- @Tag - string that allows grouping of the test or classes. We can select to
execute only those tests tag
JUnit Assertions Examples
@Test
public void whenAssertingArraysEquality_thenEqual() {
char[] expected = { 'J', 'u', 'p', 'i', 't', 'e', 'r' };
char[] actual = "Jupiter".toCharArray();

assertArrayEquals(expected, actual, "Arrays should be equal");


}
@Test
void whenAssertingEquality_thenEqual() {
float square = 2 * 2;
float rectangle = 2 * 2;

assertEquals(square, rectangle);
}
JUnit Assertions Examples
@Test
void whenAssertingEquality_thenNotEqual() {
float square = 2 * 2;
float rectangle = 2 * 3;

assertNotEquals(square, rectangle);
}
void whenAssertingConditions_thenVerified() {
assertTrue(5 > 4, "5 is greater the 4");
assertTrue(null == null, "null is equal to null");
}
JUnit Assertions Examples
@Test
public void givenBooleanSupplier_whenAssertingCondition_thenVerified() {
BooleanSupplier condition = () -> 5 > 6;
assertFalse(condition, "5 is not greater then 6");
}
@Test
void whenAssertingNotNull_thenTrue() {
Object dog = new Object();
assertNotNull(dog, () -> "The dog should not be null");
}
JUnit Assertions Examples
@Test
public void whenAssertingNull_thenTrue() {
Object cat = null;
assertNull(cat, () -> "The cat should be null");
}
@Test
void whenAssertingSameObject_thenSuccessful() {
String language = "Java";
Optional<String> optional = Optional.of(language);
assertSame(language, optional.get());
}
JUnit Assertions Examples
@Test
void whenAssertingSameObject_thenFail() {
String language = "Java";
assertNotSame(language, "Java is great");
}
@Test
void givenMultipleAssertion_whenAssertingAll_thenOK() {
Object obj = null;
assertAll(
"heading",
() -> assertEquals(4, 2 * 2, "4 is 2 times 2"),
() -> assertEquals("java", "JAVA".toLowerCase()),
() -> assertNull(obj, "obj is null")
);
Tests coverage
- Test coverage is a measure used in software testing to assess the extent to which a
set of test cases covers the functionality of a software application. It helps in
evaluating the thoroughness of testing by indicating the percentage of code or
functionalities that have been exercised during testing.
- In the IntelliJ there is also the view for the test coverage that shows the complete
coverage of the code by the tests
- High test coverage does not guarantee the absence of defects, but it can give an
indication of the areas that have been tested and those that may need additional
attention.
Tests coverage
- It is an important metric in software testing to help ensure the reliability and quality
of a software product.
- However, it's crucial to strike a balance, as achieving 100% coverage may not be
practical or necessary in all cases.
- The focus should be on testing critical and high-risk areas of the code.
Hands on experience
- Now we will create one small program that will read a list of songs from the file,
implement custom exceptions in it and create a unit tests for each method
- The code is already publicly available on our course github repository
https://github.com/ibecir/oop-2023
Resources
- https://github.com/ibecir/oop-2023
- https://www.youtube.com/watch?v=1XAfapkBQjk&ab_channel=CodingwithJohn
- https://www.youtube.com/watch?v=bCPClyGsVhc&ab_channel=CodingwithJohn
- https://www.youtube.com/watch?v=OIozDnGYqIU&ab_channel=CodingwithJohn
- https://www.youtube.com/watch?v=vZm0lHciFsQ&ab_channel=CodingwithJohn
- https://www.baeldung.com/junit-assertions#junit5-null
System.out.println("Thanks, bye!");

You might also like