Contents
First Defence
Static Checking
Dynamic Checking
Immutability
Second Defence
Localize Bugs through use of packages and methods
Defensive programming/Assertions
2
FIRST DEFENCE: Make Bugs Impossible
Static checking. eliminates many bugs by catching them at compile time.
Static checking is typically performed by specialized software tools called static
analyzers or linters. E.g. Checkstyle (works natively with CLI or as plugin for
IDE), UCDetector (Unnecessary Code like dead code). Android lint for Android
Studio. Compiler is also one tool which is integrated in IDE.
These tools can automatically analyze code to detect errors or potential issues,
such as:
syntax errors (missing semicolon, brace, parenthesis, misspelled keyword etc.)
Unused variables (dead code)
Code Duplication
Security vulnerabilities (SQL injection, XSS Vulnerabilities, weak cryptography etc.)
Coding standard violations (naming conventions, indentation etc.)
Style (indentation etc.)
Static checking may also be performed manually by developers or code reviewers
(informal reviews, formal reviews, walkthrough reviews, peer2peer reviews), who
inspect the code for common errors.
Software Construction 3
Example 1: Syntax Error
// Compilation error due to a missing semicolon
public class Example1 {
public static void main(String[] args) {
[Link]("Hello, World!")
}
}
Compiler: Detects a syntax error and prevents
successful compilation due to the missing semicolon.
Linter: May also detect the missing semicolon and
provide early feedback during development.
4
Example 2: Unused Variable
public class Example2 {
public static void main(String[] args) {
int x = 5; // Variable 'x' is declared but not used
[Link]("Hello, World!");
}
}
Compiler: Allows compilation because the code is
syntactically correct.
Linter: May detect the unused variable 'x' and suggest
removing it to improve code maintainability.
5
Example 3: Code Duplication
public class Example3 {
public static void main(String[] args) {
[Link]("Hello, World!");
[Link]("Hello, World!"); // Duplicated code
}
}
Compiler: Does not raise any issues; duplicated code is
syntactically correct.
Linter: May identify code duplication and recommend
refactoring for better maintainability.
6
Example 4: Magic Number
public class Example4 {
public static void main(String[] args) {
int result = 5 * 3; // Magic number (3) without explanation
[Link](result);
}
}
Compiler: Does not raise any issues; arithmetic operation is
syntactically correct.
Linter: May detect the use of magic numbers without
explanation and suggest using named constants for clarity.
7
FIRST DEFENCE: Make Bugs Impossible
Dynamic checking. is the process of verifying the type safety of a
program at runtime.
For example, Java makes array overflow bugs impossible by
catching them dynamically. If you try to use an index outside the
bounds of an array or a List, then Java automatically produces an
error.
Null pointer checking: Java automatically checks for null pointer exceptions
at runtime, which can help prevent errors caused by attempting to dereference
null references.
Garbage collection: Java automatically manages memory allocation and
deallocation using garbage collection, which can help prevent errors caused by
memory leaks
Software Construction 8
Example 1: Array Overflow Checking
public class ArrayExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
try {
// Attempting to access an index outside the bounds of the array
int value = numbers[10];
} catch (ArrayIndexOutOfBoundsException e) {
[Link]("Array index out of bounds: " + [Link]());
}
}
}
9
Example2 : Null pointer Checking
public class NullPointerExample {
public static void main(String[] args) {
String text = null;
try {
// Attempting to access a method on a null reference
int length = [Link]();
} catch (NullPointerException e) {
[Link]("Null pointer exception: " + [Link]());
}
}
}
10
FIRST DEFENCE: Make Bugs Impossible
Immutability (immunity from change) is another design principle that
prevents bugs. An immutable type is a type whose values can never
change once they have been created.
For example, strings if passed, less chances of changing the values. Java
also provides immutable references, such as with keyword final
final char[] vowels = new char[] { 'a', 'e', 'i', 'o', 'u' };
The vowels variable is declared final, but is it really unchanging?
Which of the following statements will be illegal (caught statically by the
compiler),
and which will be allowed?
• vowels = new char[] { 'x', 'y', 'z' };
• vowels[0] = 'z';
Software Construction 11
Second Defence: Localize Bugs
If we can’t prevent bugs, we can try to localize them to a
small part of the program, so that we don’t have to look too
hard to find the cause of a bug. When localized to a single
method or small module, bugs may be found simply by
studying the program text.
The earlier a problem is observed (the closer to its cause),
the easier it is to fix.
Software Construction
12
Second Defence: Localize Bugs
/**
* @param x requires x >= 0
* @return approximation to square root of x
*/
public double sqrt(double x) { ... }
Now suppose somebody calls sqrt with a negative argument.
What’s the best behavior for sqrt?
Since the caller has failed to satisfy the requirement that x
should be nonnegative, sqrt is no longer bound by the terms
of its contract.
Software Construction 13
Second Defence: Localize Bugs
Checking preconditions is an example of defensive
programming. Real programs are rarely bug-free.
Defensive programming offers a way to mitigate the
effects of bugs even if you don’t know where they are.
*/ public double sqrt(double x) {
if (! (x >= 0)) throw new AssertionError(); ...
}
Software Construction
14
ASSERTION
An assertion is made using the assert keyword.
Syntax :
assert condition; OR assert condition : expression;
Here, condition is a boolean expression that we assume to be true
when the program executes.
Enabling Assertions
By default, assertions are disabled and ignored at runtime.
To enable assertions, we use:
java –ea AssertTest
OR
java –enableassertions AssertTest
Software Construction
15
ASSERTION - Example
class Main {
public static void main(String args[]) {
String[] weekends = {"Friday", "Saturday", "Sunday"};
assert [Link] == 2;
[Link]("There are " + [Link] + " weekends in a week");
}
}
Output:
There are 3 weekends in a week
When assertions are enabled and the condition is true, the program executes
normally.
But if the condition evaluates to false while assertions are enabled, JVM throws an
AssertionError, and the program stops immediately.
Exception in thread "main" [Link]
Software Construction
16
ASSERTION – Example 2
class Main {
public static void main(String args[]) {
String[] weekends = {"Friday", "Saturday", "Sunday"};
assert [Link]==2 : "There are only 2 weekends in a week";
[Link]("There are " + [Link] + " weekends in a week");
}
}
Output:
Exception in thread "main" [Link]: There are only
2 weekends in a week
Software Construction
17
switch (vowel) { case 'a':
case 'e':
ASSERTION case 'i':
case 'o':
case 'u':
return "A";
Where to use Assertions
default: [Link]();}
1. Method argument requirements, like we saw for sqrt.
2. Method return value requirements. This kind of assertion is sometimes
called a self check. For example, the sqrt method might square its result to
check whether it is reasonably close to x:
3. Covering all cases. If a conditional statement or switch does not cover
all the possible cases, it is good practice to use an assertion to block the
illegal cases:
public void processOrder(Order order) {
assert order != null : "Order should not be null";
// Process the order
}
Software Construction
18
ASSERTION
Where not to use Assertions
1. Assertions should not be used to replace error messages
2. Assertions should not be used to check arguments in the
public methods as they may be provided by user. Error
handling should be used to handle errors provided by
user.
3. Assertions should not be used on command line
arguments.
Software Construction
19
20
Assertion VS Exception Handling
There are 3 types of environments for a software
Development environment
Test environment
Production environment
Unlike normal exception handling, assertions are
generally disabled at run-time.
Assertion checks are done only during development
and testing. They are automatically removed in the
production code at runtime so that it won’t slow the
execution of the program.
Software Construction
21