As you'll be writing more and more sophisticated programs, creating lines of code that have to execute one line after another in a set sequence will no longer be sufficient. That's where program flow comes in.
In the Hello World program from the last chapter, we said hello to the world. Wouldn't it be nice to be a bit more specific - like saying hello to an actual person? 🙋🏽🙋🏻♂️
Display more specific information if it is available
When starting the program, you may not know the name of a user. So what about something like:
If we know the person's name, display it.
Else keep saying hello to the entire world.
This is what conditions are all about.
How do we get to know the person's name in the first place?
Let's go back to the very first statement that a program executes - the main
function's signature:
public static void main(String[] args) {
Did you notice the String[] args
inside the()
? We have an args
variable defined with the type String[]
, which is an array of String
. What that means is that the main
function is capable of receiving arguments that we can use when the program is started.
Do you recall the command that starts a Java program from the terminal? Going back to our Hello World example from the last chapter, we completed the following steps:
Compile the program with the
javac
command.Run the program with the
java
command.
The magic of sending arguments to your program takes place during the second phase. Instead of just providing the name of the class containing the main
method, you can provide other arguments, separated with a space. Here is what you can do:
$ java hello.HelloWorld Esther
After the name of the class, we added the "Esther" string. When the program starts, this string is contained in the args
array that is part of the main function's signature. However, our original code does not make use of it. We need to change it to:
Check if the
args
array contains a value (Thelength
property provided by arrays may be our friend here).If it does, call the
sayhelloTo
method with the contained value.Else, keep calling the method with the "world " string.
Here is the actual code:
package conditions;
/** This displays:
* - a personalized Hello message if an argument has been sent when running the program
* - The traditional "Hello world!" message if not
* @author The OpenClassrooms Education team
*
*/
public class ConditionalHello {
/** This is where the program starts
*
* @param args arguments sent on the command line
*/
public static void main(String[] args) {
if (args.length==1) {
sayHelloTo(args[0]);
} else {
sayHelloTo("world");
}
}
/** prints a hello message to the provided recipient
*
* @param recipient
*/
private static void sayHelloTo(String recipient) {
System.out.println("Hello " + recipient + "!");
}
}
Let's now:
Compile the code with the
javac
command.Run the program without an argument.
Run the program by appending "Esther" after the name of the class.
$ javac conditions/ConditionalHello.java $ java conditions/ConditionalHello Hello world! $java conditions/ConditionalHello Esther Hello Esther!
It works! Let's learn more on how that conditional if statement really works.
Test your conditions with booleans
In Java, to validate a condition, you use a special data type called boolean
. A variable of the boolean
type can hold only two values: true
or false
. A boolean
is the simplest data type.
In Java, boolean types use true/false pairs. To declare a boolean variable, specify its type as boolean
. Let's declare a couple of boolean variables:
boolean theCourseIsExcellent = true;
boolean theAuthorIsHumble = false;
Makes sense, doesn't it? 😉
What really matters is that the condition that is expressed inside the ()
after the if
keyword must resolve to a boolean
. That condition can be expressed as:
1. A true
or false
value. For instance, if(true)
.
2. A variable of type boolean
. For instance, if(myVar)
where myVar
is of type boolean
.
3. An expression that resolves to a boolean value. That expression can be as simple as the result of a method call.
For instance:
String weather="The weather is good";
weather.startsWith("The weather"); // -> true
startsWith
is a method from the String
class that returns true
if this string starts with the specified prefix. It can therefore be used as a condition.
To produce a boolean
, you can also use comparison operators.
Comparison operators
As the name suggests, comparison operators are used to compare two values. There are six of them:
==
Equal to (exactly the same)!=
Not equal to (different in any way)<
Less than<=
Less than or equal to>
Greater than>=
Greater than or equal to
Here are some examples using numeric comparison:
2 == 2 // -> true
2 == 3 // -> false
4 != 4 // -> false
4 != 5 // -> true
1 < 2 // -> true
1 < 1 // -> false
1 <= 1 // -> true
3 > 4 // -> false
5 > 4 // -> true
5 >= 4 // -> true
Like any other result, it can be assigned to a variable. For instance:
int age=15;
if(age>=21){
// Do something only of age if at least 21
}
Finally, you may want to have more complicated conditions, where the decision depends on the result of a combination of different expressions. This is where you will use logical operators.
Logical operators
These operators allow you to combine boolean values: either specific boolean values or results of expressions. There are three of them:
&&
logical AND
The result is true only when all the participating parts are true.
Ex.: the result ofexpression1 && expression2
will be true only ifexpression1
is true ANDexpression2
is also true.||
logical OR
The result is true when at least one of the participating parts is true.
Ex.: The result ofexpression1 || expression2
will be true ifexpression1
is true ORexpression2
is true. It will also be true if both expressions are true!!
logical NOT
It simply inverts the given expression.
The result of!expression1
is true whenexpression1
is false; the result is false whenexpression1
is true.
Here are some examples:
true && true // true
true && false // false
false && false // false
true || false // true
true || true // true
false || false // false
!true // false
!false // true
Same rules apply when more than two expressions are chained together:
true && true && true // true
true && true && false // false
true || false || false// true
false || false || false// false
Like with numeric operators, the logical operators respect the priority of operations - the inversion operator !
comes first, then AND operator &&
and, finally, OR operator ||
. For example:
false || true && true // true
!false && true || false // true
As with numeric operators, use parentheses ( ()
) to change the order:
(true && false) || true // true
!(true && false || !true) // true
To reinforce what you've learned, can you calculate the result of following expressions?
!true && false
!(true && false)
4 < 3 || 4 >= 4
(!(1 == 2) || 3 != 3) && 35 > 34
To summarize: the general form of a conditional statement in Java is if(condition)
where the condition is either a boolean value, a variable of type boolean
, or the result of any expression that produces a boolean value.
In our Hello World example, we have defined an alternative. What if you want to make more complex decisions, based on several possible values?
Manage a chain of conditions
We've personalized our welcome message but what if we want to please people with more that one first name?
A first possibility is to create a chain of conditions. Here is the general form:
if(condition1) {
// instructions
}
else if(condition2) {
// instructions
}
else {
// instructions
}
In our Hello World example, we could send two strings after the class name when running the program. That would mean that the args
array would contain two elements. We could then send a string containing the concatenation of those two strings to our sayHelloTo
function:
public static void main(String[] args) {
if (args.length==1) {
sayHelloTo(args[0]);
} else if (args.length==2) {
sayHelloTo(args[0] + "-" + args[1]);
} else {
sayHelloTo("world");
}
}
In this example, what our chain really does is evaluate the different values of one particular condition (the size of the args
array). In that case, Java provides a specific construct that only does the evaluation once: the switch
statement.
The switch statement
At times there are circumstances when you have a longer set of conditions to go through and only one can be true
within the sequence. In this case, there is a more convenient technique to use, called switch. Switch uses what's called cases to compare some value to and make a decision whether an associated block of code needs to be executed. Let's rewrite our if/else if/else example using a switch:
public static void main(String[] args) {
switch(args.length) {
case 0: // no argument has been sent
sayHelloTo("world");
break;
case 1: // user has provided one argument on the terminal
sayHelloTo(args[0]);
break;
case 2: // user has provided 2 arguments
sayHelloTo(args[0] + "-" + args[1]);
break;
default: // user has provided more than we can manage!
System.out.println("Sorry, I don't know how to manage more than 2 names!");
}
}
With the switch
statement:
The conditional expression
args.length
is evaluated only once.Each case compares the result of the expression with a specific value.
By default, once a case is evaluated to
true
, all cases bellow are also evaluated (that's cascading). To prevent this, end each case with abreak;
statement.The
default
clause at the end deals with all cases where the result of the expression does not match any case.
The switch
statement makes your intent clearer than a chain of if/else and allows you to evaluate the condition only once. This is cool. 😎 But there's always more available! Yet another data type: enumerations.
Use the enum type
Enumerations are a list of predefined cases that help during development time. They improve code readability and decrease chance of errors. Let's look at an example where we define all possible directions (north, east, south, west) in an enum and make use of them in a switch
. Since switch
needs to cover all the possible cases, we can use two approaches.
The first one is listing all the enum cases in switch
so that we don't have to use the default clause:
public class myDirection {
/** enumerate all possible directions */
enum Direction {
north, east, south, west;
}
/** Find the north */
public static void main(String[] args) {
Direction direction = Direction.north;
switch (direction) {
case north:
System.out.println("You are heading north");
break;
case east:
System.out.println("You are heading east");
break;
case south:
System.out.println("You are heading south");
break;
case west:
System.out.println("You are heading west");
break;
}
}
}
In this case we are covering all directions so we don't need a default
clause.
We can alternatively define a use case where we should only be heading north:
public static void main(String[] args) {
Direction direction = Direction.north;
switch (direction) {
case north:
System.out.println("You are heading north");
break;
default:
System.out.println("You are lost!");
}
}
Summary
Conditions let you execute a block of code only when a provided a
boolean
value, variable, or expression which evaluates totrue
.A way to provide values to a program is by sending arguments on the command line. Those arguments are made available to the
main
function inside theargs
array.Conditional expressions make use of boolean arithmetic, including comparison operators and logical operators.
You can evaluate multiple conditions by chaining if/else if/else statements.
The
switch
statement is a cleaner way to execute based on different possible values of a particular condition.Enumerations let you define a set of possible values to make your code even more clean.
In the next chapter, you will learn another way to manage the flow of your application: loops.