in28minutes/java-tutorial-for-beginners

Java Tutorial For Beginners with 500 Code Examples

1,915

12 commits

updated Nov 26, 2023

See the code

README

Java Tutorial For Beginners

Welcome to this book on "Learning Java In 150 Steps".

I am Ranga Karanam, and I have more than two decades of programming experience.

I love Programming. One of the aims I had when I started in28minutes was to make learning programming easy. Thanks for helping us provide amazing courses to 300,000 learners across the world.

At In28Minutes, we ask ourselves one question every day: "How do we create awesome learning experiences?"

In this book, you will learn to write object oriented code with Java. You will be exposed to a lot of examples, exercises and tips. We will take up a lot of examples, and try and see how to write code for those in Java.

Help us improve this guide - Fork, Pull Requests, Shares and Likes are recommended!

Table of Contents

Our Approach

We did a study on why students give up on programming?

The popular answer was

Difficulty in writing their first program

Put yourselves in the shoes of a beginner and look at this typical Java Hello World Example.

package com.in28minutes.firstjavaproject; 
public class HelloWorld 
{   
     public static void main(String[] args) {           
            System.out.println("Hello World");   
     } 
}

A Programming Beginner will be overwhelmed by this. I remember how I felt when I saw this almost 20 years back. Stunned.

Why?

  • There are a number of keywords and concepts - package, public, class, static, void, String[] and a lot more..
  • What if the programmer makes a typo? Will he be able to fix it?

We believe that there has to be a better way to learn programming.

  • Why don't we learn programming step by step?
  • Why should it not be a lot of fun?
  • Why don't we solve a lot of problems and learn programming as a result?

This is the approach we took to writing this guide and develop our introductory programming courses for Java and Python.

Do you know? The first 3 hours of our Java Course is available here.

Introduction to Programming with Print-Multiplication-Table

Step 01: First Challenge : The Print-Multiplication-Table (PMT-Challenge)

Learning to program is a lot like learning to ride a bicycle. The first few steps are the most challenging ones.

Once you use this stepwise approach to solve a few problems, it becomes a habit.

In this book, we will introduce you to Java programming by taking on a few simple problems to start off.

Having fun along the way is what we will aim to do.

Are you all geared up, to take on your first programming challenge? Yes? Let's get started then!

Our first programming challenge aims to do, what every kid does in math class: reading out a multiplication table.

The PMT-Challenge

  1. Compute the multiplication table for 5, with entries from 1 to 10.
  2. Display this table.
5 * 1  =  5
5 * 2  = 10
5 * 3  = 15
5 * 4  = 20
5 * 5  = 25
5 * 6  = 30
5 * 7  = 35
5 * 8  = 40
5 * 9  = 45
5 * 10 = 50

As part of solving the multiplication table problem, you will be introduced to:

  • JShell
  • Statements
  • Expressions
  • Variables
  • Literals
  • Conditionals
  • Loops
  • Methods

Summary

In this step, we:

  • Stated our first programming challenge, PMT-Challenge
  • Identified basic Java concepts to learn, to solve this challenge

Step 02: Introducing JShell


JShell is a programming tool, introduced in Java SE 9. JShell is a REPL interface. The term REPL refers to this:

  • 'R' stands for Read; Read the input Java code
  • 'E' means Eval; Evaluate the source code
  • 'P' translates to Print; Print out the result
  • 'L' indicates Loop; Loop around, and wait for the next input

How about starting off exploring Java? Are you game?

Snippet-1: Check the Java programming environment

You can use https://tryjshell.org/ to run the code for the first 25 steps. Or you can Install Java 12+. Here's the troubleshooting section if you face problems.

Launch up command prompt or Terminal.

Let type in java -version on the terminal and press enter.


	in28minutes$>java -version
	java version "x.0.1"
	Java(TM) SE Runtime Environment (build x.0.1+11)
	Java HotSpot(TM) 64-bit Server VM (build x.0.1+11, mixed mode)
	in28minutes$>

A successful execution displays the version of Java installed your system. You need to have atleast Java 9 to pursue this book.

Snippet-2: Launch JShell

You can launch JShell by typing jshell at your terminal.


	in28minutes$>jshell

	|  Welcome to JShell version x.0.1
 	|  For an introduction type: /help intro
	jshell>

When run, this command displays basic information about the installed JShell program. A jshell prompt then appears, which waits for your input.

Snippet-3: Sample JShell input, using a built-in command

The JShell command /help, with a parameter intro, gives you basic guidelines on how you use the tool.


	jshell> /help intro

	|
	| intro
	| The jshell tool allows you to execute Java code, getting immediate results.
	| You can enter a Java definition (variable, method, class, etc), like: int x =8
	| or a Java expression, like: x + x
	| or a Java statement or import.
	| These little chunks of Java code are called 'snippets'.
	| There are also jshell commands that allow you to understand and
	| control what you are doing, like: /list
	|
	| For a list of commands: /help
	
	jshell>

Snippet-4: Evaluating an expression

Type 3+4 at the Jshell prompt


	jshell> 3 + 4
	$1 ==> 7
	jshell>

This was your first real REPL cycle! When you type in 3 + 4, JShell evaluates it and prints the result.

The entity $1 is actually a variable name assigned to the result. We will talk about this later.

Snippet-5: Getting out of JShell

The /exit command terminates the JShell program, and we are back to the terminal prompt.


	jshell> /exit
	|  Goodbye
	
	in28minutes$>

Snippet-6: Again, enter JShell and Exit it!

You can now effortlessly launch, feed code to, and exit from JShell!


	in28minutes$> jshell
	
	|  Welcome to JShell version 9.0.1
	|  For an introduction type: /help intro
	jshell> /exit
	|  Goodbye
	
	in28minutes$>

Summary

In this step, we learned:

  • How to launch JShell from our terminal, and run a few commands on it
  • How to run Java code on the JShell prompt

Step 03: Welcome to Problem Solving

Lets try to break down the PMT-Challenge problem to be able to solve it.

5 * 1  =  5
5 * 2  = 10
5 * 3  = 15
5 * 4  = 20
5 * 5  = 25
5 * 6  = 30
5 * 7  = 35
5 * 8  = 40
5 * 9  = 45
5 * 10 = 50

Here is how our draft steps look like

  • Calculate 5 * 3 and print result as 15
  • Print 5 * 3 = 15 (15 is result of previous calculation)
  • Do this ten times, once for each table entry (going from 1 to 10)

Summary

In this step, we:

  • Broke down the PMT-Challenge problem into sub-problems

Step 04: Introducing Expressions

The first part of solving our PMT-Challenge is to calculate the product of 5 and another number, say 3.

Let's start up jshell and type 5 X 3.


	in28minutes$> jshell

	|  Welcome to JShell version x.0.1
	|  For an introduction type: /help intro
	jshell> 5 X 3
	| Error:
	| ';' expected
	| 5 X 3
	|  ^
	| Error:
	| not a statement
	| 5 X 3
	|   ^
	| Error:
	| ';' expected
	| 5 X 3
	|    ^
	| Error:
	| missing return statement
	| 5 X 3
	| ^---^

You probably look at the symbol 'X' as a multiplier, remembering your school days.

Java does not identify 'X' as the multiplication operator! Java supports multiplication, but only if you use its predefined operator, *.

Let's type in code shown below:

	jshell> 5 * 3
	$1 ==> 15
	jshell>

Success!

Let's look at some terminology:

  • 5 * 3 is an expression.
  • 5 and 3 are operands. They are also called literals or constant values.
  • * is an operator.

Java also has built-in operators to perform other numerical tasks, such as:

  • Addition: +
  • Subtraction: -
  • Division: /
  • Modulo arithmetic: %

The following examples illustrate how to use them.


	jshell> 5 * 10
	$2 ==> 50
	jshell> 5 + 10
	$3 ==> 15
	jshell> 5 - 10
	$4 ==> -5
	jshell> 10 / 2
	$5 ==> 5
	jshell>

Your school math memories are still fresh, and the operators don't seem to disappoint either! +, - and / are your bread-and-butter operators.

% is the modulo operator, which gives you the remainder when integer division is performed.


	jshell> 9 % 2
	$6 ==> 1
	jshell> 8 % 2
	$7 ==> 0
	jshell>

Snippet: Complex Expressions, Anyone?

Java allows you to use more than one operator within an expression.

Let's look at some simple expressions with multiple operators.

 
	jshell> 5 + 5 + 5
	$8 ==> 15
	jshell> 5 + 10 - 15
	$9 ==> 0
	jshell> 5 * 5 + 5
	$10 ==> 30
	jshell> 5 * 15 / 3
	$11 ==> 25

Each of above expressions have two operators and three operands.

Summary

In this step, we:

  • Learned how to construct numeric expressions
  • Discovered that operators are predefined symbols
  • Combined several operators to form larger expressions

Step 05: Programming Exercise PE-1 (With Solutions)

At this stage, your smile tells us that you enjoy evaluating Java expressions. What if we tickle your mind a bit, to make sure it hasn't fallen asleep?

Okay, here comes a couple of programming exercises.

  1. Write an expression to calculate the number of minutes in a day.
  2. Write an expression to calculate the number of seconds in a day.

Solution 1

60 (minutes in an hour) multipled by 24 (hours in a day)


	jshell> 60 * 24
	$1 ==> 1440

Solution 2

60 (seconds in a minute) multipled by 60 (minutes in an hour) multipled by 24 (hours in a day)

$jshell>60 * 60 * 24

$1 ==> 86400

Step 06: Operators

Lets look at a few more examples to understand operators.

Invalid Operators

Let's type in 5 ** 6 followed by 5 $ 6 in JShell

	jshell> 5 ** 6
	| Error:
	| Illegal start of expression
	| 5 ** 6
	|     ^

	jshell> 5 $ 6 
	| Error:
	| ';' expected
	| 5 $ 6
	|  ^
	| Error:
	| not a statement
	| 5 $ 6
	|   ^
	| Error:
	| ';' expected
	| 5 $ 6
	|    ^

	jshell> 5 */ 6
	| Error:
	| Illegal start of expression
	| 5 */ 6
	|     ^
	

JShell was not impressed with our efforts at all!

Java has a set of grammar rules, called its syntax. Code that does not follow these rules throw errors. The compiler informs you by listing the errors, and also provides hints on how you can correct them.

Now, why is an error being thrown?

Operators in Java are all predefined, and limited in number. * is a valid operator, whereas ** and $ were rejected, with error messages.

Understanding Result of Expression with Mixed Types

Let's look at another example:


	jshell> 5 / 2
	$1 ==> 2
	jshell>

Surprise, Surprise! JShell seems to evaluate 5 / 2 to 2 instead of 2.5. Where did we go wrong?

Read what follows, with the biggest magnifying lens you can find:

The result of an expression when evaluated, depends on the operator context. This context is determined by the operands passed to it

There are two kinds of numbers typically used in programming : integer (1,2,3,...) and floating-point (1.1,2.3, 56.7889 etc). These values are represented by different types in Java. Integers are commonly of type int, and the floating-point numbers are double by default.

In the expression 5/2, both 5 and 2 are of type int. So, the result is also of type int.

Let's try with a few floating point numbers:


	jshell> 5.0 / 2.0
	$2 ==> 2.5

Both 5.0 and 2.0 are of type double, the result is double. We get a result of 2.5, as expected.

Let's do a mixed operation - using a floating point number and integer.

	jshell> 5.0 / 2
	$3 ==> 2.5
	jshell>

Among the types int and double, double is considered to be a wider type. When you perform a numeric operation between two types, the result will be of the wider type.

Understanding Precedence of Operators

Let's look at few complex examples of expressions with more than one operator.


	jshell> 5 + 5 * 6
	$1 ==> 35
	jshell> 5 - 2 * 2
	$2 ==> 1
	jshell> 5 - 2 / 2
	$3 ==> 4
	jshell>

Surprised with the results? You might expect 5 + 5 * 6 evaluate to 10 * 6 i.e. 60. Howeever, we got 35!

We write English left-to-right, and carry this habit to calculations as well.

In expressions with multiple operators, the order of sub-expression evaluation depends on operator precedence.

The basic rules for operator precedence are actually quite simple (we will look at other rules a little later).

The operators in the set {*, /, %} have higher precedence than the operators in the set {+, -}.

In the expression 5 + 5 * 6 : 5*6 is evaluated first. So, 5 + 5 * 6 becomes 5 + 30 i.e. 35.

5 - 2 * 2 and 5 - 2 / 2 are evaluated by following the same rules.

Use paranthesis for clear code

Java provides syntax elements, called parentheses ( and ), to group parts of an expression.


	jshell> (5 - 2) * 2
	$4 ==> 6
	jshell> 5 - (2 * 2)
	$5 ==> 1
	jshell>

When you put an expression in parenthesis, it is evaluated first. (5 - 2) * 2 => 3 * 2 => 6.

Parentheses lead to better readability as they reduce confusion and help avoid errors.

The old adage A stitch in time saves nine rings very true here. Use parentheses to make your code easy to read, even when they might not be necessary.

Summary

In this step, we:

  • Discovered that operators are all predefined
  • Learned that result of operation depends on operand types
  • Understood what operator precedence means
  • Used parentheses to group parts of an expression

Step 07: Introducing Console Output

We have computed the product of two literals (as in 5 * 3) in earlier steps.

The next step is to print this result in a customized format - 5 * 3 = 15.

How do we do this?

Let try typing it in into JShell

jshell> 5 * 3 = 15
|  Error:
|  unexpected type
|    required: variable
|    found:    value
|  5 * 3 = 15
|  ^---^

Hmm! Error.

How do we print text?

Java has a built-in utility method called System.out.println(), that displays text on the console.

jshell> System.out.println(3*4)
12

We formed an expression, 3*4, and passed it to System.out.println(), which is a built-in Java method.

System.out.println(3*4) is an example of a statement. It is a method call.

The syntax rules for method calls are quite strict, and all its parts are mandatory.

jshell> System.out.println3*4)
| Error:
| ';' expected
| System.out.println3*4)
|___________________^
| Error:
| cannot find symbol
|       symbol: variable println3
| System.out.println3*4)
| ^---------------------^

jshell> System.out.println 3*4
|  Error:
|  ';' expected
|  System.out.println 3*4
|                    ^
|  Error:
|  cannot find symbol
|    symbol:   variable println
|  System.out.println 3*4
|  ^----------------^

What if we want to print an entry of the Multiplication Table, as part of our solution to PMT-Challenge? In other words, how do we print the exact text 5 * 2 = 10 on the console?


	jshell> System.out.println(5 * 2 = 10)
	| Error:
	| unexpected type
	| required:  variable
	| found:     value
	| System.out.println(5 * 2 = 10)
	|____________________^--------^

You wanted to print 5 * 2 = 10 on the console. However, we see that we cannot pass 5 * 2 = 10 as an argument to System.out.println().

5 * 2 = 10 is not a single value. It is a piece of text with numeric characters, * and =.

In Java, we represent text using String. A String literal is a sequence of characters, enclosed within double quotes: " and ".

	jshell> System.out.println("5 * 2 = 10")
	| 5 * 2 = 10

Congratulations! You have now figured out how to display not just numbers on the console, but text as well!

Summary

In this step, we:

  • Were introduced to the System.out.println() method for console output
  • Used this utility to print a single PMT-Challenge table entry

Step 08: Programming Exercise PE-02

Try and solve the following exercises:

  1. Print Hello World onto the console.

  2. Print 5 * 3, as is.

  3. Print the calculated value of 5 * 3.

  4. Print the number of seconds in a day, using the System.out.println method.

  5. Do a syntax revision for the code that you write for each of the above exercises. In your code, identify the following elements:

    • Numeric and string literals
    • Expressions
    • Operators
    • Operands
    • Method calls

Step 09: Solutions to PE-02

Solution 1


	jshell> System.out.println("Hello World")
	Hello World

Solution 2


	jshell> System.out.println("5 * 3")
	5 * 3
	jshell>

Solution 3


	jshell> System.out.println(5 * 3)
	15

Solution 4


	jshell> System.out.println(60 * 60 * 24)
	86400

Step 10: Whitespace, Case sensitiveness and Escape Characters

The term whitespace refers to any sequence of continuous space, tab or newline characters.

Whitespace

Let's see a few examples of whitespace in action.

Whitespace affects the output when used in-and-around string literals.

jshell> System.out.println("Hello World")
Hello World
jshell> System.out.println("Hello      World")
Hello      World
jshell> System.out.println("HelloWorld")
HelloWorld

Whitespace is ignored by the compiler when used around numeric expressions.


	jshell> System.out.println(24 * 60 * 60)
	86400
	jshell> System.out.println(24    *    60    *    60)
	86400
	jshell>

Case Sensitive

Java is case sensitive.

System.out.println() involve pre-defined Java elements : the System class name, the out variable name,and the println method name. All are case-sensitive. If any character in these names is used with a different case, you get an error.


	jshell> system.out.println("Hello World")
	| Error:
	| package system does not exist
	| system.out.println("Hello World")
	| ^-------^

	jshell> System.Out.println("Hello World")
	| Error:
	| cannot find symbol
	| symbol: variable Out
	| System.Out.println("Hello World")
	| ^------------^

	jshell> System.out.Println("Hello World")
	| Error:
	| cannot find symbol
	| symbol: method Println(java.lang.string)
	| System.out.Println("Hello World")
	| ^---------------------^

	jshell>

Inside a string literal, the case of characters do not cause errors. The literal will be taken in and printed, as-is.

jshell> System.out.println("hello world")
hello world
jshell> System.out.println("HELLO WORLD")
HELLO WORLD

Escape Characters

An escape character is a special symbol, used with another regular symbol to form an escape sequence. In Java, the '\' (back-slash) character plays the role of an escape character. This escape sequence changes the original usage of the symbols.

If you want to print the string delimiter, the " character, you need to escape it with a \. Without it, a " character within a string literal causes an error!


	jshell> System.out.println("Hello "World")
	| Error:
	| ')' expected
	| System.out.println("Hello "World")
	|                            ^

	jshell> System.out.println("Hello \"World")
	Hello "World
	jshell>

The escape sequence \n inserts a newline.


jshell> System. out.println("Hello \n World")
Hello
 World
jshell> System.out.println("Hello n World")
Hello n World
jshell> System.out.println("Hello\nWorld")
Hello 
World
jshell>

The escape sequence \t inserts a tab.


	jshell> System.out.println("Hello \t World")
	Hello    World
	jshell> System.out.println("Hello t World")
	Hello t World
	jshell> System.out.println("Hello\tWorld")
	Hello    World
	jshell>

How do you print a \?

jshell> System.out.println("Hello \ World")
|  Error:
|  illegal escape character
|  System.out.println("Hello \ World")

You would need to escape it with another \. Printing \\ outputs the symbol \ to the console.


	jshell> System.out.println("Hello \\ World")
	Hello \ World
	jshell> System.out.println("Hello \\\\ World")
	Hello \\ World

Summary

In this step, we:

  • Were introduced to method call syntax, with System.out.println()
  • Discovered the uses of whitespace characters
  • Learned about Java escape sequences

Step 11: More On Method Calls

Let's look at method calls with a few more examples.

You know how to invoke a method with a single argument, courtesy System.out.println(3*4). Other scenarios do exist, such as

  • Calling a method without any arguments
  • Calling a method with several arguments

Let's check them out, using the built-in methods in Java Math class.

Method without parameters

In method calls, parentheses are a necessary part of the syntax. Don't leave them out!

Math.random() prints a random real number in the range [0 .. 1], a different one on each call


	jshell> Math.random
	| Error:
	| cannot find symbol
	|    symbol: Math.random
	| Math.random
	| ^------------- ^
	jshell> Math.random()
	$1 ==> 0.0424279106074651_
	jshell> Math.random()
	$2 ==> 0.8696879746593543 
	jshell> Math.random()
	$3 ==> 0.8913591586787125

Method with multiple parameters

How do we call Math.min with two parameters 23 and 45?


	jshell> Math.min 23 45
	| Error
	| cannot find symbol
	| symbol: variable min
	| Math.min 23 45
	| ^---------^
	jshell> Math.min(23 45)
	| Error
	| ')' expected
	| Math.min 23 45
	| ---------------^

While making method calls, the programmer must

  • Enclose all the parameters within parentheses
  • Separate individual parameters within the list, using the comma symbol ','.
	jshell> Math.min(23, 45)
	$4 ==> 23
	jshell> Math.min(23, 2)
	$5 ==> 2
	jshell> Math.max(23, 45)
	$6 ==> 45
	jshell> Math.max(23, 2)
	$7 ==> 2
	jshell>

Math.min() returns the minimum of two given numbers. Math.max() returns the maximum of two given numbers.

Summary

In this step, we:

  • Understood how zero, or multiple parameters are passed during a method call

Step 12: More Formatted Output

System.out.println() can accept one value as an argument at a maximum.

To display the multiplication table for 5 with a calculated value, we need a way to print both numbers and strings.

For this we would need to use another built-in method System.out.printf().

When System.out.printf() is called with a single string argument, it prints some illegible information. For now, it suffices to know, that this information is about the built-in type java.io.PrintStream.

	jshell> System.out.printf("5 * 2 = 10")
	5 * 2 = 10$1 ==> java.io.PrintStream@4e1d422d
	jshell>

The good news is, that if we call the println() method on this, the illegible stuff disappears.


	jshell> System.out.printf("5 * 2 = 10").println()
	5 * 2 = 10

The method System.out.printf() accepts a variable number of arguments:

  • The first argument specifies the print format. This is a string literal, having zero or more format specifiers. A format specifier is a predefined literal (such as %d), that formats data of a particular type (%d formats data of type int).
  • The trailing arguments are expressions,

Lots of theory? Let's break it down. Let's look at an example.

	jshell> System.out.printf("5 * 2 = %d", 5*2).println()
	5 * 2 = 10
	jshell>

System.out.printf("5 * 2 = %d", 5*2).println() gives an output 5 * 2 = 10. %d is replaced by the calculated value of 5*2.

Let's play a little more with printf:


	jshell> System.out.printf("%d %d %d", 5, 7, 5).println()
	5 7 5

Let's try to display a calculated value. In the example below 5*7 is calculated as 35.

	jshell> System.out.printf("%d %d %d", 5, 7, 5*7).println()
	5 7 35

Let's use this to print the output in the format that we want to use for multiplication table:

	jshell> System.out.printf("%d * %d = %d", 5, 7, 5*7).println()
	5 * 7 = 35

Congratulations. We are able to calculate 5*7 and print 5 * 7 = 35 successfully.

Exercise

  1. Print the following output on the console: 5 + 6 + 7 = 18. Use three literals 5, 6, 7. Calculate 18 as 5 + 6 + 7.

Solution


	jshell> System.out.printf("%d + %d + %d = %d", 5, 6, 7, 5 + 6 + 7).println()
	5 + 6 + 7 = 18
	jshell>

Playing with System.out.printf()

In the example below, there are four format specifiers (%d) and only three value arguments 5, 6, 7.


	jshell> System.out.printf("%d + %d + %d = %d", 5, 6, 7).println()
	5 + 6 + 7 = | java.util.MissingFormatArgumentException thrown: Format specifier '%d'
	| at Formatter.format (Formatter.java:2580)
	| at PrintStream.format (PrintStream.java:974)
	| at PrintStream.printf (PrintStream.java:870)
	| at (#52:1)

In a call to System.out.printf(), if the number of format specifiers exceeds the number of trailing arguments, the Java run-time throws an exception.

If the number of format specifiers is less than the number of trailing arguments, the compiler simply ignores the excess ones.


	jshell> System.out.printf("%d + %d + %d", 5, 6, 7, 8).println()
	5 + 6 + 7
	jshell>

More Format Specifiers

String values can be printed in System.out.printf(), using the format specifier %s.


	jshell> System.out.printf("Print %s", "Testing").println()
	Print Testing

Earlier, we used %d to print an int value. You cannot use %d to display floating point values.

	jshell> System.out.printf("%d + %d + %d", 5.5, 6.5, 7.5).println()
	| java.util.IllegalFormatConversionException thrown: d != java.lang.Double
	| at Formatter$FormatSpecifier.failedConversion(Formatter.java:4331)
	| at Formatter$FormatSpecifier.printInteger(Formatter.java:2846)
	| at Formatter$FormatSpecifier.print(Formatter.java:2800)
	| at Formatter.format(Formatter.java:2581)
	| at PrintStream.format(PrintStream.java:974)
	| at PrintStream.print(PrintStream.java:870)
	| at #(57:1)

Floating point literals (or expressions) can be formatted using %f.


	jshell> System.out.printf("%f + %f + %f", 5.5, 6.5, 7.5).println()
	5.500000 + 6.500000 + 7.500000
	jshell>

Summary

In this step, we:

  • Discovered how to do formatted output, using System.out.printf()
  • Stressed on the number and sequence of arguments for formatting
  • Explored the built-in format specifiers for primitive types

Step 13: Introducing Variables

In the previous steps, we worked out how to print a calculated value as part of our multiplication table.

	jshell> System.out.printf("%d * %d = %d", 5, 1, 5 * 1).println()
	5 * 1 = 5

How do we print the entire multiplication table?

We can do something like this.

	jshell> System.out.printf("%d * %d = %d", 5, 1, 5 * 1).println()
	5 * 1 = 5
	jshell> System.out.printf("%d * %d = %d", 5, 2, 5 * 2).println()
	5 * 2 = 10
	jshell> System.out.printf("%d * %d = %d", 5, 3, 5 * 3).println()
	5 * 3 = 15
	jshell> System.out.printf("%d * %d = %d", 5, 4, 5 * 4).println()
	5 * 4 = 20
	jshell>

Too much work. Isn't it?

If you carefully observe the code, these statements are very similar.

What's changing? The number in the third and fourth parameter slots changes from 1 to 4.

Wouldn't it be great to have something to represent the changing value?

Welcome variables.


	jshell> int number = 10
	number ==> 10
	jshell>

Terminology and Background

In the statement int number = 10,

  • number is a variable.
  • The literal number is the variable name.
  • The Java keyword int specifies the type of number.
  • The literal 10 provided number with an initial value.
  • This entire statement is a variable definition.

The effects of this variable definition are:

  • A specific location in the computer's memory is reserved for number.
  • This location can now hold data of type int.
  • The value 10 is stored here.

You can change the value of number variable:


	jshell> number = 11
	number ==> 11

Above statement is called variable assignment.

An assignment causes the value stored in the memory location to change. In this case, 10 is replaced with the value 11.

You can look up the value of number variable.

	jshell> number
	number ==> 11

You can change the value of a variable multiple times.

	jshell> number = 12
	number ==> 12
	jshell> number
	number ==> 12

Let's create another variable:


	jshell> int number2 = 100
	number2 ==> 100
	jshell> number2 = 101
	number2 ==> 101
	jshell> number2
	number2 ==> 101
	jshell>

The statement int number2 = 100 defines a distinct variable number2.

How do we use variables to simplify and improve the solution to PMT-Challenge?

Let's take a look.


	jshell> System.out.printf("%d * %d = %d", 5, 4, 5*4).println()
	5 * 4 = 20

Let's define a variable i, and initialize it to 1.

	jshell>int i = 1
	i ==> 1
	jshell> i
	i ==> 1
	jshell> 5*i
	$1 ==> 5

Let's update the multiplication table printf to use the variable i.

	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 1 = 5

How do we print 5 * 2 = 10?

We update i to 2 and execute the same code as before.


	jshell> i = 2
	i ==> 2
	jshell> 5*i
	$2 ==> 10
	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 2 = 10
	jshell>

You can update the value of i to any number.

The previous statement would print the corresponding multiple with 5.


	jshell> i = 3
	i ==> 3
	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 3 = 15
	jshell> i = 10
	i ==> 10_
	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 10 = 50
	jshell>

By varying the value of i, we are able to print different multiples of 5 with the same statement.

Congratulations! You made a major discovery. Variables.

Summary

In this step, we:

  • Understood the need for variables
  • Observed what different parts of a variable definition mean
  • Seen what goes on behind-the-scenes when a variable is defined

Step 14: Programming Exercise PE-03 (With solution)

  1. Create three integer variables a, b and c.
    • Write a statement to print the sum of these three variables.
    • Change the value of a, and then print this sum.
    • Then again, change the value of b and print this sum.

Solution to PE-03


	jshell>int a = 5
	a ==> 5
	jshell>int b = 7
	b ==> 7
	jshell>int c = 11
	c ==> 11
	jshell>System.out.printf("a + b + c = %d", a+b+c).println()
	a + b + c = 23
	jshell>a = 2
	a ==> 2
	jshell>System.out.printf("a + b + c = %d", a+b+c).println()
	a + b + c = 20
	jshell>b = 9
	b ==> 9
	jshell>System.out.printf("a + b + c = %d", a+b+c).println()
	a + b + c = 22
	jshell>
	

Step 15: Using Variables

Variables should be declared before use.


	jshell>newVariable
	| Error:
	| cannot find symbol
	| symbol: newVariable
	| newVariable
	  ^------------^

Java is a strongly typed programming language. This means two things:

  • Every variable in a program must be declared, with a type.
  • Values assigned to a variable should be:
    • same type as the variable's type, or
    • compatible with the variable's type

	jshell> int number = 5.5
	| Error:
	| incompatible types: possible lossy conversion from double to int
	| int number = 5.5
	|_____________^---^
	jshell>

The variable number is an integer, mathematically a number. The constant 5.5 is a number as well.

Why does it result in error?

5.5 is a floating-point number of type double. We are trying to store a double inside a memory slot meant for int.

Let's consider another example:


	jshell> int number = "Hello World"
	| Error:
	| incompatible types: java.lang.String cannot be converted to int
	| int number = "Hello World"
	|_____________^--------------^
	jshell>

number is an int variable, and we are trying to store a String value "Hello World". Not allowed.

Summary

In this step, we:

  • Observed how declaring a variable is important
  • Understood the compatibility rules for basic Java types

Step 16: Variables: Behind-The-Scenes

Giving a value to a variable, during its declaration, is called its initialization.


	jshell> int number = 5
	number ==> 5
	jshell>

The statement int number = 5 combines a declaration and the initialization of number.

The next statement int number2 = number is a little different.


	jshell> int number2 = number
	number2 ==> 5
	jshell> number2
	number2 ==> 5
	jshell>

The initial value for number2 is another variable, which is previously defined (number).

Here's what goes on behind the scenes with int number2 = number:

  • A memory slot is allocated for number2 with size of int.
  • Value stored in number's slot is copied to number2's slot.

In example below, a = 100, c = a + b, a = c are called assignments.


	jshell> int a = 5
	a ==> 5
	jshell> int b = 10
	b ==> 10
	jshell> a = 100
	a ==> 100
	jshell> int c
	c ==> 0
	jshell> c = a + b
	c ==> 110
	jshell> a = c
	a ==> 110
	jshell> int d = b + c
	d ==> 120
	jshell>

Variable assignment is allowed to happen in multiple ways:

  • From a literal value, to a variable, having compatible types. The statement a = 100 is one such example.
  • From a variable to another variable, of compatible types.The statement a = c illustrates this case.
  • From a variable expression to a variable. This expression can be formed with variables and literals of compatible types, and is evaluated before the assignment. The statement c = a + bbelow is an example of this.

An assignment to a constant literal is not allowed.


	jshell> 20 = var
	| Error:
	| unexpected type
	| required : variable
	| found : value
	| 20 = var
	| ^^

	jshell>

Summary

In this step, we discussed how to provide variables with initial values and the basics of assigment.

Step 17: Naming Variables

The syntax rules for variable definition are quite strict. Do we have any freedom with the way we name variables? The answer is "yes", to some extent.

Variable Name Rules

Here are the Java rules for variable names, in a nutshell:

A variable name can be a sequence, in any order, of

  • Letters [A-Z, a-z]
  • Numerical digits [0-9]
  • The special characters '$' ("dollar") and '_' ("underscore")

With the following exceptions:

  • The name cannot start with a numerical digit [0-9]
  • The name must not match with a predefined Java keyword

Let's now see what kinds of errors the compiler throws if you violate these naming rules.

Error : Using a invalid character -


	jshell> int test-test
	| Error:
	| ';' expected
	| int test-test
	|         ^

Error : Starting name of a variable with a number


	jshell> int 2test
	| Error:
	| '.class' expected 
	| int 2test
	|     ^
	| Error:
	| not a statement
	| int 2test
	|      ^--^
	| Error:
	| unexpected type
	| required: value
	| found: class
	| int 2test
	| ^--^
	| Error:
	| missing return statement
	| int 2test
	| ^-------^

	jshell>

Error : Using a keyword as the name of variable

In Java, certain special words are called keywords. For example, some of the data types we looked at - int, double. These keywords cannot be used as variable names.


	jshell> int int
	   ...> ;	
	| Error:
	| '.class' expected
	| int int
	|     ^
	| Error:
	| unexpected type
	| required: value
	| found: class
	| int int
	| ^--^
	| Error:
	| missing return statement
	| int int
	| ^------...

Variable Naming Conventions

Good programmers write readable code. Giving proper names to your variables makes your code easy to read.

In a football scorecard application, using a name s for a score variable is vague. Something like score carries more meaning, and is preferred.


	jshell> int s
	s ==> 0
	jshell> int score
	score ==> 0
	jshell>

The Java community, with its wealth of experience, suggests that programmers follow some naming conventions. Above examples is one of these. Violation of these rules does not result in compilation errors. That's why, these are called conventions.

In Java, another convention is to use CamelCase when we have multiple words in variable name.

 
	jshell> int noOfGoals
	noOfGoals ==> 0

noOfGoals is easier to read than noofgoals.

Both noOfGoals and NoOfGoals are equally readable.

But in Java, the convention followed is to start variable names with a lower case letter. So, for a variable, noOfGoals is preferred.

*** NOT RECOMMENDED***

	jshell> int NoOfGoals
	NoOfGoals ==> 0

Your variable names can be very long.


	jshell> int iThinkThisIsQuiteALongName
	iThinkThisIsQuiteALongName ==> 0
	jshell> int iThinkThisIsSuchALongNameThatIMightNeverUseSuchALongNameAgain
	iThinkThisIsSuchALongNameThatIMightNeverUseSuchALongNameAgain ==> 0

However, avoid using very long variable names.

Use the shortest meaningful and readable name possible for your variables.

Summary

In this step, we:

  • Explored the Java language rules for variable names
  • Understood that there are conventions to guide us
  • Looked at a popular variable naming conventions

Step 18: Introducing Primitive Types

The table below lists the primitive types in Java.

Type of ValuesJava Primitive TypeSize (in bits)Range of ValuesExample
Integral Valuesbyte8-128 to 127byte b = 5;
Integral Valuesshort16-32,768 to 32,767short s = 128;
Integral Valuesint32-2,147,483,648 to 2,147,483,647int i = 40000;
Integral Valueslong64-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807long l = 2222222222;
Floating-Point Valuesfloat32approximately ±3.40282347E+38F. NOT very precise (avoid for financial/scientific math)float f = 4.0f;
Floating-Point Valuesdouble64approximately ±1.79769313486231570E+308. NOT very precise, but better than float (also avoid for financial/scientific math)double d = 67.0;
Character Valueschar16'\u0000 to '\uffffchar c = 'A';
Boolean Valuesboolean1true or falseboolean isTrue = false;

Let's now look at how we create data of these types, and store them in memory.

We choose type for data, based on:

  • The type of data we want to store
  • The range of values we would want to store

Note: In the above examples, we used semi-colon ; character at the end. This is the Java statement separator, which is not mandatory in JShell for single statements. However, it is a must when you use code editors and IDE's, to write Java code.

Integer Types

The only difference among the integer types is their storage capacity.


	jshell> byte b = 5
	b ==> 5
	jshell> short s = 128
	s ==> 128
	jshell> int i = 40000
	i ==> 40000
	jshell> long l = 2222222222
	l ==> 2222222222
	jshell>

Floating Value Types

double is the default type for floating type values with size 64 bits.

	jshell> double d = 67.0
	d ==> 67.0

float occupies 32 bits. float literals need to have a suffix 'f' (as in 4.0f).


	jshell> float f = 4.0f
	f ==> 4.0

If this suffix f is omitted, a floating-point number is assumed to be a double. You cannot store a 64 bit value into 32 bits.

	jshell> float f2 = 4.0
	| Error:
	| incompatible types: possible lossy conversion from double to float
	| float f2 = 4.0
	|            ^-^

You can store float value in double. Remember, both types store similar kind of values and a float value is only 32 bits where as double has 64 bits.

	jshell> double d2 = 67.0f
	d2 ==> 67.0

Character Type

The character type char can store a single character symbol. The symbol must be enclosed within a pair of single quotes, ' and '.


	jshell> char c = 'A'
	c ==> 'A'

Following are a few char declaration errors: Not using single quotes and trying to store multiple characters.

	jshell> char ch = A
	| Error:
	| cannot find symbol
	| symbol: variable A
	| char ch = A
	|           ^

	jshell> char cab = 'AB'
	| Error:
	| unclosed character literal
	| char cab = 'AB'
	|            ^

Boolean Type

The concept of a boolean type is rooted in mathematical logic. The data type can store two possible values, true and false. Both are case-sensitive labels, but not enclosed in quotes.


	jshell> boolean isTrue = false
	isTrue ==> false
	jshell> isTrue = true
	isTrue ==> true
	jshell> boolean isFalse = True
	| Error:
	| cannot find symbol
	| symbol: variable True
	| boolean isFalse = True
	|                   ^--^

	jshell> isFalse = False
	| Error:
	| cannot find symbol
	| symbol: variable False
	| isFalse = False
	|           ^---^

boolean data are mostly used in expressions used to form logical conditions in your code. We will talk more about this - when we explore Java conditionals.

Summary

In this step, we:

  • Looked at the primitive data types provided in Java
  • Understood the categories into which these types are divided
  • Saw what kind of data can be stored in each primitive type

Step 19: Choosing A Data Type

How do we choose the data type for a variable? Let's look at a few examples.

Example 1 : Goals in a Football match

Consider a sports broadcaster that writes a program to track football scores. In a football game there are two teams playing. A game is generally 90 minutes long, with extra time pushing it to 120 minutes at the most. Practically speaking, the scorelines are never huge. From a practical standpoint, the number of goals scored in a match would never exceed 7200 (the number of seconds in 120 minutes). Playing it a bit safe, a short data type would be enough to store the score of each side (though a byte would be more than enough).


	jshell> short numTeamAGoals = 0
	numTeamAGoals ==> 0
	jshell> short numTeamBGoals = 0
	numTeamBGoals ==> 0
	jshell>

Example 2 : How do we store population of the world?

We know that the global count of humans is well over 7 billion now, so the only integer data type that can store it is a long.


	jshell> long globalPopulation = 7500000000;
	globalPopulation ==> 7500000000
	jshell>

Example 3 : How do we store average rainfall in a month?

Rainfall is usually measured in millimeters (mm), and we know computing an average over 30 days is very likely to yield a floating-point number. Hence we can use a float, or for more accuracy, a double to store that average.


	jshell> float avgJanRainfall = 31.77f;
	avgJanRainfall ==> 31.77
	jshell> double averageJanRainfall = 31.77
	averageJanRainfall ==> 31.77
	jshell>

Example 4 : Grades of a Student

Classroom grades in high school are generally A, B, C , ....

For a program that generates a grade report, a char type would be the best bet.


	jshell> char gradeA = 'A'
	gradeA ==> 'A'
	jshell> char gradeB = 'B'
	gradeB ==> 'B'
	jshell> char gradeC = 'C'
	gradeC ==> 'C'
	jshell> char gradeD = 'D'
	gradeD ==> 'D'
	jshell> char gradeF = 'F'
	gradeF ==> 'F'
	jshell>

Example 5 : Is a Number Odd or Even?

A boolean isNumEven is a good bet, with a default initial value of false. It can be changed to true if the number turns out to be even.


	jshell> boolean isNumEven
	isNumEven ==> false
	jshell> isNumEven = true
	isNumEven ==> true
	jshell>

Summary

In this step, we:

  • Understood how to think while choosing a data type
  • Explored cases for integer, floating-point, character and boolean data

Step 20: The Assignment Operator =

We were first exposed to the assignment operator while discussing variable assignment.

We are allowed to use expressions to assign values to variables, using code such as c = a + b.

Let's look at a few additional ways assignment can be done.


	jshell> int i = 10
	i ==> 10
	jshell> int j = 15
	j ==> 15
	jshell> i = j
	i ==> 15
	jshell>

Let's consider the following example:

	jshell> i = i * 2
	i ==> 30
	jshell>

The same variable i appears on both the right-hand-side (RHS) and left-hand-side (LHS). How would that make any sense?

The expression on the RHS is independently evaluated first. The value we get is next copied into the memory slot of the LHS variable.

Using the logic above, the assignment i = i * 2 actually updates the value of i (initially 15) to 30 (doubles it).

Java also does the right thing when it encounters the puzzling statement i = i + i, where i is all over the place! The code doubles the value of i, and this reflects on the JShell output.


	jshell> i = i + i
	i ==> 60

The next example is self explanatory.

	jshell> i = i - i
	i ==> 0

Variable Increment and Decrement

We have already seen increment by assignment:


	jshell> int i = 0
	i ==> 0
	jshell> i = i + 1
	i ==> 1
	jshell> i = i + 1
	i ==> 2
	jshell> i = i + 1
	i ==> 3
	jshell>

Conversely, the statement i = i - 1 is called a variable decrement. This can also be done repeatedly, and i changes value every time.


	jshell> i = i - 1
	i ==> 2
	jshell> i = i - 1
	i ==> 1
	jshell> i = i - 1
	i ==> 0
	jshell>
	

Summary

In this step, we:

  • Looked at the assignment operator = in a more formal way
  • Looked at heavily used scenarios for assignment, such as increment and decrement

Step 21: Assignment Puzzles, and PMT-Challenge revisited

Now that we understand how to define, assign to, and use variables in expressions, it's time to push the boundaries a bit. The following examples explore how we could play around with variables in our code.

Snippet-1 : Pre- and Post- Increment and Decrement

There are two short-hand versions for increment. number++ denotes post-increment. Conversely, ++number means pre-increment.

Operator ++ can be applied only to variables of integer types, which are byte, short, int and long.

number++ is equivalent to the statement number = number + 1


	jshell> int number = 5
	number ==> 5
	jshell> number++
	$1 ==> 5
	jshell> number
	number ==> 6
	jshell> ++number
	$2 ==> 7
	jshell> number
	number ==> 7
	jshell>

number-- is post-decrement. On the other hand, --number is pre-decrement.


	jshell> number--
	$3 ==> 7
	jshell> number
	number ==> 6
	jshell> --number
	$4 ==> 5
	jshell> number
	number ==> 5
	jshell>

What is the difference between prefix and postfix vesions?

Although both prefix and postfix versions achieve the same visible result in above examples, there is a slight difference. We will explore this later.

Snippet-2 : Compound Assignment Operators

The compound assignment operator combines the = with a numeric operator.

i += 2 : Add 2 to the current value of i


	jshell> int i = 1
	i ==> 1
	jshell> i = i + 2
	i ==> 3
	jshell> i += 2
	$1 ==> 5
	jshell>

i -= 1 : Subtract 1 from the current value of i


	jshell> i
	i ==> 5
	jshell> i -= 1
	$2 ==> 4
	jshell> i
	i ==> 4
	jshell>

i *= 4 : Multiply i with 4, and store the result back into i


	jshell> i *= 4
	$3 ==> 20
	jshell> i
	i ==> 20
	jshell>

i /= 4 : Divide i by 4, and store the result back into i


	jshell> i /= 4
	$4 ==> 5
	jshell> i
	i ==> 5
	jshell>

i %= 2 : Divide i by 2, and store the remainder back into i


	jshell> i %= 2
	$5 ==> 1
	jshell> i
	i ==> 1
	jshell>

Summary

In the step, we:

  • Looked at the built-in Java increment and decrement operators
  • Explored the side-effects of prefix and postfix versions of these operators
  • Seen the advantages of compound assignment

Step 22: Some JShell Usage Tips

  • Shortcuts
    1. Toggling to limits of current prompt entry
      • 'Ctrl+a' : to start of line
      • 'Ctrl+e' : to end of line
    2. Moving up and down history of completed prompt inputs
      • up-arrow key : move back in time
      • down-arrow key : move forward in time
    3. Reverse-keyword-search
      • Search for a term, in reverse order of JShell prompt inputs history : input 'Ctrl+r'
      • Scrolling within matches (in reverse order of history) : repeatedly input 'Ctrl+r'
  • /exit : resets and exits the JShell session, clearing all stored variables values.
  • JShell internal variables : $1, $2, and so on.
    • When expressions involving literals and/or previously declared variables are entered as-is, without assignment, those expressions are still evaluated. The result is stored in such an internal variable, and is available for use until the JShell session is reset.
  • Variable Declaration rules relaxation
    1. Single Java statements need not be terminated with the separator ';'.
    2. If multiple statements are entered on a single line at the prompt, successive statements must be separated by the ';'. However, the trailing ';' can still be omitted.

Summary

In this step, we:

  • Explored some useful keyboard shortcuts for JShell commands
  • Understood the idea behind JShell internal variables
  • Observed how JShell reduces typing effort, by relaxing some coding rules

Step 23: Introducing Conditionals - the if

The PMT-Challenge needs us to print a total of 10 table entries. The for loop is a suitable iteration mechanism to get this done. The word loop means exactly what the English dictionary says.

As i varies from 1 through 10, do some stuff involving i

For the PMT-Challenge, do some stuff would be the call to System.out.printf().

The way a for loop is structured is:


	for(initialization; condition; update) {
		statement1;
		statement2;
	}

Here's how above code runs

  1. Execute initialization code.
  2. If condition evaluates to true, execute statements. Else, go out of loop.
  3. Execute update
  4. Repeat 2 and 3

Does it sound complex? Let's break it down.

Let's start with understanding what condition is all about.

Logical Operators

condition represents a logical value(a true or a false).

Turns out Java has a class of logical operators, which can be used with operands within logical expressions, evaluating to a boolean value.

While in school, you probably used the = symbol to compare numbers.

The world of Java is a little different. = is assignment operator. == is the comparison operator.


	jshell> int i = 10
	i ==> 10
	jshell> i == 10
	$1 ==> true
	jshell> i == 11
	$2 ==> false

These are other comparison operators as well, such as < and >.


	jshell> i < 5
	$3 ==> false
	jshell> i > 5
	$4 ==> true

<= and >= are simple extensions.


	jshell> i <= 5
	$4 ==> false
	jshell> i <= 10
	$5 ==> true
	jshell> i >= 10
	$6 ==> true
	jshell>

Conditionals: The "if" Statement

We would want to execute specific lines of code only when a condition is true.

Enter if statement.

An if statement is structured this way:


	if (condition) {
		statement;
	}

statement is executed only if condition evaluates to true.

Typically, all the code that we write is executed always.

In the example below, i is less than 5 is always printed.


	jshell> int i = 10
	i ==> 10
	jshell> System.out.println("i is less than 5")
	i is less than 5

Using the if statement, we can control the execution of System.out.println("i is less than 5");.


	jshell> if (i < 5)
	   ...> System.out.println("i is less than 5");
	jshell> 

The condition i < 5 will evaluate to false, since i is currently 10. Nothing is printed to console.

Let's change i to 4 and execute the if condition.


	jshell> i = 4
	i ==> 4
	jshell> if (i < 5)
	   ...> System.out.println("i is less than 5");
	i is less than 5
	jshell>

i is less than 5 is printed to console.

By controlling the value stored in the variable i, we are able to control whether the statement System.out.println("i is less than 5"); actually runs.

Hurrah! We just achieved conditional execution!

Just as we can compare a variable with a literal, it is possible to compare the values of two variables. The same set of comparison operators, namely ==, <, >, <= and >= can be used.


	jshell> int number1 = 5
	number1 ==> 5
	jshell> int number2 = 7
	number2 ==> 7
	jshell> if (number2 > number1)
	   ...> System.out.println("number2 is greater than number1");
	number2 is greater than number1

	jshell> number2 = 3
	number2 ==> 3
	jshell> if (number2 > number1)
	   ...> System.out.println("number2 is greater than number1");

	jshell>

Summary

In this step, we:

  • Understood the need for a conditionals
  • Were introduced to the concept of logical expressions, and conditional operators
  • Explored usage of the Java if statement

Step 24: Programming Exercise PE-04


  1. Create four integer variables a, b, c and d. Write an if statement to print if the sum of a and b is greater than the sum of c and d.

  2. Store three numerical values as proposed angles of a triangle in integer variables angle1, angle2 and angle3. Create an if statement to state whether these three angles together can form a triangle.

    Hint: A triangle is a closed geometric figure with three angles, whose sum must exactly equal 180 degrees.

  3. Have a variable store an integer. Create an if statement to find out if it's an even number.

    Hint: Use operator %.

Step 25: Solution to PE-04

Solution 1


	jshell> int a = 5
	a ==> 5
	jshell> int b = 7
	b ==> 7
	jshell> int c = 4
	c ==> 4
	jshell> int d = 3
	d ==> 3
	jshell> if (a + b > c + d)
	   ...> System.out.println("a and b together tower above c plus d");
	a and b together tower above c plus d

	jshell>

Solution 2


	jshell> int angleOne = 55
	angleOne ==> 55
	jshell> int angleTwo = 65
	angleOne ==> 55
	jshell> int angleThree = 60
	angleOne ==> 55
	jshell> if (angleOne + angleTwo + angleThree == 180)
	   ...> System.out.println("The three angles together form a triangle");
	The three angles together form a triangle

	jshell> angleThree = 75
	angleOne ==> 55
	jshell> if (angleOne + angleTwo + angleThree == 180)
	   ...> System.out.println("The three angles together form a triangle");

	jshell>

Solution 3


	jshell> int num = 10
	num ==> 10
	jshell> if (num % 2 == 0)
	   ...> System.out.println("The number is even");
	The number is even

	jshell> num++
	num ==> 11
	jshell> if (num % 2 == 0)
	   ...> System.out.println("The number is even");

	jshell>

Step 26: if Statement again

Let's look at a few more examples of if statements.

Snippet-1

Here's a basic example of conditional execution.


	jshell> int i = 5
	i ==> 5
	jshell> if (i == 5)
	   ...> System.out.println("i is odd");
	i is odd

Let's add two statements to the second line.

	jshell> if (i == 5)
	   ...> System.out.println("i is odd"); System.out.println("i is prime");
	i is odd
	i is prime

	jshell>

Both text messages are printed out.

Let's change value of i to 6 and execute again.


	jshell> i = 6
	i ==> 6
	jshell> if (i == 5)
	   ...> System.out.println("i is odd"); System.out.println("i is prime");
	i is prime

	jshell>

i is prime is printed to console. Why?

Why is this statement executed when the condition is false?

The if statement, by default, binds only to the next statement.

It does not control the execution of System.out.println("i is prime");, which in fact runs unconditionally, always.

Is there a way we can ensure conditional execution of a two statements? And more than two?

Snippet-2 : if with statement blocks

We seem to have pulled a rabbit out of the hat here, haven't we! The rabbit lies in the pair of braces : '{' and '}'.

They are used to group a sequence of statements together, into a block. Depending on the condition value (true or false), either all the statements in this block are run, or none at all.


	jshell> int i = 5
	i ==> 5
	jshell> if (i == 5) {
	   ...> System.out.println("i is odd");
	   ...> System.out.println("i is prime");
	   ...> }
	i is odd
	i is prime

	jshell> i = 6
	i ==> 6
	jshell> if (i == 5) {
	   ...> System.out.println("i is odd");
	   ...> System.out.println("i is prime");
	   ...> }

	jshell>

It is considered good programming practice to always use blocks in an if conditional. Here is an example:


	if (i == 5) {
		System.out.println("i is odd");
	}

A block can also consist of a single statement! This improves readability of code.

Summary

In this step, we:

  • Saw the importance of using statement blocks with if conditionals
  • Understood how control flow can be made more readable

Step 27: Introducing Loops: The for Statement

The PMT-Challenge needs us to print a total of 10 table entries. The for loop is a suitable iteration mechanism to get this done.

The word loop means exactly what the English dictionary says. As i varies from 1 through 10, do some stuff involving i

for loop is built this way:


	for(initialization; condition; update) {
		statement1;
		statement1;
	}

Here's how above code runs:

  1. Execute initialization code.
  2. If condition evaluates to true, execute statements. Else, go out of loop.
  3. Execute update
  4. Repeat 2 and 3

We've already seen these components in isolation:

  • initialization : int i = 1
  • condition : i <= 10
  • update : i++

Let's now put them together to get the bigger picture. Here is how it might look:


	for (int i = 1; i <= 10; i++) {
		System.out.println("Hello World");
	}

This loop, when executed, prints the message "Hello World" on a separate line, for a total of 10 times.

Snippet-1 : PMT-Challenge Solution

We need to replace the "Hello World" message with the console print of a table entry. This print is controlled by i taking values from 1 through 10.


	jshell> int i
	i ==> 0
	jshell> for (i=0; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 5, i, 5*i).println();
	   ...> }
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 2
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50

Snippet-1 Explained
  1. The first step is the initialization: i = 1.
  2. After this, the statement System.out.printf("%d * %d = %d", 5, i, 5*i).println(); is executed once.
  3. Then, the update occurs: i++.
  4. Immediately after, the condition i<=10 is evaluated. It returns true. Progress happens. Since it is a for loop, the statement is executed again.
  5. Thereafter, this sequence is executed until i gets a value of 11 (due to successive updates).
  6. The moment i reaches 11, , the condition becomes false. The looping within the for terminates.

Meanwhile, the Multiplication Table for 5, for entries 1 through 10 has been displayed!

Now, wasn't that really elegant? It sure was!

Let's pat ourselves on the back for having reached this stage of learning. This elegant, yet powerful technique (loops) is used in almost every Java program that's written.

Summary

In this step, we:

  • Observed why we need a looping construct, such as the for
  • Understood the mechanism of a for loop
  • Used a for loop in iteration, to solve our PMT-Challenge

Step 28: Programming Exercise PE-05

  1. Repeat the entire process at arriving at the Multiplication Table Print problem, now for the number 7. Start with a fresh JShell session, if you're still using an existing one for quite some time (Rinse, and repeat!).
  2. Use the final solution to print Multiplication Tables for 6 and 10.
  3. Print the integers from 1 to 10.
  4. Print the integers from 10 to 1.
  5. Print the squares of the integers from 1 to 10.
  6. Print the squares of the first 10 even integers.
  7. Print the squares of the first 10 odd integers.

Step 29: Solution to PE-05

Solution 2


	jshell> int i
	i ==> 0
	jshell> for (i=0; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 6, i, 6*i).println();
	   ...> }
	6 * 1 = 6
	6 * 2 = 12
	6 * 3 = 18
	6 * 4 = 24
	6 * 5 = 30
	6 * 6 = 36
	6 * 7 = 42
	6 * 8 = 48
	6 * 9 = 54
	6 * 10 = 60

	jshell> i = 0
	i ==> 0
	jshell> for (i=0; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 10, i, 10*i).println();
	   ...> }
	10 * 1 = 10
	10 * 2 = 20
	10 * 3 = 30
	10 * 4 = 40
	10 * 5 = 50
	10 * 6 = 60
	10 * 7 = 70
	10 * 8 = 80
	10 * 9 = 90
	10 * 10 = 100

Solution 3


	jshell> for (int i=1; i<=10; i++) {
	   ...> System.out.printf(i).println();
	   ...> }
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10

Solution 4

This is the first time we are using i--. Isn't this interesting?


	jshell> for (int i=10; i>0; i--) {
	   ...> System.out.printf(i).println();
	   ...> }
	10
	9
	8
	7
	6
	5
	4
	3
	2
	1

Solution 5


	jshell> for (int i=1; i<=10; i++) {
	   ...> System.out.printf(i*i).println();
	   ...> }
	1
	4
	9
	16
	25
	36
	49
	64
	81
	100

Solution 6

update of a for loop can do a lot of things. Here, we are using i += 2.


	jshell> for (int i=2; i<20; i += 2) 
	   ...> System.out.printf(i*i).println();
	   ...> }
	4
	16
	36
	64
	100
	144
	196
	256
	324
	400

Solution 7


	jshell> for (int i=1; i<=19; i += 2) {
	   ...> System.out.printf(i*i).println();
	   ...> }
	1
	9
	25
	49
	81
	121
	169
	225
	289
	361

Step 30: Puzzling You With for

In the conceptual form of the for construct:


	for (initialization; condition; updation) {
		statement;
		statement;
		//...
		statement;
	}

It may surprise you that each one of initialization, condition, updation and statements block is optional. They can all be left out individually, in combination, or all altogether!! Let's examine a few interesting cases in code.

  1. Empty initialization, Empty Statement

Increments the control variable in quick succession until the condition evaluates to false.


	jshell> int i = 1
	i ==> 1
	jshell> for (; i<=10; i++);
	jshell> i
	i ==> 11
	jshell>

  1. Multiple initializations, Empty Statement

You can have multiple statements in initialization and update separated by ,.


	jshell> int j
	i ==> 11
	jshell> for (i=1, j=2; i<=10; i++, j++);
	jshell> i
	i ==> 11
	jshell> j
	j ==> 12
	jshell>

In the example below, i is incremented and j is decremented.


	jshell> for (i=1, j=2; i<=10; i++, j--);
	jshell> i
	i ==> 11
	jshell> j
	j ==> -8
	jshell>

  1. Infinite Loop

An infinite loop is one where the condition is left empty. An empty condition always evaluates to true. Since a for loop only terminates when the condition becomes false, such a loop this never terminates.

It can only be terminated externally with a keyboard interrupt (CTRL + c).


	jshell> for (;;);

	^C
	jshell>

  1. Statement Block in for

As in case of the if conditional statement, we can have statement blocks in for loops as well. As before, we enclose the statement set between braces ('{' and '}'). The statements are executed repeatedly, in the same order as they appear in the block.


	jshell> for (i=1; i<=5; i++) {
	   ...> System.out.println("No 1");
	   ...> System.out.println("No 2");
	   ...> }
	No 1
	No 2
	No 1
	No 2
	No 1
	No 2
	No 1
	No 2
	No 1
	No 2

Summary

In this step, we saw that all components of a for loop are optional:

  • initialization
  • condition
  • updation
  • statement block

Step 31: A Review Of Basic Concepts

Before we go further, let's quickly get a Big Picture of what we are doing here!

A computer is a machine that does a job for you and me. It is can be used to run tasks that we find complicated, time-consuming, or even boring! For instance, a laptop can play music from a CD, videos from the web, or fire a print job.

We have mobile phones around us, which are mini versions of computers. Then there are others, ranging from blood-sugar monitors to weather-forecast systems. Computers surround us, wherever we go!

Any computer is made up of two basic layers:

  • The hardware: Consists of all the electronic and mechanical parts of the computer, including the electronic circuits.
  • The software: Describes the instructions fed into the computer, which are stored and run on its hardware.

If the human body were a computer,

  • Its hardware would consist of the various organs (such as limbs, blood and heart)
  • Its software would be the signals from the nervous system, which drive these organs.

Computer programming involves writing software instructions to run tasks on a computer. The user who gives these instructions is called the programmer. Often, computer programming involves solving challenging, and very interesting problems.

In the previous steps, we introduced you to the basic Java language concepts and constructs.

We solved a programming challenge, the PMT-Challenge using basic Java constructs.

We used JShell REPL to learn the following concepts, Step by-step:

  • Expressions, Operators and Statements
  • Variables and Formatted Output
  • Conditionals and Loops

At each step, we applied fresh knowledge to enhance our solution to the PMT-Challenge

Hope you liked the journey thus far. Next sections delve deeper into Java features, using the same Step by-step approach. We will catch up again soon, hopefully!

Understanding Methods

Feeling good about where you are right now? You just created an elegant, yet powerful solution to the PMT-Challenge, using:

  • Operators, variables and expressions
  • Built-in formatted output
  • Conditionals for control-flow, and
  • Iteration through loops

And guess what we ended up with? A good-looking display of a Multiplication Table! There's a good chance people in your circles want to see it, use it and maybe share it among their friends.

However, some might be unhappy that it works only for 5, and not for 8 and 7. Maybe it would, but then they would need to type in those lines of code again. This might disappoint them, and your new found popularity would slide downhill.

Surely a more elegant solution exists, a pattern waiting to unravel itself.

Exist it does, and the mechanism to use it lies with Java methods. A method is a feature that allows you to group together a set of statements, and give it a name. This name represents the functionality of that set, which can be re-used when necessary.

A method is essentially a routine that performs a certain task, and can do it any number of times it is asked to. It may also return a result for the task it performs. The syntax for a method definition is along these lines:

ReturnType   methodName () {
  method-body
}

Where

  • methodName is the name of the routine
  • method-body is the set of statements
  • a pair of braces { and } enclose method-body
  • ReturnType is the type of methodName's return value

Summary

In this step, we:

  • Examined the need for labeling code, and its reuse
  • Learned that a Java method fits the bill
  • Saw how a method definition looks like, conceptually

Step 01 : Defining A Simple Method

We will start off, by writing a simple method that prints "Hello World" twice on your screen.


	jshell> void sayHelloWorldTwice() {
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> }
	| created method sayHelloWorldTwice()

A little bit of theory:

  • Above code for the method is called method definition.
  • void indicates that the method does not return any computed result - We will examine return values from methods, a little later.

When the code ran, it didn't exactly welcome us twice, did it? All we got was a boring message from JShell, mumbling created method sayHelloWorldTwice().

That's because defining a method does NOT execute its statement body.

Since the statement block is not stand-alone anymore, its functionality needs to be invoked. This is done by writing a method call.

Let's look at a few examples for method calls.


	jshell> sayHelloWorldTwice
	| Error:
	| cannot find symbol
	| symbol: variable sayHelloWorldTwice
	| sayHelloWorldTwice
	| ^----------------^

	jshell> sayHelloWorldTwice()
	Hello World
	Hello World
	

All that we had to do was to add parantheses to name of the method.

The trailing ';' can be left out in JShell, and is another example of syntax rules being relaxed.

Method names need to follow the same rules as variable names.

Summary

In this step we:

  • Got our hands dirty coding our first method
  • Learned that defining and invoking methods are two different steps

Step 02: Exercise-Set PE-01

Let's now reinforce our basic understanding of methods, by trying out a few exercises.

Exercise Set -5

  1. Write and execute a method named sayHelloWorldThrice to print Hello World thrice.

  2. Write and execute a method that prints the following four statements:

    I've created my first variable

    I've created my first loop

    I've created my first method

    I'm excited to learn Java

Solutions to PE-01

Solution-1


	jshell> void sayHelloWorldThrice() {
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> }
	| created method sayHelloWorldThrice()

	jshell> sayHelloWorldThrice()
	Hello World
	Hello World
	Hello World

Solution-2

 
	jshell> void sayFourThings() {
	   ...> System.out.println("I've created my first variable");
	   ...> System.out.println("I've created my first loop");
	   ...> System.out.println("I've created my first method");
	   ...> System.out.println("I'm excited to learn Java");
	   ...> }
	| created method sayFourThings()

	jshell> sayFourThings()
	I've created my first variable
	I've created my first loop
	I've created my first method
	I'm excited to learn Java

Step 03: Editing A Method Definition (Jshell Tips)

Snippet-01: Editing sayHelloWorldTwice()

	jshell> void sayHelloWorldTwice() {
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> }
	| created method sayHelloWorldTwice()

The /methods command lists out the methods defined in the current session.

	jshell> /methods
	| void sayHelloWorldTwice()
	jshell>

The /list command lists the code of the specified method.


	jshell> /list sayHelloWorldTwice
	59 : void sayHelloWorldTwice() {
	System.out.println("HELLO WORLD");
	System.out.println("HELLO WORLD");
	}
	jshell>

The /edit command allows you to modify the method definition, in a separate editor window.


	jshell> /edit sayHelloWorldTwice
	| modified method sayHelloWorldTwice
	jshell> sayHelloWorldTwice()
	HELLO WORLD
	HELLO WORLD
	jshell>

The /save method takes a file name as a parameter. When run, it saves the session method definitions to a file.

	
	jshell> /save backup.txt
	jshell> /exit
	| Goodbye

in28minutes$>

Summary

In this step, we explored a few JShell tips that make life easier for you while defining methods

Step 04: Methods with Arguments

We wrote the method sayHelloWorldTwice to say Hello World twice. In the programming exercise, we wanted to print Hello World thrice and we wrote a new method sayHelloWorldThrice.

Imagine you're in the Java classroom, where your teacher wants to test your Java skills by saying: "I want you to print Hello World an arbitrary number of times".

Now, that probably would test your patience as well!

How to write a method to print Hello World an arbitrary number of times?

The thing to note is the word "arbitrary", which means the method body should have no clue! This number has to come from outside the method, which can only happen with a method call.

External input to a method is given as a method argument, or parameter.

To support arguments during a call, the concept of a method needs to be tweaked to:


	ReturnType methodName(ArgType argName) {

		method-body

	}

The only addition to the concept of a method, is the phrase

ArgType argName

within the parentheses. argName represents the argument, and ArgType is its type. The next example should clear the air for you.

Snippet-01: Method with an argument: Definition

Let's look at a method definition using an argument numOfTimes.


	jshell> void sayHelloWorld(int numOfTimes) {
	   ...> }
	| created method sayHelloWorld(int)

Let's try to call the method.

	jshell> sayHelloWorld()
	| Error:
	| method sayHelloWorld in class cannot be applied to given types;
	| required : int
	| found : no arguments
	| reason : actual and formal argument lists differ in length
	| sayHelloWorld(
	|^-----------------^
	jshell> sayHelloWorld(1)
	jshell>

Method call must include the same number and types of arguments, that it is defined to have. sayHelloWorld() is an error because sayHelloWorld is defined to accept one parameter. sayHelloWorld(1) works.

However, the method does not do anything. Isn't it sad?

Snippet-02 : Passing and accessing a parameter

The next example will show you how method body code can access arguments passed during a call. Not only that, the argument values can be used during computations.


void sayHelloWorld(int numOfTimes) {
	System.out.println(numOfTimes);
}

System.out.println(numOfTimes) prints the value of argument passed.

A method can be invoked many times within a program, and each time different values could be passed to it. The following example will illustrate this fact.


	jshell> sayHelloWorld(1)
	1
	jshell> sayHelloWorld(2)
	2
	jshell> sayHelloWorld(4)
	4
	jshell> /edit sayHelloWorld
	| modified method sayHelloWorld(int)
	jshell>

Snippet-03: More complex method

Code inside a method can be any valid Java code! For instance, you could write code for iteration, such as a for loop.

Let's look at an example:


	void sayHelloWorld(int numOfTimes) {
		for (int i=1; i<=numOfTimes; i++) {
			System.out.println(numOfTimes);
		}
	}

In the above example, we printed numOfTimes a total of numOfTimes for each method call.

We print 2 two times and 4 four times.


	jshell> sayHelloWorld(2)
	2
	2
	jshell> sayHelloWorld(4)
	4
	4
	4
	4
	jshell>

Snippet-4 : Saying "Hello World", Again and again...

We wanted to print "Hello World" multiple times. Let's update the method:

	void sayHelloWorld(int numOfTimes) {
		for (int i=1; i<=numOfTimes; i++) {
			System.out.println("Hello World");
		}
	}

Isn't this cool?

	jshell> sayHelloWorld(1)
	Hello World
	jshell> sayHelloWorld(2)
	Hello World
	Hello World
	jshell> sayHelloWorld(4)
	Hello World
	Hello World
	Hello World
	Hello World
	jshell>

You can now proudly demonstrate this code to your Java instructor. Your program can print "Hello World" an arbitrary number of times!

What started off giving you a headache, will probably keep you in her good books, for the rest of your course!

Armed with this confidence booster, let's now see how Java treats mistakes you may make. .

Snippet-5 : Parameter type mismatch

Java is a strongly typed language, with strict rules laid out for type compatibility. We saw that with variables, and how they play out with expressions and assignments. The same type compatibility rules are enforced by the compiler, when it needs to match the arguments from method calls with method definition.


	jshell> sayHelloWorld("value")
	| Error:
	| incompatible types: java.lang.String cannot be converted to int
	| sayHelloWorld("value")
	|               ^-----^
	jshell> sayHelloWorld(4.5)
	| Error:
	| incompatible types: possibly lossy conversion from double to int
	| sayHelloWorld(4.5)
	|               ^-^
	jshell>

Summary

In this step, we:

  • Understood why Java supports method arguments, and how we may use them
  • Observed how method arguments lead to convenience and reuse
  • Decided to abide by type compatibility for actual arguments

Step 05: Exercise Set PE-02 (With Solutions)

Exercises

  1. Write a method printNumbers(int n) that prints all successive integers from 1 to n.
  2. Write a method printSquaresOfNumbers(int n) that prints the squares of all successive integers from 1 to n.

Solution-01


	jshell> void printNumbers(int n) {
	   ...> for(int i=0; i< n; i++) {
	   ...> System.out.println(i);
	   ...> }
	   ...> }
	| created method printNumbers(int)
	

jshell>

Solution 2


	jshell> void printSquaresOfNumbers(int n) {
	   ...> for(int i=0; i< n; i++) {
	   ...> System.out.println(i*i);
	   ...> }
	   ...> }
	| created method printSquaresOfNumbers(int)
	jshell>

Step 07: PMT-Challenge Revisited (And Some Puzzles)

A method, in its own right, provides an elegant way to name and reuse a code block. In addition, its behavior can be controlled with parameters.

Can we top-up the existing solution to the PMT-Challenge, with even more elegance? You're right, we're talking about:

  1. Writing a method to print the multiplication table for 5.
  2. Using this method to print the multiplication table for any number.

Want to take a look? Dive right in.

Here's what we did earlier:


	jshell> for (int i=1; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 5, i, 5*i).println();
	   ...> }
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50

Let's wrap this in a method:


	void printMultiplicationTable() {
		for (int i=1; i<=10; i++) {
		System.out.printf("%d * %d = %d", 5, i, 5*i).println();
		}
	}

You can call it to print 5 table.


	jshell> printMultiplicationTable()
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50
	jshell>
	

Summary

In this step, we:

  • Revisited the PMT-Challenge solution we had earlier
  • Enclosed its logic within a method definition, printMultiplicationTable()
  • Haven't fully explored its power yet!

Step 08: Methods With Arguments, And Overloading

The real power of a definition such as printMultiplicationTable() is when we arm it with arguments. Not verbal arguments, but "value" ones. That's right!

We will modify printMultiplicationTable() to have it accept a parameter, which would make it more flexible.

	void printMultiplicationTable(int number) {
		for (int i=1; i<=10; i++) {
			System.out.printf("%d * %d = %d", number, i, number*i).println();
		}
	}

We can now print the multiplication table of any number, by calling the method printMultiplicationTable(number).


	jshell> printMultiplicationTable(6)
	6 * 1 = 6
	6 * 2 = 12
	6 * 3 = 18
	6 * 4 = 24
	6 * 5 = 30
	6 * 6 = 36
	6 * 7 = 42
	6 * 8 = 48
	6 * 9 = 54
	6 * 10 = 60
	jshell>
	

Nothing new to explain here. We have only combined stuff you have been learning so far, most recently adding the flavor of methods to the existing code.

Soak in the power, simplicity and elegance of this program, folks!

Overloaded Methods

It turns out we can call both versions of the method, printMultiplicationTable() and printMultiplicationTable(5) :


	jshell> printMultiplicationTable()
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50
	jshell>

and


	jshell> printMultiplicationTable(5)
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50
	jshell>

You can have multiple methods with same name but different number of parameters. This is called method overloading.

Summary

In this step, we:

  • Enhanced the logic of printMultiplicationTable() by passing arguments
  • Added flexibility to the PMT-Challenge solution
  • Were introduced to the concept of method overloading

Step 09: Methods With Multiple Arguments

It is possible, and pretty useful, to define methods that accept more than one argument.

We have already seen how to call two in-built Java methods, Math.max and Math.min, which accept 2 arguments each.

Time now to enrich our understanding, by writing one such method ourselves as well.

A method void sum(int, int) that computes the sum of two integers, and prints their output.


	jshell> void sum(int firstNum, int secondNum) {
	   ...> int sum = firstNum + secondNum;
	   ...> System.out.println(sum);
	   ...> }
	| created method sum(int, int)
	jshell> sum(5, 10)
	15
	jshell>

A method void sum(int, int, int) that computes the sum of three integers, and prints their output.


	jshell> void sum(int firstNum, int secondNum, int thirdNum) {
	   ...> int sum = firstNum + secondNum + thirdNum;
	   ...> System.out.println(sum);
	   ...> }
	| created method sum(int,int,int)
	jshell> sum(5, 10, 15)
	30

There are overloaded methods. They have same name sum and have different number of arguments.

Summary

In this step, we:

  • Used our understanding of method overloading to define our own methods

Step 10: Returning From A Method

A method can also be coded to return the result of its computation. Such a result is called a return value.

A lot of built-in Java methods have return values, the most notable we have seen being Math.min() and Math.max().

	jshell> Math.max(15, 25)
	$1 ==> 25
	jshell> $1
	$1 ==> 25

Math.max() does return a value, which is stored in the JShell variable $1.

A return mechanism is quite important, as it provides you the flexibility of:

  • Sharing computed results with other code and methods
  • Improving the breaking down of a problem, into sub-problems

The next example explains how you can collect a method's return value.

	jshell> int max = Math.max(15, 25)
	max ==> 25
	jshell> max
	max ==> 25
	jshell>

We are storing the return value in a variable int max.

We could define our own method that returns a value, in a similar manner. In the method sumOfTwoNumbers above, instead of displaying sum at once, we could return it to the calling-code.


	jshell> int sumOfTwoNumbers(int firstNum, int secondNum) {
	   ...> int sum = firstNum + secondNum;
	   ...> return sum;
	   ...> }
	| created method sumOfTwoNumbers(int,int)
	jshell> sumOfTwoNumbers(1, 10)
	$2 => 11

The statement return sum; is called a return statement.

When the code sum = sumOfTwoNumbers(1, 10) is run, sum collects the result returned by sumOfTwoNumbers(). You could now print sum on the console, store it in another variable, or even invoke a different method by passing it as an argument!

	jshell> sum = sumOfTwoNumbers(1, 10)
	sum => 11_
	jshell> sum = sumOfTwoNumbers(15, 15)
	sum => 30
	jshell>

Summary

In this step, we:

  • Understood the need for a return mechanism with methods
  • Explored the syntax for a return statement
  • Wrote our own method sumOfTwoNumbers() with a return value, and saw how it became more flexible

Step 11: Exercise-Set PE-04 (With Solutions)

Let's now try a few exercises on methods that return values.

Exercises

  1. Write a method that returns the sum of three integers.
  2. Write a method that takes as input two integers representing two angles of a triangle, and computes the third angle. Hint: The sum of the three angles of a triangle is 180 degrees.

Solution-01


	jshell> int sumOfThreeNumbers(int firstNum, int secondNum, int thirdNum) {
	   ...> int sum = firstNum + secondNum + thirdNum;
	   ...> return sum;
	   ...> }
	| created method sumOfThreeNumbers(int,int, int)
	jshell>

Solution-02


	jshell> int getThirdAngle(int firstAngle, int secondAngle) {
	   ...> int sumOfTwo = firstAngle + secondAngle;
	   ...> return 180 - sum;
	   ...> }
	| created method getThirdAngle(int,int)
	jshell>
	

Step 12: Java Methods, A Review

In this section, we introduced you to the concept of methods in Java.

  • We understood that methods are routines that perform a unit of computation. They group a set of statements together into a block, and need to be run by being invoked, through a method call.
  • We can define methods that accept no arguments, a single argument and multiple arguments.
  • A method can also be defined to return results of its computation, and this makes it your program more flexible.

Understanding the Java Platform

JShell is amazing to start with the basics of Java programming. It abstracts all complexities behind writing, compiling and running Java code.

What's happening behind the screens? Let's find out.

Step 01: The Java Platform - An Introduction

A computer only understands binary code, which are sequences of 0’s and 1’s (called bits). All instructions to a computer should be converted to 0’s and 1’s before execution.

When we wrote our code in JShell, how was it converted to binary code?

We write our programs in a high-level language, such as Java, as it is easier to learn, remember and maintain.

Who converts it to binary code?

Typically, Compiler is a program which understands the syntax of your programming language and converts it into binary code.

Java designers wanted it to be Platform independent. Compile the code once and run it anywhere.

However, different Operating Systems have different instruction sets - different binary code.

Java provides an interesting solution:

  • All Java compilers translate source code to an intermediate representation ( bytecode ).
  • To run Java programs (bytecode), you need a JVM (Java Virtual Machine).
    • JVM understands bytecode and runs it.
    • There are different JVM's for different operating systems. Windows JVM converts bytecode into Windows executable instructions. Linux JVM converts bytecode into Linux executable instructions.

The Java compiler translates Java source code to bytecode, which is stored as a .class file on the computer.

Summary

In this step, we:

  • Understood the role of the Java compiler in translating source code
  • Realized the need for an Intermediate Representation (IR) such as bytecode
  • Understood how the (Compiler + JVM + OS) combination ensure source code portability

Step 02: Creating a Java class

First, let's understand the concept of a class.

Let's consider an example:

A Country is a concept. India, USA and Netherlands are examples or instances of Country.

Similarly, a class is a template. Objects are instances of a class.

We will discuss more about class and object in the section on Object Oriented Programming.

The syntax to create a class, and its objects, is very simple.


	jshell> class Country {
	   ...> }
	created class Country

Let's create an instance of the class:

	jshell> Country india = new Country();
	india ==> Country@6e06451e

The syntax is simple - ClassName objectName = new ClassName().

india is an object of type Country, and is stored in memory at a location indicated by 6e06451e.

Let's create a few more instances of the class:

	jshell> Country usa = new Country();
	usa ==> Country@6e1567f1
	jshell> Country netherlands = new Country();
	netherlands ==> Country@5f134e67
	jshell>

india, usa and netherlands are all different objects of type Country.

We actually left the contents of the class Country bare.

A class does often include both data (member variables) and method definitions. More on this at a relevant time.

Let's consider another example:


	jshell> class Planet {
	   ...>}
	created class Planet
	jshell> Planet planet = new Planet();
	planet ==> Planet@56ef9176
	jshell> Planet earth = new Planet();
	earth ==> Planet@1ed4004b
	jshell> Planet planet = new Planet();
	venus ==> Planet@25bbe1b6

We can also create a class for a different concept, like a Planet.

Planet is now a different template. planet, earth and venus are instances of Planet class.

Summary

In this step, we:

  • Saw how class creation actually creates a new type
  • Understood how to create instances of classes - objects

Step 03: Adding A Method To A class

A method defined within a class, denotes an action than can be performed on objects of that class.

Let's define a method inside Planet - to revolve()!


		jshell> class Planet {
	   ...> void revolve() {
	   ...> System.out.println("Revolve");
	   ...> }
	   ...> }
	replaced class Planet
	update replaced variable planet, reset to null
	update replaced variable earth, reset to null
	update replaced variable venus, reset to null

Syntax of revolve() is similar to other methods we've created before.

The class template got updated as a result of adding new method. Earlier instances planet,earth and venus got reset to null as they are based on the old template

Let's re-instantiate a few objects.

	jshell> Planet earth = new Planet();
	earth ==> Planet@192b07fd
	jshell> Planet planet = new Planet();
	venus ==> Planet@64bfbc86
	jshell>

How do we call the revolve method?


	jshell> Planet.revolve();
	| Error:
	| non-static method revolve() cannot be referenced from a static context
	| Planet.revolve();
	|^-----------------^
	jshell> earth.revolve();
	Revolve
	jshell> venus.revolve();
	Revolve
	jshell>

Our attempt to perform revolve() did not work with the syntax Planet.revolve() as it is not a static method (more on that in a later section).

Invoking revolve() through syntax such as earth.revolve() succeeds, because earth is an object of type Planet.

Summary

In this step, we:

  • Learned how to add a method definition to an existing class
  • Discovered how to invoke it, on objects of the class

Step 04: Writing and Running Java Code in separate Source Files

So far, we have enjoyed creating classes and defining methods within them, all with our friendly neighborhood JShell.

JShell kind of spoiled us kids, by relaxing some Java syntax rules, invoking the compiler on our behalf, and also running the code like room service.

The time has come for us frog princes to outgrow the proverbial well. Yes, you're right! Time to start writing code in a proper code editor, and smell the greener grass on that side.

Let's start with creating a new source code file - 'Planet.java'. Choose any folder on your hard-disk and create the file shown below:

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
	}

You can get the code that we wrote earlier in JShell for Planet by running the command /list Planet, and copying the code.

You can use any text editor of your choice, for now.

The source file name must match the class name it contains. Here, we must name the file Planet.java.

The next course of action would be to compile this code (Stage 2). For that, exit out of JShell, and run back to your system terminal or command prompt. Now, see what plays out!


	jshell> /exit
	|  Goodbye

cd to the folder where you have created the file Planet.java

	in28minutes$> cd in28Minutes/git/JavaForBeginners/
	command-prompt> ls
	Planet.java

Check Java version.

	command-prompt> java -version
	java version "x.0.1"
	Java(TM) SE Runtime Environment (build x.0.1+11)
	Java HotSpot(TM) 64-bit Server VM (build x.0.1+11, mixed mode)

You can compile java code using javac Planet.java. You can see that a new file is created Planet.class. This contains your bytecode.

	command-prompt> javac Planet.java
	command-prompt> ls
	Planet.class         Planet.java_

You can run the class using command java Planet.

	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application
	command-prompt>	

Why is there an error? Let's discuss that in the next step.

Summary

In this step, we:

  • Ventured out of JShell into unexplored territory, to write source code
  • Learned how to invoke the compiler to compile source files, from the terminal

Step 05: Introducing main(), And Running Bytecode

In the previous step, we compiled Planet.java. In this step, let's run the bytecode generated, which lies inside Planet.class.

Snippet-01: Running Planet

Console Commands


	command-prompt> ls
	Planet.class         Planet.java
	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application
	command-prompt>

The code may have compiled without any errors, but what's the use if we cannot run the program to see what stuff it's got!

The main() method is essential to run code defined within any class.

The definition of main() needs to have this exact synatx:

public static void main(String[] args) { /* <Some Code Goes In Here> */ }

A few details:

  • void is its return type
  • main is its name
  • args is its formal argument. Here, it's an array of String.
  • `publicandstatic``` are reserved Java keywords. More on these later sections.

Let's add one such definition within the Planet code. Open up your text editor and add the main method as shown below.

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
		public static void main(String[] args) {

		}
	}

Let's run it now:


	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application

Why is there no change in result?

After changing your Java source file, you need to compile the code again to create a new class file.

	command-prompt> javac Planet.java
	command-prompt> ls
	Planet.class         Planet.java_

Let's try it again.

	command-prompt> java Planet
	command-prompt>

We got a blank stare from the terminal. Why?

What did we write in the main method? Nothing.

		public static void main(String[] args) {

		}

Let's fix it. We need to edit Planet.java once again!

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
		public static void main(String[] args) {
			Planet earth = new Planet();
			earth.revolve();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	command-prompt> ls
	Planet.class         Planet.java
	command-prompt> java Planet
	Revolve
	command-prompt>

Bingo! We finally got what we wanted to see!

Summary

In this step, we:

  • Learned that we need a main() method to run a Java program
  • Discovered that after every code update, we need to compile that source file

Step 06: Puzzles About Planet

In this step, let's play with Planet source code. Get ready for a comedy of errors, by trial-and-error!

Below is the source code for Planet that worked so well for us:

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
		
		public static void main(String[] args) {
			Planet earth = new Planet();
			earth.revolve();
		}
	}

Here starts our nut-job.

Snippet-01: Messing-up main() - v1

Change method name from main to main1

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main1(String[] args) {
			Planet earth = new Planet();
			earth.revolve();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application
	command-prompt>

Don't mess with the method-name of main().

Other parts also need to remain the same, such as:

  • The return-type: void
  • Argument type: String[]
  • The presence of keywords public and static.
Snippet-02: Messing-up main() - v2

Remove semicolons after statements Planet earth = new Planet() and earth.revolve().

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main(String[] args) {
			Planet earth = new Planet()
			earth.revolve()
		}
	}

Console Commands


	command-prompt> javac Planet.java
	Planet.java:6: error: ';' expected
	Planet earth =  new Planet()
	|_______________________^
	Planet.java:7: error: ';' expected
	earth.revolve()
	|_____________^
	2 errors
	command-prompt>

The ; symbol is the Java statement separator, which is mandatory.

It is not needed in JShell but mandatory when you write separate Java source files.

Snippet-03: Messing-up main() - v3

Make a typo Planet earth = new Plane();

Planet.java


	class Planet {
		
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main(String[] args) {
			Planet earth = new Plane();
			earth.revolve();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	Planet.java:6: error: cannot find symbol
	Planet earth =  new Plane();
	|________________^
	symbol: class Plane
	location: class Planet
	1 error
	command-prompt>

We misspelled Planet as Plane, and the compiler trapped this error. It shows us a red flag with a message to help us correct our mistake.

Snippet-04: Messing-up main() - v4

Call a non existing method earth.revolve1();.

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main(String[] args) {
			Planet earth = new Planet();
			earth.revolve1();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	Planet.java:7: error: cannot find symbol
	earth.revolve1();
	|_____^
	symbol: method revolve1()
	location: variable earth of type Planet
	1 error
	command-prompt>

We misspelled the name of the revolve() method, to revolve1(). Rightly, got rapped on our knuckles by the compiler.

Summary

In this step, we:

  • Learned that the best way to learn about language features is to play around with working code
  • Observed that JShell simplifies coding for us, even relaxing some syntax rules
  • Concluded that developing Java code in code-editors is an empowering feeling!

Step 07: The JVM, JRE And JDK

What are JVM, JRE and the JDK?

Apart from the fact that all start with a 'J', there are important differences in what they contain, and what they do.

The following list gives you a bird's eye view of things.

The JVM runs your program bytecode.

JRE = JVM + Libraries + Other Components

  • Libraries are built-in Java utilities that can be used within any program you create. System.out.println() was a method in java.lang, one such utility.
  • Other Components include tools for debugging and code profiling (for memory management and performance).

JDK = JRE + Compilers + Debuggers

  • JDK refers to the Java Development Kit. It's an acronym for the bundle needed to compile (with the compiler) and run (with the JRE bundle) your Java program.

An interesting way to remember this organization is:

  • JDK is needed to Compile and Run Java programs

  • JRE is needed to Run Java Programs

  • JVM is needed to Run Bytecode generated from Java programs

Let's check a couple of scenarios to test your understanding.

Scenario 1: You give Planet.class file to a friend using a different operating system. What does he need to do to run it?

First, install JRE for his operating system. Run using java Planet on the terminal. He does not need to run javac, as he already has the bytecode.

Scenario 2: You gave your friend the source file Planet.java. What does he need to do to run it?

Install JDK of a compatible version. Compile code using javac Planet.java. Run java Planet on his terminal.

In summary

  • Application Developers need ==> JDK

  • Application Users need ==> JRE

Summary

In this step, we:

  • Understood the differences in the scope-of-work done by the JVM, JRE and JDK
  • Realized how each of them could be invoked by different terminal commands, such as javac and java.

Eclipse

TODO - Need Revision

Introducing Java Software Development with Eclipse

  • Features of the Eclipse IDE (Integrated Development Environment)

    • Installation & Configuration
    • Workspace Creation & Configuration
    • Project Creation & Organization
      • JRE Version Selection and Included Libraries
      • Eclipse Java Perspectives
      • Source Files Organization into Folders
      • Packages?
    • IDE User Interface Description
      • Perspective
      • Views
      • Console Content and Display Options
  • Creating a new Java class in Eclipse (And related source file)

    • Package name

      • A Java solution to solving a problem could be composed of several application components. It is considered good programming arctice to identify a class for each distinct component. Package is the Java way to organize classes in source code.
      • Analogy: Eatables in a Refrigerator (Freezer, Chill-Tray, Vegetable-Tray, Bottle-Rack)
    • Public method stub : can be used to create a default public static void main(String[] args) signature

    • (Include Snapshots)

      • Class creation pop-up, with selected options
      • Default generated source code in editor window
    • Customizing the generated source code to our needs

      • Syntax Highlighting
        • Keywords
        • Built-in Types
        • Constant literals: numbers, strings
      • Auto-suggest feature of eclipse as code is being typed in
    • The "Run as --> Java Application" Option to compile-and-run the source code

      • Option is avaibale only for classes that have a main() method

Using Eclipse in Debug Mode

Execution of the Multiplication Table Program can be done Step by-step. That is, the entire application dies not execute at one go, printing the final output onto the console. We can stall its flow at several steps, by taking control of its execution using the Eclipse IDE. This is possible in a special mode of Eclipse, called Debug Mode.

The process is called Debugging, because this mode is heavily used not just to have fun seeing what happens, but also to detect and fix software bugs. A bug is a defect in the program being written, that leads to its incorrect execution. The process of removing bugs is called debugging. Humans being humans, programming errors are but natural, and a debug mode in the IDE is worth its wight in gold to the programmer. Here is how Eclipse facilitates debugging of Java applications.

  • Prior to debugging application, we need to set few Break-Points. A Break-Point is a statement in the source of the program, before which execution under debug mode is suspended, and control is passed to the programmer.

  • The overall state of the data in the suspended program is available to the programmer at that particular break-point. He/she gets to specify one or more break-points in the program, and when the execution is suspended, a list of possible actions can be performed, including:

    • Reading & modifying data variables
    • Resuming program execution
    • Re-executing current statement
    • Skipping all statements till the next break-point

    and others.

  • The Eclipse IDE provides a very user-friendly and intuitive interface to the programmer for controlling execution of a program in Debug Mode (Provide Snapshots of IDE at various stages of Debug Mode execution).

    • Setting and Removing a Break-point (also Toggling)
    • Stepping over a method call, or into and out of a method body (during a method call)
      • Stepping into int print() and int print(int) and int print(int,int,int) gives us interesting infromation, but stepping into System.out.printf can freak you out! So, you may want to step over it.
    • For nested method calls, examine the method call Stack Trace (Call child, call parent relationship)
      • Example : int print(), int print(int) and int print(int,int,int) method call chain of class MultiplicationTable.
    • Viewing and Modifying current state of data variables, at a break point
    • Stepping through from one statement to another in the source code
      • As we step through, observe the view displaying changes in data variable values
      • Example of for loop control variable i, inside method int print(int,int,int) of class MultiplicationTable
      • Observe that execution exits from the for loop when the condition i<=10 is no longer true.
    • Re-executing a line of code
    • Skipping execution of all statements till next break-point
    • Ignoring all remaining breakpoints, resume execution of code till completion

Eclipse IDE Keyboard Shortcuts

  • Code Text Editor Shortcuts
  • New Project/Class Creation Shortcuts
  • Search for a Class

Differences between JShell and IDE

Variables just declared, but used without an initialization, will flag a compilation error in an IDE! But not so, it seems, in JShell. In regular software, variable initialization at point of declaration (called a "defintion", as we already know) is mandatory.

Snippet-1 : JShell redefines variables on demand

	jshell> int i = 2
	$1 ==> 2
	jshell> int i = 4
	$2 ==> 4
	jshell> long i = 1000
	$3 ==> 1000
	jshell>

When the following code (similar to the one given to JShell) is compiled manually or by IDEs such as Eclipse, it will flag errors!


	package com.in28minutes.firstjavaproject;
	
	public class RedefineTestRunner {
		public static void main(String[] args) {
			int i = 2;
			int i = 4;
			long i = 1000;
			System.out.println(i);
		}
	}

That is because Java source code is governed by strict Scope Rules.

Let's have another look at where we have reached with our solution, to the PMT-Challenge problem. Only now, let's change the code arrangement.

Snippet-01: Revisited - The PMT-Challenge

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;
	public class MultiplicationTable {
		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", 5, i, 5*i).println();
			}
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();	
	}	
}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

Snippet-01 Explained
  • We have now split the code into two source files:
    • MultiplicationTable.java: Houses the MultiplicationTable class definition, with some methods we need.
    • MultiplicationRunner.java: Acts as the client of the MultiplicationTable class, to invoke its functionality. It defines a main() method, that instantiates a MultiplicationTableobject, and invokes its print() method.
  • After this code was rearranged, we still got it to work!
  • We now want to enhance our current solution to this challenge, even though we've come a long way. "Once you get the whiff of success, sky is the limit!". Here is the changes we need:
    • Pass the number whose table needs to be printed, as an argument
    • Pass the (continuous) range of numbers, whose index entries in the table are to be printed. (For example, printing the table entries for 6, with entries for indexes between 15 to 30).

One way to achieve all this, would involve overloading the print() method. The next example is one such attempt.

Snippet-02: print() overloaded

Overloading print() works for us, and we now support three ways in which to display any table:


		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", 5, i, 5*i).println();
			}
		}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

The default table for 5, with entries fixed within 1 to 10.


		public static void print(int number) {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

Console Output

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

Printing a table for any number, but with entries fixed between 1 and 1.


		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

Console Output

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Displaying a table for any number, with entries for any range

The full code:

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;
	
	public class MultiplicationTable {
		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", 5, i, 5*i).println();
			}
		}	
	
		public static void print(int number) {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(8);
			table.print(6, 11, 20);
		}
	}

Issue: Code Duplication In Print-Multiplication-Table

There is an issue with the code for class MultiplicationTable. In the final print format, what if we are asked to replace the multiplication symbol '*' with an 'X', so that school kids like it better? Since there are three calls to System.out.printf(), one in each print() version, we make three changes.

Snippet-3: Code Duplication

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationTable {
		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d X %d = %d", 5, i, 5*i).println();
			}
		}

		public static void print(int number) {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d X %d = %d", number, i, number*i).println();
			}
		}
	}

Console Output

5 X 1 = 5

5 X 2 = 10

5 X 3 = 15

5 X 4 = 20

5 X 5 = 25

5 X 6 = 30

5 X 7 = 35

5 X 8 = 40

5 X 9 = 45

5 X 10 = 50

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

6 X 11 = 66

6 X 12 = 72

6 X 13 = 78

6 X 14 = 84

6 X 15 = 90

6 X 16 = 96

6 X 17 = 102

6 X 18 = 108

6 X 19 = 114

6 X 20 = 120

Snippet-3 Explained
  • Humans make mistakes. The programmer missed out on changing the format symbol in the code for void print(int, int), but we don't recommend punishment. He could be overworked, or could only be the maintainer of code someone else wrote years ago! The point is not to blame human flaws (there are many), but to show how code duplication causes errors. This issue arises frequently with overloaded methods, point blank.
  • Instead of trying to change human nature, can we change our software? Let's have a closer look at print():
    • The method void print() prints the multiplication table for 5 only, in the default range 1 to 10.
    • The method void print(int) outputs the table for any number, but only in the fixed range from 1 to 10.
    • The method void print(int,int,int) displays the table for any number, in any range of entries.

A Solution: Code Reuse

There is something huge we observe in the previous example. All overloaded versions of print() have nearly the same code!

  • print(int) has wider usage potential than print(). The latter is a special case, as it prints only the for 5. We can achieve what print() does, by passing a fixed parameter value of 5 to print(int). It's simple: invoke print(int) within print(), by passing 5 to it.
  • The point to note is, that a more specialized function can be implemented-in-terms-of a more general function.

Let's now reorganize this part of the code.

Snippet-4: Code Reuse

MultiplicationTable.java


	public static void print() {
		print(5);
	}

	public static void print(int number) {
		for(int i=1; i<=10;i++) {
			System.out.printf("%d * %d = %d", number, i, number*i).println();
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(8);
		}
	}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

Snippet-4 Explained

When we call a method inside another, the method call statement is replaced by its body (with actual arguments replacing the formal ones). In the new definition of int print() above, the code executed during the call will be:


	for(int i=1; i<=10;i++) {
		System.out.printf("%d * %d = %d", 5, i, 5*i).println();
	}

Extending Code Reuse

  • The method int print(int,int,int) is a more general version of int print(int). We can achieve what the latter computes, by passing fixed range of indexes, namely 1 and 10, as arguments to the former. have look into he code that follows.
Snippet-5 : Extending code reuse

MultiplicationTable.java


	public static void print(int number) {
		print(number, 1, 10);		
	}	

	public static void print(int number, int from, int to) {
		for(int i=from; i<=to;i++) {
			System.out.printf("%d X %d = %d", number, i, number*i).println();
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print(8);
			table.print(6, 11, 20);
		}
	}

Console Output

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Snippet-5 Explained
  • This example merely extended what we did in the previous example. We will will take this extension one level further now! Yes, you guessed right. We will implement print() in terms of print(int,int,int).
Snippet-6 : Extending code reuse (contd.)

MultiplicationTable.java


	public static void print() {
		print(5, 1, 10);
	}

	public static void print(int number, int from, int to) {
		for(int i=from; i<=to;i++) {
			System.out.printf("%d X %d = %d", number, i, number*i).println();
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(6, 11, 20);
		}
	}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Snippet-6 Explained
  • By extending the same logic of code reuse, the method int print(int,int,int) can be used to implement the logic of int print(). Just pass in a number parameter 5, as well as the fixed range parameters 1 and 10, in a call to the former. int print() is thus implemented-in-terms-of int print(int,int,int).

  • Our new version of class MultiplicationTable looks like this:

Snippet-7: Extending Code Reuse (Contd.)

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationTable {
		public static void print() {
			print(5, 1, 10);
		}

		public static void print(int number) {
			print(number, 1, 10);
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d X %d = %d", number, i, number*i).println();
			}	
		}
	}

  • The logic of the class MutliplicationRunner does not change at all:

MultiplicationRunner.java:


	package com.in28minutes.firstjavaproject;
	
	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(8);
			table.print(6, 11, 20);
		}
	}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Snippet-7 Explained

Neat, isn't it! To make our program school kid friendly, we just need to change one character in the code, take a peek below.

Snippet-8 : Extending Code Reuse (Contd.)

MultiplicationTable.java:


	package com.in28minutes.firstjavaproject;

	public class MultiplicationTable {
		public static void print() {
			print(5, 1, 10);		
		}

		public static void print(int number) {
			print(number, 1, 10);
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d X %d = %d", number, i, number*i).println();
			}
		}
	}

Console Output

5 X 1 = 5

5 X 2 = 10

5 X 3 = 15

5 X 4 = 20

5 X 5 = 25

5 X 6 = 30

5 X 7 = 35

5 X 8 = 40

5 X 9 = 45

5 X 10 = 50

8 X 1 = 8

8 X 2 = 16

8 X 3 = 24

8 X 4 = 32

8 X 5 = 40

8 X 6 = 48

8 X 7 = 56

8 X 8 = 64

8 X 9 = 72

8 X 10 = 80

6 X 11 = 66

6 X 12 = 72

6 X 13 = 78

6 X 14 = 84

6 X 15 = 90

6 X 16 = 96

6 X 17 = 102

6 X 18 = 108

6 X 19 = 114

6 X 20 = 120

Snippet-8 Explained

Software Development is an iterative process. The best code that we want to write does not happen at one go. It starts off at a certain level, and can always be improved. More importantly, such improvements needs to be remembered, to be applied again at different points in the same program, and across programs. This process is called Code Refactoring. Thought we'd keep you posted.

Summary

In this step, we:

  • Explored how to reorganize the code for PMT-Challenge into a class
  • Understood that overloading works the same way for class methods
  • Observed that code reuse is possible across overloaded versions of a class method

Object Oriented Progamming (OOP)

How do you design great Object Oriented Programs?

Let's find out

Recommended Videos:

Step 01: Object Oriented Progamming (OOP) - Basic Terminology

Let's consider a few examples before we get to Object Oriented Progamming.

Humans think in a step by step process.

Let's say I've to take a flight from London to New York. This is how I would think:

  • Take a cab to London Airport
  • Check in
  • Pass Security
  • Board the flight
  • Wish the Hostess
  • Take Off
  • Cruise
  • Land
  • Get off the plane
  • Take a cab to ..

Procedural programming is just a reflection of this thought process. A procedural program for above process would look something like this:

takeACabToLondonAirport();
checkIn();
passSecurity();
boardPlane();
wishHostess();
takeOff();
cruiseMode();
land();
getOffPlane();
//...

Object Oriented Programming (OOP) brings in a new thought process around this.

How about thinking in terms of the different Actors? How about storing data related to each actor right beside itself? How about giving them some responsiblity and let them do their own actions?

Here's how our program would look like when we think in terms of different actors and give them data and responsibilities


    Person
    	name
    	boardFlight(Plane flight), wishHostess (Hostess hostess), getOffFlight(Plane flight)

    AirPlane
    	altitude, pilot, speed, flightMode
		takeOff(), cruiseMode(), land()

    Hostess
    	welcome()

Do not worry about the implementation details. Focus on the difference in approaches.

We have encapsulated data and methods into these entities, which are now called objects. We have defined object boundaries, and what it can (and cannot) do.

An object has

  • State : Its data
  • Behavior : Its operations

The position of an Airplane can change over time. The operations that can be performed on an Airplane include takeOff(), land() and cruiseMode(). Each of these actions can change its position. Therefore, an object's behavior can affects its own state.

It's now time to introduce you to some core OOP terms, which will make our future discussions easier.

OOP Terminology

Let's visit and enhance the Planet example we had written a few sections ago. This time, let's also explore the conceptual angle.

Planet


	class Planet
		name, location, distanceFromSun // data / state / fields
		rotate(), revolve() // actions / behavior / methods

	earth : new Planet
	venus : new Planet

Let's look at some OOP terminology.

A class is a template. An object is an instance of a class. In above example, Planet is a class. earth and venus are objects.

  • name, location and distanceFromSun compose object state.
  • rotate() and revolve() define object's behavior.

Fields are the elements that make up the object state. Object behavior is implemented through Methods.

Each Planet has its own state:

  • name: "Earth", "Venus"
  • location : Each has its own orbit
  • distanceFromSun : They are at unique, different distances from the sun

Each has its own unique behavior:

  • rotate() : They rotate at different rates (and in fact, different directions!)
  • revolve() : They revolve round the sun in different orbits, at different speeds

Summary

In this step, we:

  • Understood how OOP is different from Prodedural Programming
  • Learned about a few basic OOP terms

Step 02: Programming Exercise PE-01

Exercises

In each of the following systems, identify the basic entities involved, and organize them using object oriented terminology:

  1. Online Shopping System
  2. Person

Solution-1: Online Shopping System


	Customer
		name, address
		login(), logout(), selectProduct(Product)


	ShoppingCart
		items
		addItem(), removeItem()


	Product
		name, price, quantityAvailable
		order(), changePrice()

Solution-2: Person


	Person
		name, address, hobbies, work
		walk(), run(), sleep(), eat(), drink()

Step 03: Creating MotorBike class

In this series of examples, we want to model your pet mode of transport, a motorbike. We want to create motorbike objects and play around with them.

We will start with two java files:

  • MotorBike.java, which contains the MotorBike class definition. This class will encapsulate our motorbike state and behavior
  • MotorBikeRunner.java, with class MotorBikeRunner holding a main method, our program's entry point
Snippet-1: MotorBike Class

MotorBike.java


	package com.in28minutes.oops;
		public class MotorBike {
		//behavior
		void start() {
			System.out.println("Bike started!");
		}
}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();
		}
	}

Console Output

Bike started!

Bike started!

Snippet-1 Explained

We started off creating a simple MotorBike class with a start method. We created a couple of instances and invoked the start method on them.

We created two classes because we believe in Seperation of Concerns:

  • MotorBike class is responsible for all its data and behavior.
  • MotorBikeRunner class is responsible for running MotorBike examples.

Summary

In this step, we:

  • Defined a MotorBike class allowing us to further explore OOP concepts in the next steps

Step 04: Programming Exercise OO-PE-02

Exercises

  1. Write a small Java program to create a Book class, and then create instances to represent the following book titles:
    • "The Art Of Computer Programming"
    • "Effective Java"
    • "Clean Code"

Solution

Book.java


	public class Book {
		private String title;

		public void setTitle(String bookTitle) {
			title = bookTitle;
		}

		public String getTitle() {
			return title;
		}
	}

BookRunner.java


	public class BookRunner {
		public static void main(String[] args) {
			Book taocp = new Book();
			taocp.setTitle("The Art Of Computer Programming");
			Book ej = new Book();
			ej.setTitle("Effective Java");
			Book cc = new Book();
			cc.setTitle("Clean Code");
			System.out.println(taocp.getTitle());
			System.out.println(ej.getTitle());
			System.out.println(cc.getTitle());
		}
	}

Console Output

The Art Of Computer Programming

Effective Java

Clean Code

Step 05: MotorBike - Representing State

An object encapsulates both state and behavior.

State defines "the condition of the object at a given time". State is represented by member variables.

In the MotorBike example, if we need a speed attribute for each MotorBike, here is how we would include it.

Snippet-1 : MotorBike with state variable speed

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		int speed;
		void start() {
			System.out.println("Bike started!");
		}
	}
	

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();

			ducati.speed = 100;
			honda.speed = 80;
			ducati.speed = 20;
			honda.speed = 0;
		}
	}

Console Output

Bike started!

Bike started!

Snippet-4 Explained

int speed; within MotorBike, defines a member variable.

It can be accessed within objects such as ducati and honda, by qualifying it with the object name (ducati or honda).

ducati.speed = 100;
honda.speed = 80;

ducati has its own value for speed, and so does honda. These values are independent of each other. Changing one does not affect the other.

Classroom Exercise CE-OO-01

  1. Update the Book class created previously to include a member variable named noOfCopies, and demonstrate how it can be set and updated independently for each of the three titles specified earlier.

Solution

TODO

Step 07: MotorBike - get() and set() methods

In the previous step. we were merrily modifying the speed attribute within the ducati and honda objects directly, from within the main() program.

	public class MotorBikeRunner {
		public static void main(String[] args) {
			//... Other code
			ducati.speed = 100;
			honda.speed = 0;
		}
	}

This did work fine, but it breaks the fundamental principle of encapsulation in OOP.

"A method of one object, should not be allowed to directly access the state of another object. To do so, such an object should only be allowed to invoke methods on the target object".

In other words, a member variable should not be directly accessible from methods declared outside its class.

Snippet-3 : MotorBike class with private attributes

MotorBike.java


	package com.in28minutes.oops;
	
	public class MotorBike {
		private int speed;
		
		void start() {
			System.out.println("Bike started!");
		}

		void setSpeed(int speed) {
			this.speed = speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();
		
			ducati.setSpeed(100);
			honda.setSpeed(80);
	
			ducati.setSpeed(20);
			honda.setSpeed(0);
		}
	}

Console Output

Bike started!

Bike started!

Snippet-3 Explained

By declaring speed as private, we provide MotorBike with something called access control. Java keywords such as public and private are called access modifiers. They control what external objects can access within a given object.

Let's look at this.speed = speed; in the body of method setSpeed():

  • An member variable always belongs to a specific instance of that class.
  • A method argument behaves just like a local variable inside that method.
  • To differentiate between the two, this is used. The expression this.speed refers to the member variable speed of a Motorbike object. setSpeed() would be invoked on that very object.

Code written earlier within MotorBikeRunner, such as ducati.speed = 100; would now result in errors! The correct way to access and modify speed is to invoke appropriate methods such as setSpeed(), on MotorBike objects.

Classroom Exercise CE-OO-02

  1. Update the class Book to make sure it no longer breaks Encapsulation principles.

Solution

TODO

Summary

In this step, we:

  • Learned about the need for access control to implement encapsulation
  • Observed that Java provides access modifiers (such as public and private) for such control
  • Understood the need for get() and set() methods to access object data

Step 08: Accessing Object State

Encapsulation is needed to protect an object's state from direct access by other objects. We were able to protect the state of MotorBike objects by declaring speed to be private. We have created a sort of rigid situation here, since the private declaration of speed forbids even a get access. How do we address this issue? Again, the answer is to provide a method for reading the current speed.

Snippet-4 : getSpeed() of MotorBike

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//Same as before

		int getSpeed() {
			return this.speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();

			ducati.setSpeed(100);
			honda.setSpeed(80);
			System.out.printf("Current Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Current Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

Console Output

Bike started!

Bike started!

Current Ducati Speed is : 100

Current Honda Speed is : 80

Snippet-4 Explained

Defining a method such as getSpeed() allows us to access the currentspeed of a MotorBike object.

		int getSpeed() {
			return this.speed;
		}

Eclipse has a very handy feature. When the state elements (member variables) of a class have been defined, it can generate default get() and set() methods for each of them. You would want to use this regularly, to save on time and typing effort. Right click on class > Generate Source > Generate Getters and Setters

Summary

In this step, we:

  • Understood how access control forces us to provide get() methods as well
  • Explored a few Eclispe tips to generate get() and set() versions for each class attribute

Step 10: Default Object State

What happens if a data element inside an object is not initialized with a value?

Snippet-5 : Default Initialization of Object State

MotorBike.java

//Same as before

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike honda = new MotorBike();			
			System.out.printf("Current Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

Console Output

Current Honda Speed is : 0

Snippet-6 Explained

When we instantiate an object, all its state elements are always initialized, to the default values of their types. Inside MotorBike, speed is declared to be an int, and so is initialized to 0. This happens even before any method of MotorBike is called, including start().

You can see that honda.getSpeed() printed 0 even though we did not explictly initialize it.

Default

Summary

In this step, we:

  • Learnt that default values are assigned to object member variables.

Step 10: Encapsulation: Its Advantages

At the heart of encapsulation, is the need to protect object's state. From whom? Other objects.

Let's look at an example to understand Encapsulation better.

Snippet-7 : Advantage of Encapsulation

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		private int speed;

		public void start() {
			System.out.println("Bike started!");
		}

		public void setSpeed(int speed) {
			this.speed = speed;
		}

		public int getSpeed() {
			return this.speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {

		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			ducati.start();
			ducati.setSpeed(-100);
			System.out.printf("Current Ducati Speed is : %d", ducati.getSpeed()).println();
		}
	}

Console Output

Bike started!

Current Ducati Speed is : -100

Snippet-01 Explained

For a motorbike, -100 might be an invalid speed. Currently, we do not have any validation. Having a method setSpeed allows us to add validation.

Let's see how to do that.

Snippet-02 : Speed Validity Check

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {

		//Other code as is

		public void setSpeed(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

	}

MotorBikeRunner.java

//Same as before

The output of this snippet is:

Bike started!

Current Ducati Speed is : 0

Snippet-8 Explained

setSpeed() checks if(speed > 0) and does not update speed for negative values.

This is not perfect solution because the caller of the setSpeed method assumes that he was successful. Ideally, we should throw an Exception indicating validation error. We will talk about Exceptions later.

Summary

In this step, we:

  • Explored the first advantage of encapsulation - A provision for adding data validation
  • Highlighted how such validation can be done, using the Motorbike example

Step 11: Encapsulation - Advantages (Code Reuse)

We've understood quite a few things about encapsulation under OOP.

Suppose at different points of time, we want to increase the speeds of both Honda and Ducati bikes by a fixed amount, say 100 mph. The logic would be simple, right? Fetch the current speed of each bike, increment that fetched value by 100, and then set the new value back into that bike's speed. The following example puts the above logic into action.

Snippet-1 : Bulky Speed Increment code

MotorBike.java

// No Change

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();		
			honda.start();
			ducati.setSpeed(100);
			
			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();
		
			int ducatiSpeed = ducati.getSpeed();
			ducatiSpeed = ducatiSpeed + 100;
			ducati.setSpeed(ducatiSpeed);
			
			int hondaSpeed = honda.getSpeed();
			hondaSpeed = hondaSpeed + 100;
			honda.setSpeed(hondaSpeed);
			
			System.out.printf("Later Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Later Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 200

Later Honda Speed is : 100

Snippet-1 Explained

Notice the repeated code within MotorBikeRunner? The code for updating the speed of ducati, is almost the same as that for honda. Remember at the start of this book, we said something like this:

"The goal of any computer program is to make a task easier, less cumbersome and more elegant for the programmer."

OOP achieves all thus through encapsulation! The idea is to encapsulate repeated logic within a method, and pass object-specific information to it as arguments. The next example shows you one way of doing it.

Snippet-2 : Speed Increase through Code Encapsulation

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//Other code same as before
		public void increaseSpeed(int howMuch) {
			this.speed = this.speed + howMuch;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			
			MotorBike duati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();

			ducati.setSpeed(100);

			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();

			ducati.increaseSpeed(100);
			honda.increaseSpeed(100);

			System.out.printf("Later Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Later Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 200

Later Honda Speed is : 100

Snippet-2 Explained

The method increaseSpeed() has been added to MotorBike. It can be invoked on the ducati and honda objects.

Let's now add a feature to MotorBike, by which speed can be decreased.

Snippet-3 : Speed Increase And Decrease through Code Encapsulation

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		// Other methods same as before
		public void decreaseSpeed(int howMuch) {
			this.speed = this.speed - howMuch;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();
	
			ducati.setSpeed(100);
			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();

			ducati.increaseSpeed(100);
			honda.increaseSpeed(100);
			ducati.decreaseSpeed(50);
			honda.decreaseSpeed(50);

			System.out.printf("Later Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Later Honda Speed is : %d", honda.getSpeed()).println();
			
			ducati.decreaseSpeed(200);
			honda.decreaseSpeed(200);

			System.out.printf("Final Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Final Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 150

Later Honda Speed is : 50

Final Ducati Speed is : -50

Final Honda Speed is : -150

Snippet-3 Explained

The method decreaseSpeed() has been added to MotorBike. It can be invoked on the ducati and honda objects inside the main() method of MotorBikeRunner.

On of the things you can observe again is Negative Speed Values. Our validation needs to be improved.

Snippet-4 : Validation across methods, repeated!

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {

		//Same as before

		public void increaseSpeed(int howMuch) {
			if(this.speed + howMuch > 0)
			   this.speed = this.speed + howMuch;
		}

		public void decreaseSpeed(int howMuch) {
			if(this.speed - howMuch > 0)
			   this.speed = this.speed - howMuch;
		}
	}

MotorBikeRunner.java

	//Same as before

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 150

Later Honda Speed is : 50

Final Ducati Speed is : 150

Final Honda Speed is : 50

Snippet-4 Explained

We have achieved data validation, because attempts to decrease the speed of ducati and honda below 0 are now ignored.

But this has come at a cost, which is code bloat.

How do we reduce duplication?

Snippet-5: Validation by code reuse

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//Other methods same as before


		public void setSpeed(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

		public void increaseSpeed(int howMuch) {
			setSpeed(this.speed + howMuch);
		}

		public void decreaseSpeed(int howMuch) {
			setSpeed(this.speed - howMuch);
		}
	}

MotorBikeRunner.java

	//Same as before

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 150

Later Honda Speed is : 50

Final Ducati Speed is : 150

Final Honda Speed is : 50

Snippet-5 Explained

The idea behind this solution is, that an update is the same as a set() operation. Since setSpeed() already has a validation check, it can be called inside both increaseSpeed() and decreaseSpeed() with appropriate parameters.

In this way, the validation logic would be reused across update methods.

Be always careful. Duplication of logic makes your code difficult to maintain.

Summary

In this step, we:

  • Started exploring the next advantage of encapsulation - code reuse
  • Mapped this understanding to the MotorBike example, building on data validation

Step 12: Programming Exercise PE-OO-03

Exercises

  1. Use an encapsulation technique to write methods for the Book class, that
    • Increase the number of books
    • Decrease the number of books

Solution

BookRunner.java


	public class BookRunner {
		public static void main(String[] args) {
			Book taocp = new Book();
			taocp.setTitle("The Art Of Computer Programming");
			Book ej = new Book();
			ej.setTitle("Effective Java");
			Book cc = new Book();
			cc.setTitle("Clean Code");
			
			System.out.println(taocp.getTitle());
			System.out.println(ej.getTitle());
			System.out.println(cc.getTitle());

			taocp.increaseCopies(10);
			ej.increaseCopies(15);
			cc.increaseCopies(20);
			taocp.decreaseCopies(5);
			ej.decreaseCopies(10);
			cc.decreaseCopies(15);

			System.out.println(taocp.getNumberOfCopies());
			System.out.println(ej.getNumberOfCopies());
			System.out.println(cc.getNumberOfCopies());
		}
	}

Book.java


	public class Book {
		private String title;
		private int numberOfCopies;

		public void setTitle(String bookTitle) {
			title = bookTitle;
		}

		public String getTitle() {
			return title;
		}

		public void setNumberOfCopies(int numberOfCopies) {	
			if(numberOfCopies > 0) {
				this.numberOfCopies = numberOfCopies;
			}
		}

		public int getNumberOfCopies() {
			return numberOfCopies;
		}

		public void increaseCopies(int howMuch) {
			setNumberOfCopies(numberOfCopies + howMuch);
		}

		public void decreaseCopies(int howMuch) {
			setNumberOfCopies(numberOfCopies - howMuch);
		}
	}

Console Output

The Art Of Computer Programming

Effective Java

Clean Code

5

5

5

Step 13: Introducing Constructors

When we create Ducati and Honda motorbikes, we may want to configure them with some start speeds.

Suppose our whim is that a Ducati bike starts with 100 mph, and a Honda with 200 mph.

Snippet-1: MotorBike Constructor

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		private int speed;

		
		MotorBike(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

		//Same as before

	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike(100);
			MotorBike honda = new MotorBike(200);
			ducati.start();
			honda.start();
			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 200

Snippet-1 Explained

We defined a single-argument constructor for MotorBike, whosw definition looks like this:

public MotorBike(int speed){ /* Constructor Code Goes Here */ }

The constructor is a method, whose name is the same as the class name. All Java rules for a method apply to constructors as well. Constructor cannot be directly called.

A constructor is always invoked when a class object is created, using the new keyword. A constructor for a class could accept zero, one or more than one arguments. Let's next write some full-blooded code for a MotorBike constructor.

Summary

In this step, we were introduced to the concept of a class constructor

Programming Exercise PE-OO-04, And More On Constructors

Exercises

  1. Rewrite the Book class solution by using a constructor, which accepts an integer argument specifying the initial number of copies to be published:
    • "The Art Of Computer Programming" : 100 copies
    • "Effective Java" : 75 copies
    • "Clean Code" : 60 copies

Solution To PE-OO-04

BookRunner.java


	public class BookRunner {
		public static void main(String[] args) {
			Book taocp = new Book(100);
			taocp.setTitle("The Art Of Computer Programming");
			
			Book ej = new Book(75);
			ej.setTitle("Effective Java");
			
			Book cc = new Book(60);
			cc.setTitle("Clean Code");

			System.out.println(taocp.getTitle());
			System.out.println(taocp.getNumberOfCopies());

			System.out.println(ej.getTitle());`
			System.out.println(ej.getNumberOfCopies());

			System.out.println(cc.getTitle());
			System.out.println(cc.getNumberOfCopies());
		}
	}

Book.java


	public class Book {
		private String title;
		private int numberOfCopies;
		
		public Book(int numberOfCopies) {
			this.numberOfCopies = numberOfCopies;
		}

		public void setTitle(String bookTitle) {
			title = bookTitle;
		}

		public String getTitle() {
			return title;
		}

		public int getNumberOfCopies() {
			return numberOfCopies;
		}
	}

Console Output

The Art Of Computer Programming

100

Effective Java

75

Clean Code

60

More on Constructors

We enjoyed defining the MotorBike class and checking out the behavior of its instances, ducati and honda.

When we started off , we created instances of MotorBike classes using:

MotorBike ducati = new MotorBike();

Did you notice something familiar? Doesn't the expression new MotorBike() look like a constructor call?

As it turns out, it is a constructor call on MotorBike!

When we define a class in Java (even a seemingly empty one), some behind-the-scene magic happens. Consider one such class Cart:


	class Cart {

	};

This class has neither state, nor behavior. When we try to create instances of this "empty" class:


	class CartRunner {
		public static void main(String[] args) {
			Cart cart = new Cart();
		}
	}

The code seems to compile, execute and get initialized quite smoothly! What happens is, that the compiler silently generates a default constructor for Cart.

A default constructor is one that accepts no arguments. It is as if the Cart class were defined this way:


	class Cart {
		public Cart() {
		}
	};

A constructor may also have overloaded definitions.

Let's now try to create MotorBike instances with default initialization, just as we did with Cart.

Snippet-2 : Default Motorbike Construction?

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {

		private int speed;

		MotorBike(int speed) {
			if(speed > 0)
				this.speed = speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike(100);
			MotorBike honda = new MotorBike(200);
			MotorBike yamaha = new MotorBike();
		}
	}

Console Output

Compiler Error

Snippet-2 Explained

The compiler flags an error with MotorBikeRunner.java! MotorBike yamaha = new MotorBike(); is failing compilation. Why?

No default constructor is generated here! If you provide any constructor definition in a class, the compiler will not add a default constructor. Do them all yourself, if you don’t like what I do for you! is what it yells back.

If you need the default constructor, you can explicitly add it.

Snippet-3 : Programmer-defined default constructor

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//state
		private int speed;

		//behavior
		MotorBike() {
			this(5);
		}

		MotorBike(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike(100);
			MotorBike honda = new MotorBike(200);
			MotorBike yamaha = new MotorBike();
			System.out.printf("Earlier Yamaha Speed is : %d", yamaha.getSpeed()).println();
		}
	}

The output of this snippet is:

Earlier Yamaha Speed is : 5

Snippet-3 Explained

We defined a zero-argument constructor MotorBike(), to enable default object initialization. But what are we doing in its body with the statement this(5);?

We have called the constructor MotorBike(int), qualified with the this keyword, within Motorbike().

Primitive Data Types

Earlier, we looked at basic Java types (including int, double and boolean), and got a little familiar with them.

We used literal values, declared variables and formed expressions using them.

Java primitive types include:

  • Integer Types
    • byte
    • short
    • int
    • long
  • Floating-Point Types
    • float
    • double
  • Character Type
    • char
  • Logical Type
    • boolean

In this section, let's play with each of these types to understand them further.

Step 01: The Integer Types

Integers are not much of a mystery, are they? They've been part of us since our school days, and we normally prefer them over other numbers (they scare us less!).

Java supports them with ease, and we have coded quite a few examples using them, already.

Java also has a wrapper class corresponding to each of them, which make their primitive versions more versatile. The wrapper classes we are talking about are:

  • Byte: for byte
  • Short: matching short
  • Integer corresponding to int
  • Long: about long

Let's see how we can work with them.

Snippet-01 : Integer Sizes

Look at all the information these tiny classes hold for you! As they say, "fore-warned is fore-armed". Depending on the data (range and size) your program handles, you decide which types to use, to store them.


	jshell> Byte.SIZE
	$1 ==> 8
	jshell> Byte.BYTES
	$2 ==> 1
	jshell> Byte.MAX_VALUE
	$3 ==> 127
	jshell> Byte.MIN_VALUE
	$4 ==> -128
	jshell> Short.BYTES
	$5 ==> 2
	jshell> Integer.BYTES
	$6 ==> 4
	jshell> Long.BYTES
	$7 ==> 8
	jshell> Short.MAX_VALUE
	$8 ==> 32767
	jshell> Integer.MAX_VALUE
	$8 ==> 2147483647
	jshell> int i = 100000;
	i ==> 100000
	jshell> long l = 50000000000;
	| Error:
	| integer number too large: 50000000000
	| long l = 50000000000;
	|_________^
	jshell> long l = 50000000000l;
	l ==> 50000000000
	jshell>

Integer Type Conversions

Problems will (and should) arise if we attempt to store large data into smaller bins. The compiler warns the programmer about such issues by flagging errors. However, if the programmer is aware of the risks and intends to go ahead, explicit casts are her tools to push the code through.

Operations in the other direction (storing a smaller data value in a larger bin), is a piece of cake for the compiler. Such a conversion is called an implicit cast.

Snippet-02 : Integer Type Conversions

Attempting to store a long value into an int variable will give us a compiler error. However, you can use an explicit cast, such as i = (int) l;.


	jshell> int i = 100000;
	i ==> 100000
	jshell> long l = 50000000000l;
	l ==> 50000000000
	jshell> i = l;
	| Error :
	| incompatible types: possible lossy conversion from long to int
	| i = l;
	|_____^
	jshell> i = (int) l;
	i ==> -1539607552
	jshell> l = i;
	l ==> -1539607552
	jshell>
	

The compiler is not responsible for the type-safety of this statement. The onus is on me, the programmer.

Remember our earlier statement on possible incorrect program behavior? As you can see, a different value got stored in i.

Summary

In this step, we:

  • Explored the wrapper classes present for the primitive integer types
  • Understood the different capacities and data ranges of these types
  • Examined how to use explicit and implicit casts

Step 02: Integer Representations, And Other Puzzles

In a decimal system, the allowed digits are 0 through 9. When a value of 10 is encountered, the number of digits increases by 1, and its representation is "10".

Those familiar with number systems would know that decimal is not the only system that computers understand.

Other number systems that the Java language supports are Octal (Base-8) and Hexadecimal (Base-16).

In an Octal system, the allowed digits are 0 through 7, and a value 8 is represented by "010". The leading 0 is added only to distinguish the octal format from the decimal one.

In a Hexadecimal system, the allowed digits are 0 through 9, followed by a through f (or A through F). A value of 16 is represented by "0x10". Here, a leading 0x is added to help the compiler recognize Hexa decimal representation.

Let's see how Java supports these three number systems.

Snippet-01 : Storing Octal and Hexadecimal in Integer types

There are no number-system specific integer types in Java! The same int type is used to store decimal, octal and hexadecimal values.

If we adhere to to number system conventions about valid digits and understand the compiler hints, we get no surprises.


	jshell> int eight = 010;
	eight ==> 8
	jshell> int sixteen = 0x10;
	sixteen ==> 16
	jshell> int fifteen = 0xf;
	fifteen ==> 15
	jshell> int eight = 08;//8 is invalid octal digit
	| Error:
	| integer number too large : 08
	| int eight = 08;
	|___________^
	jshell> int big = 0xbbaacc;
	big ==> 12298956
	jshell>

Snippet-02 : More Integer Type-casting

There are two kinds of assignments:

  • Literal-to-variable assignment: With short s = 123456;, the data is clearly out of range (this is known at compile-time). The compiler flags an error.
  • Variable-to-variable assignment: Consider sh = in;. The value stored in int in at that stage was 4567, which is well within the range of the short type. The compiler chooses not to take chances and flags an error. This can again be preempted with a explicit cast sh = (short) in.

	jshell> byte b = 128;
	| Error:
	| incompatible types: possible lossy conversion from int to byte
	| byte b = 128;
	|_________^--^
	jshell> short s = 123456;
	| Error:
	| incompatible types: possible lossy conversion from int to short
	| short s = 123456;
	|__________^-------^
	jshell> short sh = 3456;
	sh ==> 3456
	jshell> int in = 4567;
	in ==> 3456
	jshell> sh = in;
	| Error:
	| incompatible types: possible lossy conversion from int to short
	| sh = in;
	|______^
	jshell> sh = (short) in;
	sh ==> 4567
	jshell> int num = sh;
	num ==> 4567
	jshell>

Built-In Operators For Integer Types

We already had a glimpse of arithmetic operators for the integer types:

  • +
  • -
  • *
  • /
  • %
  • ++ (both prefix and post-fix increment)
  • -- (both prefix and post-fix increment)

The increment and decrement operators are an interesting case, as they are actually short-hands for multiple statements. When we use their prefix and post-fix versions, we need to look out for side-effects.

Snippet-03 : Increment & Decrement Operators

With post-fix increment, such as in int j = i++;, the increment takes place after the assignment is done. j gets the value before increment.


	jshell> int i = 10;
	i ==> 10
	jshell> int j = i++;
	j ==> 10
	jshell> i
	i ==> 11

When prefix increment is involved, as with int n = ++m;, the increment is carried out before the assignment. n gets the value after increment.

	jshell> int m = 10;
	m ==> 10
	jshell> int n = ++m;
	n ==> 11
	jshell> m
	m ==> 11

With post-fix decrement, as with int l = k--;, the decrement occurs after the assignment is done. As far as prefix decrement is concerned, such as in int q = --p;, the decrement is performed before the assignment.

	jshell> int k = 10;
	k ==> 10
	jshell> int l = k--;
	l ==> 10
	jshell> k
	k ==> 9
	jshell> int p = 10;
	p ==> 10
	jshell> int q = --p;
	q ==> 9
	jshell> p
	p ==> 9
	jshell>

Summary:

In this step, we:

  • Looked at the number-systems supported in Java for integers
  • Examined how prefix and post-fix versions work for increment and decrement operators

Step 03: Classroom Exercise CE-01 (With Solutions)

Exercise Set

  1. Create a Java class BiNumber that stores a pair of integers, and has the following functionality:

    • Can be created by passing its initial two numbers to store
    • Must Support Addition and Multiplication operations on the stored integers
    • An operation to double the values of both numbers
    • Operations to access each number individually

In short, we must be able to write code like this in the main method of our runner class:


	BiNumber numbers = new BiNumber(2, 3);
	System.out.println(numbers.add());
	System.out.println(numbers.multiply());
	numbers.double();
	System.out.println(numbers.getNumber1());
	System.out.println(numbers.getNumber2());

Solution to CE-01

BiNumber.java


	package com.in28minutes.primitive.datatypes;
	
	public class BiNumber {
		private int number1;
		private int number2;

		public BiNumber(int number1, int number2) {
			this.number1 = number1;
			this.number2 = number2;
		}

		public int add() {
			return number1 + number2;
		}

		public int multiply() {
			return number1 * number2;
		}

		public void doubleValue() {
			number1 *= 2;
			number2 *= 2;
		}

		public int getNumber1() {`
			return number1;
		}

		public int getNumber2() {
			return number2;
		}

		public void setNumber1(int number1) {
			this.number1 = number1;
		}

		public void setNumber2(int number2) {
			this.number2 = number2;
		}
	}

BiNumberRunner.java


	package com.in28minutes.primitive.datatypes;

	public class BiNumberRunner {
		public static void main(String[] args) {
			BiNumber numbers = new BiNumber(2, 3);
			System.out.println(numbers.add());
			System.out.println(numbers.multiply());
			numbers.doubleValue();
			System.out.println(numbers.getNumber1());
			System.out.println(numbers.getNumber2());
		}
	}

Console Output

5

6

4

6

Step 05: Floating-Point Types

You would recall there are two types in Java to support floating-point numbers:

  • double: The default type for floating-point literals, with a capacity of 8 bytes
  • float: A narrower, less precise representation for floating-point data. It has a capacity of 4 bytes.

Let's quickly refresh what we know, with a few code snippets.

Snippet-01 : double and float

Default floating point type in Java is double. A float literal must be accompanied with a trailing f or F.


	jshell> float f = 34.5;
	| Error:
	| incomaptible types: possible lossy conversion from double to float
	| float f = 34.5;
	|_________^---^
	jshell> float f = 34.5f;
	f ==> 34.5
	jshell> float fl = 34.5F;
	fl ==> 34.5
	jshell> double d = 34.5678;
	d ==> 34.5678
	jshell> float flo = d;
	| Error:
	| incomaptible types: possible lossy conversion from double to float
	| float flo = d;
	|__________^
	jshell> float flo = (float) d;
	flo ==> 34.567
	jshell>

Snippet-02 : Operators for type double

You can use operators ++, -- and % on double.


jshell> double dbl = 34.5678;
dbl ==> 34.5678

jshell> dbl++
$3 ==> 34.5678

jshell> dbl
dbl ==> 35.5678

jshell> dbl--
dbl ==> 35.5678
jshell> dbl % 5
dbl ==> 4.567799999999998

You would need an explicit cast to convert a float to an integer value int i = (int)f.

	jshell> float f = 34.5678f;
	f ==> 34.5678
	jshell> int i = f;
	| Error:
	| incomaptible types: possible lossy conversion from float to int
	| int i = f;
	|_______^
	jshell> int i = (int)f;
	i ==> 34
	jshell> float fl = i;
	fl ==> 34.0
	jshell>

Summary

In this step, we:

  • Saw how we create literals and variables of the floating-point types
  • Understood the differences between double and float

Step 06: Introducing BigDecimal

Compact though they are, double and float are not very precise representations of floating-point numbers.

In fact, they are not used in computations that require high degrees for accuracy, such as scientific experiments and financial applications. The next example shows you why.


	jshell> 34.56789876 + 34.2234
	$1 ==> 68.79129875999999

The literal expression 34.56789876 + 34.2234 should evaluate to 68.79129876. Above addition is not really accurate.

This is due to a flaw in floating-point representations, used in the double and float types.

The BigDecimal class was introduced in Java to tide over these problems.

Accuracy of BigDecimal representation is retained only when String literals are used to build it.


	jshell> BigDecimal number1 = new BigDecimal("34.56789876");
	number1 ==> 34.56789876
	jshell> BigDecimal number2 = new BigDecimal("34.2234");
	number2 ==> 34.2234_

A BigDecimal type can be used to create only immutable objects. The values in an immutable object cannot be changed after creation.

You can see that the value of number1 is not changed on executing number1.add(number2). To get the result of the sum, we create a new variable sum.

	jshell> number1.add(number2);
	$2 ==> 68.79129876
	jshell> number1
	number1 ==> 34.56789876
	jshell> BigDecimal sum = number1.add(number2);
	sum ==> 68.79129876

Summary

In this step, we:

  • Learned that double and float are not very precise data types
  • Were introduced to the BigDecimal built-in data type
  • Understood that BigDecimal is immutable
  • Saw that accuracy is best achieved when you construct BigDecimal data using string literals

Step 06: BigDecimal Operations

Let's look at a few other operations defined in the BigDecimal class.

Snippet-01: Arithmetic Operations

All BigDecimal operations support only BigDecimal operands.


	jshell> BigDecimal number1 = new BigDecimal("11.5");
	number1 ==> 34.56789876
	jshell> BigDecimal number2 = new BigDecimal("23.45678");
	number2 ==> 23.45678
	jshell> number1.add(number2);
	$1 ==> 34.95678

BigDecimal does not jell well with primitive types.

	jshell> int i = 5;
	i ==> 5
	jshell> number1.add(i);
	| Error:
	| incompatible types: int cannot be converted to java.math.BigDecimal
	| number1.add(i);
	|_____________^

We can add, multiple, divide or subtract BigDecimal values.

	jshell> number1.add(new BigDecimal(i));
	$2 ==> 16.5
	jshell> number1.multiply(new BigDecimal(i));
	$3 ==> 67.5
	jshell> number1.divide(new BigDecimal(100));
	$4 ==> 0.115
	jshell>

Summary

In this step, we:

  • Explored the BigDecimal methods for doing some basic arithmetic
  • Found that BigDecimal has constructors accepting most basic Java numeric types

Step 07: Classroom Exercise CE-02

Exercise-Set

Write a Program that does a Simple Interest computation for a Principal amount. Recall that the formula for such a calculation is:

Total amount (TA) = Principal Amount (PA) + ( PA * Simple Interest (SI) Rate * Duration In Years (N))

In essence, write a SimpleInterestCalculator class that can be used in the following manner:


	SimpleInterestCalculator calculator = new SimpleInterestCalculator("4500.00", "7.5");
	BigDecimal totalValue = calculator.calculateTotalValue(5); //5 year duration
	System.out.println(totalValue);

Solution To CE-02

SimpleInterestCalculatorRunner.java


	package com.in28minutes.primitive.datatypes;
	import java.math.BigDecimal;

	public class SimpleInterestCalculatorRunner {
		public static void main(String[] args) {
			SimpleInterestCalculator calculator = new SimpleInterestCalculator("4500.00", 7.5");
			BigDecimal totalValue = calculator.calculateTotalValue(5); //5 year duration
			System.out.println(totalValue);
		}
	}

SimpleInterestCalculator.java


	package com.in28minutes.primitive.datatypes;
	import java.math.BigDecimal;

	public class SimpleInterestCalculatorRunner {
		BigDecimal principal;
		BigDecimal interest;

		public SimpleInterestCalculator(String principal, String interest) {
			this.principal = new BigDecimal(principal);
			this.interest = new BigDecimal(interest).divide(new BigDecimal(100));
		}

		public BigDecimal calculateTotalValue(int noOfYears)
			//Total Value = Principal  + Principal * Interest* Years
			BigDecimal totalValue = prinipal.add(principal.multiply(interest).multiply(new BigDecimal(noOfYears)));
			return totalValue;`
		}	
}

Console Output:

6187.50000

Tip: The import Statement

The Java import statement is Required in each source file that uses a class from another package. Hence, both SimpleInterestCalculator.java (class definition) and SimpleInterestCalculatorRunner.java (runner class definition) need to import class java.math.BigDecimal.

package java.lang.* is imported by default.

The .* suffix indicates that all classes in the package java.lang are being imported.

Summary

In this step, we:

  • Used BigDecimal values in a stand-alone Java program
  • Learnt how to make use of built-in Java packages, through the import statement

Step 08: boolean, Relational and Logical Operators

The Java boolean data type is one that holds only one of two values: true or false. Both labels are case-sensitive. We have seen examples of built-in comparison operators, such as ==, != and >, that evaluate expressions to give us boolean results. Let us do a quick recap of some of these.

Snippet-01 : Relational Operators : Recap

Relational Operators are used mainly for comparison. They accept operands of non-boolean primitive data types, and return a boolean value.


	jshell> int i = 7;
	i ==> 7
	jshell> i > 7;
	$1 ==> false
	jshell> i >= 7;
	$2 ==> true
	jshell> i < 7;
	$3 ==> false
	jshell> i <= 7;
	$4 ==> true
	jshell> i == 7;
	$5 ==> true
	jshell> i == 8;
	$6 ==> false
	jshell>
	

Logical Operators

Java also has logical operators that are used in expressions. Logical operators expect boolean operands. Expressions involving these are used for forming boolean conditions in code, including within if, for and while statements. The prominent logical operators are:

  • && : logical AND
  • || : OR
  • ! : NOT

Let's learn how we use them in our code.

Snippet-02 : Logical Operators

We would want to find if i is between 15 and 25. An expression i >= 15 && i <= 25 can be used. Details below.


	jshell> int i = 17;
	i ==> 17
	jshell> i >= 15
	$1 ==> true
	jshell> i <= 25
	$2 ==> true
	jshell> i >= 15 && i <= 25
	$3 ==> true
	jshell> i == 30;
	i ==> 30
	jshell> i >= 15 && i <= 25
	$4 ==> false
	jshell> i == 5;
	i ==> 30
	jshell> i >= 15 && i <= 25
	$5 ==> false

An expression with&& evaluates to true only if both its boolean operands evaluate to true.

	jshell> true && true
	$6 ==> true
	jshell> true && false
	$7 ==> false
	jshell> false && true
	$8 ==> false
	jshell> false && false
	$9 ==> false
	jshell>

Snippet-02 Explained

The next example helps us visualize truth tables for the prominent logical operators.


	jshell> true || true
	$1 ==> true
	jshell> true || false
	$2 ==> true
	jshell> false || true
	$3 ==> true
	jshell> false || false
	$4 ==> false
	jshell> true ^ true
	$5 ==> false
	jshell> true ^ false
	$6 ==> true
	jshell> false ^ true
	$7 ==> true
	jshell> false ^ false
	$8 ==> false
	jshell> !true
	$9 ==> false
	jshell> !false
	$10 ==> true
	jshell> int x = 6;
	x ==> 6
	jshell> !(x > 7)
	$11 ==> true
	jshell>

Summary

In this step, we:

  • We're introduced to the boolean primitive type
  • Understood where logical operators are used in Java programs
  • Explored the truth-tables of commonly used logical operators

Step 09: Short-Circuit Evaluation (With Puzzles)

Consider code below. The expression j > 15 && i++ > 5 evaluates to false as expected. j>15 is false as j has a value of 15.


	jshell> int j = 15;
	j ==> 15
	jshell> int i = 10;
	i ==> 10
	jshell> j > 15 && i++ > 5
	$1 ==> false
	jshell> j
	j ==> 15
	jshell> i
	i ==> 10

You can also observe that the value of i remains unchanged 10.

Why? Because i++ > 5 was not even evaluated. Why? && is lazy. It saw that j > 15 is false. Irrespective of the result of second expression, the result of this && would be false. So, it does NOT evaluate the second expression.

A more detailed explanation

The expression j > 15 && i++ > 5 was scanned from left to right. As the first operand to && evaluated to false, the compiler got lazy. && avoids evaluating expressions that don't affect the final result. The optimization has a name: Short-Circuit Evaluation, also called lazy evaluation.

The logical operator & is another version of the logical AND operation, that does away with lazy evaluation.

Both operands to & are always evaluated.


	jshell> j > 15 & i++ > 5
	$1 ==> false
	jshell> j
	j ==> 15
	jshell> i
	i ==> 11
	jshell>

Similarly, the logical OR operator also has two versions:

  • The || operator we saw earlier. This exhibits lazy evaluation.
  • The | operator, without lazy evaluation.

It is bad programming practice for our code to depend on the compiler's lazy evaluation. It makes code less readable, and can hide difficult-to-fix software bugs. It obviously adds to the code maintenance burden, so don't do it unless you like being in your peers' bad books.

Summary

In this step, we:

  • Examined conditions involving logical operators, that had lazy evaluation
  • Observed that the lazy evaluation depends on the operator's truth-table
  • Saw versions of the operators without lazy evaluation
  • Learned that code depending on lazy-evaluation, is less readable

Step 10: Character Types

Earlier, we explored how we could store basic keyboard characters(called ascii-code characters), such as:

  • Upper-Case and lower-case letters (A-Z, a-z)
  • Numeric characters (0-9)
  • Punctuation and other special characters (such as ',', '$', '{', etc.)

Turns out Java supports a much larger family of character encoding sets, called Unicode. All Unicode characters can be input to, understood and processed by, as well as output from your code.

Snippet-01 : Unicode characters

Not all Unicode characters can be input from your keyboard. But Java allows you to handle their values from your code, if you deal correctly with their format.

 
	jshell> char ch = '"';
	ch ==> '"'
	jshell> char c = '\u0022';
	c ==> '"'

Integer values can be stored in char variables. If the value is within a meaningful range, it also corresponds to the ascii value of a keyboard character.

	jshell> char cn = 65;
	cn ==> 'A'

Integer arithmetic can be performed on char data.

	jshell> cn++
	$1 ==> 'A'
	jshell> cn
	$2 ==> 'B'
	jshell> ++cn
	$3 ==> 'C'
	jshell> cn + 5
	$4 ==> 72
	jshell> cn
	cn ==> 'C'
	jshell> (int)cn
	cn ==> 67
	jshell>

Summary

In this step, we:

  • Were introduced the the char data type
  • Learned that Unicode takes the character set beyond your keyboard
  • An ascii character is char value, encoded by an integer value

Step 11: Programming Exercise PE-02

Exercise Set

  1. Write a Java class MyChar that is a special type of char. An object of type MyChar is created round an input char data element, and has operations that do the following:
    • Check if the input character is a:
      • Numeric Digit
      • Letter of the Alphabet
      • Vowel (Either upper-case or lower-case)
      • Consonant (Either upper-case or lower-case) NOTE: A letter is a consonant if not a vowel
    • Print all the letters of the Alphabet in
      • Upper-Case
      • Lower-Case

In Essence, a runner class for MyChar would have its main method run code similar to:


	MyChar myChar = new MyChar('c');
	System.out.println(myChar.isDigit());
	System.out.println(myChar.isAlphabet());
	System.out.println(myChar.isVowel());
	System.out.println(myChar.isConsonant());
	myChar.printLowerCaseAlphabets();
	myChar.printUpperCaseAlphabets();

Step 12: Solution To PE-02, Part 1 - isVowel()

MyCharRunner.java


	package com.in28minutes.primitive.datatypes;

	public class MyCharRunner {
		public static void main(String[] args) {
			MyChar myChar = new MyChar('c');
			System.out.println(myChar.isVowel());
		}
	}

MyChar.java


	package com.in28minutes.primitive.datatypes;
	
	public class MyChar {
		private char ch;
		
		public MyChar(char ch) {
			this.ch = ch;
		}

		public boolean isVowel() {
			if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
				return true;
			} 
			if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
				return true;
			}
			return false;
		}
	}

Console Output :

false

Step 13: Solution To PE-02, Part 2 - isDigit()

MyCharRunner.java


	package com.in28minutes.primitive.datatypes;

	public class MyCharRunner {
		public static void main(String[] args) {
			MyChar myChar = new MyChar('c');
			System.out.println(myChar.isDigit());
			System.out.println(myChar.isVowel());
		}
	}

MyChar.java


	package com.in28minutes.primitive.datatypes;

	public class MyChar {
		private char ch;

		public MyChar(char ch) {
			this.ch = ch;
		}

		public boolean isVowel() {
			if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
				return true;
			} 

			if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
				return true;
			}
			return false;
		}

		public boolean isDigit() {
			if(ch >= 48 && ch <= 57) {
				return true;
			}
			return false;
		}

}

Console Output :

false

false

Step 14: Solution To PE-02, Part 3 - Other Methods

MyCharRunner.java


	package com.in28minutes.primitive.datatypes;
	
	public class MyCharRunner {
		public static void main(String[] args) {
			MyChar myChar = new MyChar('c');
			System.out.println(myChar.isDigit());
			System.out.println(myChar.isAlphabet());
			System.out.println(myChar.isVowel());
			System.out.println(myChar.isConsonant());
			myChar.printLowerCaseAlphabets();
			myChar.printUpperCaseAlphabets();
		}
	}

MyChar.java


	package com.in28minutes.primitive.datatypes;

	public class MyChar {
		private char ch;
		
		public MyChar(char ch) {
			this.ch = ch;
		}

		public boolean isVowel() {
			if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
				return true;
			} 
			if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
				return true;
			}
			return false;
		}

		public boolean isConsonant() {
			if(isAlphabet() && !(isVowel())) {
				return true;
			}
			return false;
		}

		public boolean isDigit() {
			if(ch >= 48 && ch <= 57) {
				return true;
			}
			return false;
		}

		public boolean isAlphabet() {
			if(ch >= 97 && ch <= 122) {
				return true;
			}
			if(ch >= 65 && ch <= 90) {
				return true;
			}
			return false;
		}

		public void printLowerCaseAlphabets() {
			for(char ch='a'; ch <= 'z'; ch++) {
				System.out.println(ch);
			}
		}

		public void printUpperCaseAlphabets() {
			for(char ch='A'; ch <= 'Z'; ch++) {
				System.out.println(ch);
			}
		}
	}

Console Output :

false

true

false

true

a

b

c

d

e

f

g

h

i

j

k

l

m

n

o

p

q

r

s

t

u

v

w

x

y

z

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

Step 15: The Primitive Types - A Review

In this section, we built on our knowledge of the primitive Java types.

  • We first got familiar with built-in wrappers for the integer types, that store useful type information.
  • Going from the integer to the floating-point types, we examined type compatibility, and how the compiler warns you about common pitfalls. We used explicit casts to force type conversions, and learned that implicit type conversions are quite common.
  • We moved on to the BigDecimal class, a floating-point type with greater precision and accuracy.
  • Next in line was boolean, where we built on what we know of logical expressions. We focused on the logical operators, more so on short-circuit evaluation of their expressions.
  • We saw how dependency on side-effects, and on lazy evaluation, is not a good programming practice.
  • Finally, we got to the char type, and were pleasantly surprised to know, that the keyboard is not the limit.

Introducing Conditionals - if, switch and more

Decision making is a part of our daily lives. Computers do tasks for humans, so even programs need to make decisions. They do this by checking logical conditions, which evaluate to boolean values.

In the following steps, we will explore the following conditional statements:

  • if
  • if-else
  • if-else if-else
  • switch

What better way to master these basics, than using them to solve a programming challenge?

Here we go!

Programming Challenge : Design A Menu (The Menu-Challenge)

  • Ask the User for input:
    • Enter two numbers
    • Choose the arithmetic to do on those:
      • Add
      • Subtract
      • Multiply
      • Divide
  • Perform the Operation
  • Publish the Result

An example scenario could be:

Enter First Number

2

Enter Second Number

4

1 - Add

2 - Subtract

3 - Multiply

4 - Divide

Enter your choice of operation

3

The Result Is : 8

Summary

In this step, we:

  • Discussed how input affects the control-flow of a program
  • Listed out the conditionals available with Java
  • Selected a programming challenge to help us learn about conditions

Step 01: The if and if-else Conditionals

An if statement is the most basic way to manage control-flow in a program. A boolean condition is tested, and if found to be true, some code is executed. Otherwise, that code is not run.

  • "Do Something when condition is true"

Conceptually, the if statement looks like this:


	if(condition) {
		<if-body>
	}

An if-else statement improves over the plain if. We can now choose between executing two pieces of code, depending on what condition evaluates to.

  • "Do Something when condition is true, something else when condition is false"

An if-else statement boils down to the following:


	if(condition) {
		<if-body>
	} else {
		<else-body>
	}

If condition is found to be true, the statement block <if-body> is executed, otherwise <else-body> is run.

Let's now look at a examples that make use of these conditionals.

Snippet-01 : if behavior

In this example:

  • we have used compound comparison operators such as <= and >=, which also evaluate to boolean values.
  • Also used, are logical operators such as && and ||, which both accept and return values of type boolean.

	jshell> int i = 3;
	i ==> 3
	jshell> if(i==3) {
	   ..>> System.out.println("True");
	   ..>> }
	True
	jshell> if(i<2) {
	   ..>> System.out.println("True");
	   ..>> }
	
	jshell> if(i<=3 || i >= 35) {
	   ..>> System.out.println("True");
	   ..>> }
	True
	jshell> if(i<=3 && i >= 35) {
	   ..>> System.out.println("True");
	   ..>> }

if-else allows us to specify code to execute when a condition is false.

	jshell> if(i==3) {
	   ..>> System.out.println("True");
	   ..>> } else {
	   ..>> System.out.println("i is not 3");
	   ..>> }
	True
	jshell> i = 5;
	i ==> 5
	jshell> if(i==3) {
	   ..>> System.out.println("True");
	   ..>> } else {
	   ..>> System.out.println("i is not 3");
	   ..>> }
	i is not 3
	jshell>

Snippet-02 : chained if-else - v1

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			//int i=25;
			int i=26;
			if(i == 25) {
				System.out.println("i = 25");
			} else {		
				System.out.println("i != 25");
			}
		}
	}

Console Output

i != 25

Snippet-03 : chained if-else v2

We would want to test a number for 3 conditions - value is 24, value is 25 or value is not 24 and 25. Let's consider the code from the example below.

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24
			
			int i=25;
			if(i == 25) {
				System.out.println("i = 25");
			}
			if(i == 24) {
				System.out.println("i = 24"); 
			} else {			
				System.out.println("i != 25 and i != 24");
			}
		}
	}

Console Output

i = 25

i != 25 and i != 24

Snippet-03 Explained

What just happened here? The value of i is set to 25 within the program, so like in the previous example, only i = 25 should have been printed.

Why the extra print?

We started off trying to check fro 3 possibilities: * i being equal to 25 * i being equal to 24 * Neither of the above

We get wrong output, because i == 25 in first if is independent from i == 24 in the if-else that follows it.

Our decision making is not continuous. We need a tighter conditional to deal with more than two alternatives. We will explore this topic in the next step.

Summary

In this step, we:

  • Learned about the if and if-else conditionals
  • Tried out a few examples to see how they are used

Step 02: The if-else if-else Conditional

The if-else if-else statement solves the issue we faced, while trying to test more than two conditions.

Let's see an example.

Snippet-01 : Matching The if Clause

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24

			int i=25;
			if(i == 25) {
				System.out.println("i = 25");
			} else if(i == 24) {
				System.out.println("i = 24"); 
			} else {
				System.out.println("i != 25 and i != 24");
			}
		}
	}

Console Output

i = 25

Let's now try giving i a different value, say 24.

Snippet-02: Matching The else if Clause

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25		
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24
		
			//int i=25;
			int i=24;
			if(i == 25) {
				System.out.println("i = 25");
			} else if(i == 24) {
				System.out.println("i = 24"); 
			} else {
				System.out.println("i != 25 and i != 24");		
			}
		}
	}

Console Output

i = 24

Snippet-02 Explained
  • With i holding 24, a different condition (the one coresponding to i == 24) evaluates to true.

Let's now try to get a match with the else clause, the only one unexplored so far.

Snippet-03: Matching The else Clause

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24
			
			//int i=24;
			int i=26;
			if(i == 25) {
				System.out.println("i = 25");
			} else if(i == 24) {
				System.out.println("i = 24"); 
			} else {
				System.out.println("i != 25 and i != 24");
			}
		}
	}

Console Output

i != 25 and i != 24

Snippet-03 Explained

When i is given a value of 26, the first two conditions are false. Hence, the code in the else gets executed.

one, and only one clause among those present in an if-else if-else statement ever evaluates to true. Also, the code block corresponding to the matched clause will get executed. This is ensured even if conditions are duplicated, or overlap. In that scenario, only the first such condition, downward from the if in sequence, will evaluate to true. The remaining possible matches are not even checked.

Summary

In this step, we:

  • Learned about the if-else if-else conditional
  • Found out how to test when each different clause gets executed
  • Understood the guarantees made by Java regarding the conditional's code execution

Step 03: Puzzles on if

Try and guess the outputs of the following puzzles.

Programming Puzzle PP-01


	public class puzzleRunner {

		public static void main(String[] args) {
			puzzleOne();
		}

		public static void puzzleOne() {
			int k = 15;
			if(k > 20) {
				System.out.println(1);
			} else if(k > 10) {
				System.out.println(2);
			} else if(k < 20) {
				System.out.println(3);
			} else {
				System.out.println(4);
			}
		}
	}

Answer:

2

Programming Puzzle PP-02


	public class puzzleRunner {
		public static void main(String[] args) {
			puzzleTwo();
		}

		public static void puzzleTwo() {
			int l = 15;
			if(l < 20)
			System.out.println("l < 20");
			if(l > 20)
			System.out.println("l > 20");
			else
			System.out.println("Who Am I?");
		}
	}

Answer:

l < 20

Who Am I?

Programming Puzzle PP-03


	public class puzzleRunner {
		public static void main(String[] args) {
			puzzleThree();
		}
		
		public static void puzzleThree() {
			int m = 15;
			if(m > 20)
			if(m < 20)
			System.out.println("m >  20");	else
			System.out.println("Who Am I?");
		}
	}

Answer:

Nothing is printed. Because the code is structured this way.

if(m > 20) {
	if(m < 20)
		System.out.println("m >  20");	
	else
		System.out.println("Who Am I?");
}

Programming Puzzle PP-04


	jshell> int i = 0;
	i ==> 3
	jshell> if(i) {
	   ..>> System.out.println("i");
	   ..>> }
	| Error:
	| incompatible types: int cannot be converted to boolean
	| if(i)
	|____^
	jshell> if(i=1) {
	   ..>> System.out.println("i");
	   ..>> }
	| Error:
	| incompatible types: int cannot be converted to boolean
	| if(i=1)
	|____^-^
	jshell> if(i==1) {
	   ..>> System.out.println("i");
	   ..>> }
	jshell>

Answer:

Compiler Error

Programming Puzzle PP-05


	public class puzzleRunner {
		public static void main(String[] args) {
			puzzleFive();
		}

		public static void puzzleFive() {
			int number = 5;
			if(number < 0)
			number = number + 10;
			number++;
			System.out.println(number);
		}
	}

**Answer : **

6

In the absence of explicit blocks, Only the statement next to the if statement is considered to be part of the if statement block.

Step 04: Reading User Input


Look at the statement of Menu-Challenge once again:

  • Ask the User for input:
    • Enter two numbers
    • Choose an Arithmetic Operation to perform on them:
      • Add
      • Subtract
      • Multiply
      • Divide
  • Perform the Operation
  • Publish the Result

We have a good idea about how the if-else if-else conditional works.What we don't know, however, is how a such a conditional would behave when fed with random input. To test those scenarios out, the next step would be to learn how to take console input, from within our code.

We will do just that, in our next example.

Snippet-01: Reading console input

Java provides a built-in class named Scanner, to scan user input from the console. Roping in this utility would require you, the programmer, to do the following:

  • import the java.util.Scanner class within your code (here, we were writing code in the Eclipse IDE)
  • Create a scanner object which is of type Scanner. This involves invoking the Scanner constructor through the new operator. You also need to pass System.in as a constructor parameter, which ties scanner to the console input.
  • To read integer input from the console, call the method scanner.nextInt(). The keyboard's key needs to be pressed to complete user input. That number is passed on to your code, whe

Truncated — view the full README on GitHub.

java
java-8
java8
programming
programming-challenges
programming-fundamentals

in28minutes/java-tutorial-for-beginners

Java Tutorial For Beginners with 500 Code Examples

1,915

12 commits

updated Nov 26, 2023

See the code

README

Java Tutorial For Beginners

Welcome to this book on "Learning Java In 150 Steps".

I am Ranga Karanam, and I have more than two decades of programming experience.

I love Programming. One of the aims I had when I started in28minutes was to make learning programming easy. Thanks for helping us provide amazing courses to 300,000 learners across the world.

At In28Minutes, we ask ourselves one question every day: "How do we create awesome learning experiences?"

In this book, you will learn to write object oriented code with Java. You will be exposed to a lot of examples, exercises and tips. We will take up a lot of examples, and try and see how to write code for those in Java.

Help us improve this guide - Fork, Pull Requests, Shares and Likes are recommended!

Table of Contents

Our Approach

We did a study on why students give up on programming?

The popular answer was

Difficulty in writing their first program

Put yourselves in the shoes of a beginner and look at this typical Java Hello World Example.

package com.in28minutes.firstjavaproject; 
public class HelloWorld 
{   
     public static void main(String[] args) {           
            System.out.println("Hello World");   
     } 
}

A Programming Beginner will be overwhelmed by this. I remember how I felt when I saw this almost 20 years back. Stunned.

Why?

  • There are a number of keywords and concepts - package, public, class, static, void, String[] and a lot more..
  • What if the programmer makes a typo? Will he be able to fix it?

We believe that there has to be a better way to learn programming.

  • Why don't we learn programming step by step?
  • Why should it not be a lot of fun?
  • Why don't we solve a lot of problems and learn programming as a result?

This is the approach we took to writing this guide and develop our introductory programming courses for Java and Python.

Do you know? The first 3 hours of our Java Course is available here.

Introduction to Programming with Print-Multiplication-Table

Step 01: First Challenge : The Print-Multiplication-Table (PMT-Challenge)

Learning to program is a lot like learning to ride a bicycle. The first few steps are the most challenging ones.

Once you use this stepwise approach to solve a few problems, it becomes a habit.

In this book, we will introduce you to Java programming by taking on a few simple problems to start off.

Having fun along the way is what we will aim to do.

Are you all geared up, to take on your first programming challenge? Yes? Let's get started then!

Our first programming challenge aims to do, what every kid does in math class: reading out a multiplication table.

The PMT-Challenge

  1. Compute the multiplication table for 5, with entries from 1 to 10.
  2. Display this table.
5 * 1  =  5
5 * 2  = 10
5 * 3  = 15
5 * 4  = 20
5 * 5  = 25
5 * 6  = 30
5 * 7  = 35
5 * 8  = 40
5 * 9  = 45
5 * 10 = 50

As part of solving the multiplication table problem, you will be introduced to:

  • JShell
  • Statements
  • Expressions
  • Variables
  • Literals
  • Conditionals
  • Loops
  • Methods

Summary

In this step, we:

  • Stated our first programming challenge, PMT-Challenge
  • Identified basic Java concepts to learn, to solve this challenge

Step 02: Introducing JShell


JShell is a programming tool, introduced in Java SE 9. JShell is a REPL interface. The term REPL refers to this:

  • 'R' stands for Read; Read the input Java code
  • 'E' means Eval; Evaluate the source code
  • 'P' translates to Print; Print out the result
  • 'L' indicates Loop; Loop around, and wait for the next input

How about starting off exploring Java? Are you game?

Snippet-1: Check the Java programming environment

You can use https://tryjshell.org/ to run the code for the first 25 steps. Or you can Install Java 12+. Here's the troubleshooting section if you face problems.

Launch up command prompt or Terminal.

Let type in java -version on the terminal and press enter.


	in28minutes$>java -version
	java version "x.0.1"
	Java(TM) SE Runtime Environment (build x.0.1+11)
	Java HotSpot(TM) 64-bit Server VM (build x.0.1+11, mixed mode)
	in28minutes$>

A successful execution displays the version of Java installed your system. You need to have atleast Java 9 to pursue this book.

Snippet-2: Launch JShell

You can launch JShell by typing jshell at your terminal.


	in28minutes$>jshell

	|  Welcome to JShell version x.0.1
 	|  For an introduction type: /help intro
	jshell>

When run, this command displays basic information about the installed JShell program. A jshell prompt then appears, which waits for your input.

Snippet-3: Sample JShell input, using a built-in command

The JShell command /help, with a parameter intro, gives you basic guidelines on how you use the tool.


	jshell> /help intro

	|
	| intro
	| The jshell tool allows you to execute Java code, getting immediate results.
	| You can enter a Java definition (variable, method, class, etc), like: int x =8
	| or a Java expression, like: x + x
	| or a Java statement or import.
	| These little chunks of Java code are called 'snippets'.
	| There are also jshell commands that allow you to understand and
	| control what you are doing, like: /list
	|
	| For a list of commands: /help
	
	jshell>

Snippet-4: Evaluating an expression

Type 3+4 at the Jshell prompt


	jshell> 3 + 4
	$1 ==> 7
	jshell>

This was your first real REPL cycle! When you type in 3 + 4, JShell evaluates it and prints the result.

The entity $1 is actually a variable name assigned to the result. We will talk about this later.

Snippet-5: Getting out of JShell

The /exit command terminates the JShell program, and we are back to the terminal prompt.


	jshell> /exit
	|  Goodbye
	
	in28minutes$>

Snippet-6: Again, enter JShell and Exit it!

You can now effortlessly launch, feed code to, and exit from JShell!


	in28minutes$> jshell
	
	|  Welcome to JShell version 9.0.1
	|  For an introduction type: /help intro
	jshell> /exit
	|  Goodbye
	
	in28minutes$>

Summary

In this step, we learned:

  • How to launch JShell from our terminal, and run a few commands on it
  • How to run Java code on the JShell prompt

Step 03: Welcome to Problem Solving

Lets try to break down the PMT-Challenge problem to be able to solve it.

5 * 1  =  5
5 * 2  = 10
5 * 3  = 15
5 * 4  = 20
5 * 5  = 25
5 * 6  = 30
5 * 7  = 35
5 * 8  = 40
5 * 9  = 45
5 * 10 = 50

Here is how our draft steps look like

  • Calculate 5 * 3 and print result as 15
  • Print 5 * 3 = 15 (15 is result of previous calculation)
  • Do this ten times, once for each table entry (going from 1 to 10)

Summary

In this step, we:

  • Broke down the PMT-Challenge problem into sub-problems

Step 04: Introducing Expressions

The first part of solving our PMT-Challenge is to calculate the product of 5 and another number, say 3.

Let's start up jshell and type 5 X 3.


	in28minutes$> jshell

	|  Welcome to JShell version x.0.1
	|  For an introduction type: /help intro
	jshell> 5 X 3
	| Error:
	| ';' expected
	| 5 X 3
	|  ^
	| Error:
	| not a statement
	| 5 X 3
	|   ^
	| Error:
	| ';' expected
	| 5 X 3
	|    ^
	| Error:
	| missing return statement
	| 5 X 3
	| ^---^

You probably look at the symbol 'X' as a multiplier, remembering your school days.

Java does not identify 'X' as the multiplication operator! Java supports multiplication, but only if you use its predefined operator, *.

Let's type in code shown below:

	jshell> 5 * 3
	$1 ==> 15
	jshell>

Success!

Let's look at some terminology:

  • 5 * 3 is an expression.
  • 5 and 3 are operands. They are also called literals or constant values.
  • * is an operator.

Java also has built-in operators to perform other numerical tasks, such as:

  • Addition: +
  • Subtraction: -
  • Division: /
  • Modulo arithmetic: %

The following examples illustrate how to use them.


	jshell> 5 * 10
	$2 ==> 50
	jshell> 5 + 10
	$3 ==> 15
	jshell> 5 - 10
	$4 ==> -5
	jshell> 10 / 2
	$5 ==> 5
	jshell>

Your school math memories are still fresh, and the operators don't seem to disappoint either! +, - and / are your bread-and-butter operators.

% is the modulo operator, which gives you the remainder when integer division is performed.


	jshell> 9 % 2
	$6 ==> 1
	jshell> 8 % 2
	$7 ==> 0
	jshell>

Snippet: Complex Expressions, Anyone?

Java allows you to use more than one operator within an expression.

Let's look at some simple expressions with multiple operators.

 
	jshell> 5 + 5 + 5
	$8 ==> 15
	jshell> 5 + 10 - 15
	$9 ==> 0
	jshell> 5 * 5 + 5
	$10 ==> 30
	jshell> 5 * 15 / 3
	$11 ==> 25

Each of above expressions have two operators and three operands.

Summary

In this step, we:

  • Learned how to construct numeric expressions
  • Discovered that operators are predefined symbols
  • Combined several operators to form larger expressions

Step 05: Programming Exercise PE-1 (With Solutions)

At this stage, your smile tells us that you enjoy evaluating Java expressions. What if we tickle your mind a bit, to make sure it hasn't fallen asleep?

Okay, here comes a couple of programming exercises.

  1. Write an expression to calculate the number of minutes in a day.
  2. Write an expression to calculate the number of seconds in a day.

Solution 1

60 (minutes in an hour) multipled by 24 (hours in a day)


	jshell> 60 * 24
	$1 ==> 1440

Solution 2

60 (seconds in a minute) multipled by 60 (minutes in an hour) multipled by 24 (hours in a day)

$jshell>60 * 60 * 24

$1 ==> 86400

Step 06: Operators

Lets look at a few more examples to understand operators.

Invalid Operators

Let's type in 5 ** 6 followed by 5 $ 6 in JShell

	jshell> 5 ** 6
	| Error:
	| Illegal start of expression
	| 5 ** 6
	|     ^

	jshell> 5 $ 6 
	| Error:
	| ';' expected
	| 5 $ 6
	|  ^
	| Error:
	| not a statement
	| 5 $ 6
	|   ^
	| Error:
	| ';' expected
	| 5 $ 6
	|    ^

	jshell> 5 */ 6
	| Error:
	| Illegal start of expression
	| 5 */ 6
	|     ^
	

JShell was not impressed with our efforts at all!

Java has a set of grammar rules, called its syntax. Code that does not follow these rules throw errors. The compiler informs you by listing the errors, and also provides hints on how you can correct them.

Now, why is an error being thrown?

Operators in Java are all predefined, and limited in number. * is a valid operator, whereas ** and $ were rejected, with error messages.

Understanding Result of Expression with Mixed Types

Let's look at another example:


	jshell> 5 / 2
	$1 ==> 2
	jshell>

Surprise, Surprise! JShell seems to evaluate 5 / 2 to 2 instead of 2.5. Where did we go wrong?

Read what follows, with the biggest magnifying lens you can find:

The result of an expression when evaluated, depends on the operator context. This context is determined by the operands passed to it

There are two kinds of numbers typically used in programming : integer (1,2,3,...) and floating-point (1.1,2.3, 56.7889 etc). These values are represented by different types in Java. Integers are commonly of type int, and the floating-point numbers are double by default.

In the expression 5/2, both 5 and 2 are of type int. So, the result is also of type int.

Let's try with a few floating point numbers:


	jshell> 5.0 / 2.0
	$2 ==> 2.5

Both 5.0 and 2.0 are of type double, the result is double. We get a result of 2.5, as expected.

Let's do a mixed operation - using a floating point number and integer.

	jshell> 5.0 / 2
	$3 ==> 2.5
	jshell>

Among the types int and double, double is considered to be a wider type. When you perform a numeric operation between two types, the result will be of the wider type.

Understanding Precedence of Operators

Let's look at few complex examples of expressions with more than one operator.


	jshell> 5 + 5 * 6
	$1 ==> 35
	jshell> 5 - 2 * 2
	$2 ==> 1
	jshell> 5 - 2 / 2
	$3 ==> 4
	jshell>

Surprised with the results? You might expect 5 + 5 * 6 evaluate to 10 * 6 i.e. 60. Howeever, we got 35!

We write English left-to-right, and carry this habit to calculations as well.

In expressions with multiple operators, the order of sub-expression evaluation depends on operator precedence.

The basic rules for operator precedence are actually quite simple (we will look at other rules a little later).

The operators in the set {*, /, %} have higher precedence than the operators in the set {+, -}.

In the expression 5 + 5 * 6 : 5*6 is evaluated first. So, 5 + 5 * 6 becomes 5 + 30 i.e. 35.

5 - 2 * 2 and 5 - 2 / 2 are evaluated by following the same rules.

Use paranthesis for clear code

Java provides syntax elements, called parentheses ( and ), to group parts of an expression.


	jshell> (5 - 2) * 2
	$4 ==> 6
	jshell> 5 - (2 * 2)
	$5 ==> 1
	jshell>

When you put an expression in parenthesis, it is evaluated first. (5 - 2) * 2 => 3 * 2 => 6.

Parentheses lead to better readability as they reduce confusion and help avoid errors.

The old adage A stitch in time saves nine rings very true here. Use parentheses to make your code easy to read, even when they might not be necessary.

Summary

In this step, we:

  • Discovered that operators are all predefined
  • Learned that result of operation depends on operand types
  • Understood what operator precedence means
  • Used parentheses to group parts of an expression

Step 07: Introducing Console Output

We have computed the product of two literals (as in 5 * 3) in earlier steps.

The next step is to print this result in a customized format - 5 * 3 = 15.

How do we do this?

Let try typing it in into JShell

jshell> 5 * 3 = 15
|  Error:
|  unexpected type
|    required: variable
|    found:    value
|  5 * 3 = 15
|  ^---^

Hmm! Error.

How do we print text?

Java has a built-in utility method called System.out.println(), that displays text on the console.

jshell> System.out.println(3*4)
12

We formed an expression, 3*4, and passed it to System.out.println(), which is a built-in Java method.

System.out.println(3*4) is an example of a statement. It is a method call.

The syntax rules for method calls are quite strict, and all its parts are mandatory.

jshell> System.out.println3*4)
| Error:
| ';' expected
| System.out.println3*4)
|___________________^
| Error:
| cannot find symbol
|       symbol: variable println3
| System.out.println3*4)
| ^---------------------^

jshell> System.out.println 3*4
|  Error:
|  ';' expected
|  System.out.println 3*4
|                    ^
|  Error:
|  cannot find symbol
|    symbol:   variable println
|  System.out.println 3*4
|  ^----------------^

What if we want to print an entry of the Multiplication Table, as part of our solution to PMT-Challenge? In other words, how do we print the exact text 5 * 2 = 10 on the console?


	jshell> System.out.println(5 * 2 = 10)
	| Error:
	| unexpected type
	| required:  variable
	| found:     value
	| System.out.println(5 * 2 = 10)
	|____________________^--------^

You wanted to print 5 * 2 = 10 on the console. However, we see that we cannot pass 5 * 2 = 10 as an argument to System.out.println().

5 * 2 = 10 is not a single value. It is a piece of text with numeric characters, * and =.

In Java, we represent text using String. A String literal is a sequence of characters, enclosed within double quotes: " and ".

	jshell> System.out.println("5 * 2 = 10")
	| 5 * 2 = 10

Congratulations! You have now figured out how to display not just numbers on the console, but text as well!

Summary

In this step, we:

  • Were introduced to the System.out.println() method for console output
  • Used this utility to print a single PMT-Challenge table entry

Step 08: Programming Exercise PE-02

Try and solve the following exercises:

  1. Print Hello World onto the console.

  2. Print 5 * 3, as is.

  3. Print the calculated value of 5 * 3.

  4. Print the number of seconds in a day, using the System.out.println method.

  5. Do a syntax revision for the code that you write for each of the above exercises. In your code, identify the following elements:

    • Numeric and string literals
    • Expressions
    • Operators
    • Operands
    • Method calls

Step 09: Solutions to PE-02

Solution 1


	jshell> System.out.println("Hello World")
	Hello World

Solution 2


	jshell> System.out.println("5 * 3")
	5 * 3
	jshell>

Solution 3


	jshell> System.out.println(5 * 3)
	15

Solution 4


	jshell> System.out.println(60 * 60 * 24)
	86400

Step 10: Whitespace, Case sensitiveness and Escape Characters

The term whitespace refers to any sequence of continuous space, tab or newline characters.

Whitespace

Let's see a few examples of whitespace in action.

Whitespace affects the output when used in-and-around string literals.

jshell> System.out.println("Hello World")
Hello World
jshell> System.out.println("Hello      World")
Hello      World
jshell> System.out.println("HelloWorld")
HelloWorld

Whitespace is ignored by the compiler when used around numeric expressions.


	jshell> System.out.println(24 * 60 * 60)
	86400
	jshell> System.out.println(24    *    60    *    60)
	86400
	jshell>

Case Sensitive

Java is case sensitive.

System.out.println() involve pre-defined Java elements : the System class name, the out variable name,and the println method name. All are case-sensitive. If any character in these names is used with a different case, you get an error.


	jshell> system.out.println("Hello World")
	| Error:
	| package system does not exist
	| system.out.println("Hello World")
	| ^-------^

	jshell> System.Out.println("Hello World")
	| Error:
	| cannot find symbol
	| symbol: variable Out
	| System.Out.println("Hello World")
	| ^------------^

	jshell> System.out.Println("Hello World")
	| Error:
	| cannot find symbol
	| symbol: method Println(java.lang.string)
	| System.out.Println("Hello World")
	| ^---------------------^

	jshell>

Inside a string literal, the case of characters do not cause errors. The literal will be taken in and printed, as-is.

jshell> System.out.println("hello world")
hello world
jshell> System.out.println("HELLO WORLD")
HELLO WORLD

Escape Characters

An escape character is a special symbol, used with another regular symbol to form an escape sequence. In Java, the '\' (back-slash) character plays the role of an escape character. This escape sequence changes the original usage of the symbols.

If you want to print the string delimiter, the " character, you need to escape it with a \. Without it, a " character within a string literal causes an error!


	jshell> System.out.println("Hello "World")
	| Error:
	| ')' expected
	| System.out.println("Hello "World")
	|                            ^

	jshell> System.out.println("Hello \"World")
	Hello "World
	jshell>

The escape sequence \n inserts a newline.


jshell> System. out.println("Hello \n World")
Hello
 World
jshell> System.out.println("Hello n World")
Hello n World
jshell> System.out.println("Hello\nWorld")
Hello 
World
jshell>

The escape sequence \t inserts a tab.


	jshell> System.out.println("Hello \t World")
	Hello    World
	jshell> System.out.println("Hello t World")
	Hello t World
	jshell> System.out.println("Hello\tWorld")
	Hello    World
	jshell>

How do you print a \?

jshell> System.out.println("Hello \ World")
|  Error:
|  illegal escape character
|  System.out.println("Hello \ World")

You would need to escape it with another \. Printing \\ outputs the symbol \ to the console.


	jshell> System.out.println("Hello \\ World")
	Hello \ World
	jshell> System.out.println("Hello \\\\ World")
	Hello \\ World

Summary

In this step, we:

  • Were introduced to method call syntax, with System.out.println()
  • Discovered the uses of whitespace characters
  • Learned about Java escape sequences

Step 11: More On Method Calls

Let's look at method calls with a few more examples.

You know how to invoke a method with a single argument, courtesy System.out.println(3*4). Other scenarios do exist, such as

  • Calling a method without any arguments
  • Calling a method with several arguments

Let's check them out, using the built-in methods in Java Math class.

Method without parameters

In method calls, parentheses are a necessary part of the syntax. Don't leave them out!

Math.random() prints a random real number in the range [0 .. 1], a different one on each call


	jshell> Math.random
	| Error:
	| cannot find symbol
	|    symbol: Math.random
	| Math.random
	| ^------------- ^
	jshell> Math.random()
	$1 ==> 0.0424279106074651_
	jshell> Math.random()
	$2 ==> 0.8696879746593543 
	jshell> Math.random()
	$3 ==> 0.8913591586787125

Method with multiple parameters

How do we call Math.min with two parameters 23 and 45?


	jshell> Math.min 23 45
	| Error
	| cannot find symbol
	| symbol: variable min
	| Math.min 23 45
	| ^---------^
	jshell> Math.min(23 45)
	| Error
	| ')' expected
	| Math.min 23 45
	| ---------------^

While making method calls, the programmer must

  • Enclose all the parameters within parentheses
  • Separate individual parameters within the list, using the comma symbol ','.
	jshell> Math.min(23, 45)
	$4 ==> 23
	jshell> Math.min(23, 2)
	$5 ==> 2
	jshell> Math.max(23, 45)
	$6 ==> 45
	jshell> Math.max(23, 2)
	$7 ==> 2
	jshell>

Math.min() returns the minimum of two given numbers. Math.max() returns the maximum of two given numbers.

Summary

In this step, we:

  • Understood how zero, or multiple parameters are passed during a method call

Step 12: More Formatted Output

System.out.println() can accept one value as an argument at a maximum.

To display the multiplication table for 5 with a calculated value, we need a way to print both numbers and strings.

For this we would need to use another built-in method System.out.printf().

When System.out.printf() is called with a single string argument, it prints some illegible information. For now, it suffices to know, that this information is about the built-in type java.io.PrintStream.

	jshell> System.out.printf("5 * 2 = 10")
	5 * 2 = 10$1 ==> java.io.PrintStream@4e1d422d
	jshell>

The good news is, that if we call the println() method on this, the illegible stuff disappears.


	jshell> System.out.printf("5 * 2 = 10").println()
	5 * 2 = 10

The method System.out.printf() accepts a variable number of arguments:

  • The first argument specifies the print format. This is a string literal, having zero or more format specifiers. A format specifier is a predefined literal (such as %d), that formats data of a particular type (%d formats data of type int).
  • The trailing arguments are expressions,

Lots of theory? Let's break it down. Let's look at an example.

	jshell> System.out.printf("5 * 2 = %d", 5*2).println()
	5 * 2 = 10
	jshell>

System.out.printf("5 * 2 = %d", 5*2).println() gives an output 5 * 2 = 10. %d is replaced by the calculated value of 5*2.

Let's play a little more with printf:


	jshell> System.out.printf("%d %d %d", 5, 7, 5).println()
	5 7 5

Let's try to display a calculated value. In the example below 5*7 is calculated as 35.

	jshell> System.out.printf("%d %d %d", 5, 7, 5*7).println()
	5 7 35

Let's use this to print the output in the format that we want to use for multiplication table:

	jshell> System.out.printf("%d * %d = %d", 5, 7, 5*7).println()
	5 * 7 = 35

Congratulations. We are able to calculate 5*7 and print 5 * 7 = 35 successfully.

Exercise

  1. Print the following output on the console: 5 + 6 + 7 = 18. Use three literals 5, 6, 7. Calculate 18 as 5 + 6 + 7.

Solution


	jshell> System.out.printf("%d + %d + %d = %d", 5, 6, 7, 5 + 6 + 7).println()
	5 + 6 + 7 = 18
	jshell>

Playing with System.out.printf()

In the example below, there are four format specifiers (%d) and only three value arguments 5, 6, 7.


	jshell> System.out.printf("%d + %d + %d = %d", 5, 6, 7).println()
	5 + 6 + 7 = | java.util.MissingFormatArgumentException thrown: Format specifier '%d'
	| at Formatter.format (Formatter.java:2580)
	| at PrintStream.format (PrintStream.java:974)
	| at PrintStream.printf (PrintStream.java:870)
	| at (#52:1)

In a call to System.out.printf(), if the number of format specifiers exceeds the number of trailing arguments, the Java run-time throws an exception.

If the number of format specifiers is less than the number of trailing arguments, the compiler simply ignores the excess ones.


	jshell> System.out.printf("%d + %d + %d", 5, 6, 7, 8).println()
	5 + 6 + 7
	jshell>

More Format Specifiers

String values can be printed in System.out.printf(), using the format specifier %s.


	jshell> System.out.printf("Print %s", "Testing").println()
	Print Testing

Earlier, we used %d to print an int value. You cannot use %d to display floating point values.

	jshell> System.out.printf("%d + %d + %d", 5.5, 6.5, 7.5).println()
	| java.util.IllegalFormatConversionException thrown: d != java.lang.Double
	| at Formatter$FormatSpecifier.failedConversion(Formatter.java:4331)
	| at Formatter$FormatSpecifier.printInteger(Formatter.java:2846)
	| at Formatter$FormatSpecifier.print(Formatter.java:2800)
	| at Formatter.format(Formatter.java:2581)
	| at PrintStream.format(PrintStream.java:974)
	| at PrintStream.print(PrintStream.java:870)
	| at #(57:1)

Floating point literals (or expressions) can be formatted using %f.


	jshell> System.out.printf("%f + %f + %f", 5.5, 6.5, 7.5).println()
	5.500000 + 6.500000 + 7.500000
	jshell>

Summary

In this step, we:

  • Discovered how to do formatted output, using System.out.printf()
  • Stressed on the number and sequence of arguments for formatting
  • Explored the built-in format specifiers for primitive types

Step 13: Introducing Variables

In the previous steps, we worked out how to print a calculated value as part of our multiplication table.

	jshell> System.out.printf("%d * %d = %d", 5, 1, 5 * 1).println()
	5 * 1 = 5

How do we print the entire multiplication table?

We can do something like this.

	jshell> System.out.printf("%d * %d = %d", 5, 1, 5 * 1).println()
	5 * 1 = 5
	jshell> System.out.printf("%d * %d = %d", 5, 2, 5 * 2).println()
	5 * 2 = 10
	jshell> System.out.printf("%d * %d = %d", 5, 3, 5 * 3).println()
	5 * 3 = 15
	jshell> System.out.printf("%d * %d = %d", 5, 4, 5 * 4).println()
	5 * 4 = 20
	jshell>

Too much work. Isn't it?

If you carefully observe the code, these statements are very similar.

What's changing? The number in the third and fourth parameter slots changes from 1 to 4.

Wouldn't it be great to have something to represent the changing value?

Welcome variables.


	jshell> int number = 10
	number ==> 10
	jshell>

Terminology and Background

In the statement int number = 10,

  • number is a variable.
  • The literal number is the variable name.
  • The Java keyword int specifies the type of number.
  • The literal 10 provided number with an initial value.
  • This entire statement is a variable definition.

The effects of this variable definition are:

  • A specific location in the computer's memory is reserved for number.
  • This location can now hold data of type int.
  • The value 10 is stored here.

You can change the value of number variable:


	jshell> number = 11
	number ==> 11

Above statement is called variable assignment.

An assignment causes the value stored in the memory location to change. In this case, 10 is replaced with the value 11.

You can look up the value of number variable.

	jshell> number
	number ==> 11

You can change the value of a variable multiple times.

	jshell> number = 12
	number ==> 12
	jshell> number
	number ==> 12

Let's create another variable:


	jshell> int number2 = 100
	number2 ==> 100
	jshell> number2 = 101
	number2 ==> 101
	jshell> number2
	number2 ==> 101
	jshell>

The statement int number2 = 100 defines a distinct variable number2.

How do we use variables to simplify and improve the solution to PMT-Challenge?

Let's take a look.


	jshell> System.out.printf("%d * %d = %d", 5, 4, 5*4).println()
	5 * 4 = 20

Let's define a variable i, and initialize it to 1.

	jshell>int i = 1
	i ==> 1
	jshell> i
	i ==> 1
	jshell> 5*i
	$1 ==> 5

Let's update the multiplication table printf to use the variable i.

	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 1 = 5

How do we print 5 * 2 = 10?

We update i to 2 and execute the same code as before.


	jshell> i = 2
	i ==> 2
	jshell> 5*i
	$2 ==> 10
	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 2 = 10
	jshell>

You can update the value of i to any number.

The previous statement would print the corresponding multiple with 5.


	jshell> i = 3
	i ==> 3
	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 3 = 15
	jshell> i = 10
	i ==> 10_
	jshell> System.out.printf("%d * %d = %d", 5, i, 5*i).println()
	5 * 10 = 50
	jshell>

By varying the value of i, we are able to print different multiples of 5 with the same statement.

Congratulations! You made a major discovery. Variables.

Summary

In this step, we:

  • Understood the need for variables
  • Observed what different parts of a variable definition mean
  • Seen what goes on behind-the-scenes when a variable is defined

Step 14: Programming Exercise PE-03 (With solution)

  1. Create three integer variables a, b and c.
    • Write a statement to print the sum of these three variables.
    • Change the value of a, and then print this sum.
    • Then again, change the value of b and print this sum.

Solution to PE-03


	jshell>int a = 5
	a ==> 5
	jshell>int b = 7
	b ==> 7
	jshell>int c = 11
	c ==> 11
	jshell>System.out.printf("a + b + c = %d", a+b+c).println()
	a + b + c = 23
	jshell>a = 2
	a ==> 2
	jshell>System.out.printf("a + b + c = %d", a+b+c).println()
	a + b + c = 20
	jshell>b = 9
	b ==> 9
	jshell>System.out.printf("a + b + c = %d", a+b+c).println()
	a + b + c = 22
	jshell>
	

Step 15: Using Variables

Variables should be declared before use.


	jshell>newVariable
	| Error:
	| cannot find symbol
	| symbol: newVariable
	| newVariable
	  ^------------^

Java is a strongly typed programming language. This means two things:

  • Every variable in a program must be declared, with a type.
  • Values assigned to a variable should be:
    • same type as the variable's type, or
    • compatible with the variable's type

	jshell> int number = 5.5
	| Error:
	| incompatible types: possible lossy conversion from double to int
	| int number = 5.5
	|_____________^---^
	jshell>

The variable number is an integer, mathematically a number. The constant 5.5 is a number as well.

Why does it result in error?

5.5 is a floating-point number of type double. We are trying to store a double inside a memory slot meant for int.

Let's consider another example:


	jshell> int number = "Hello World"
	| Error:
	| incompatible types: java.lang.String cannot be converted to int
	| int number = "Hello World"
	|_____________^--------------^
	jshell>

number is an int variable, and we are trying to store a String value "Hello World". Not allowed.

Summary

In this step, we:

  • Observed how declaring a variable is important
  • Understood the compatibility rules for basic Java types

Step 16: Variables: Behind-The-Scenes

Giving a value to a variable, during its declaration, is called its initialization.


	jshell> int number = 5
	number ==> 5
	jshell>

The statement int number = 5 combines a declaration and the initialization of number.

The next statement int number2 = number is a little different.


	jshell> int number2 = number
	number2 ==> 5
	jshell> number2
	number2 ==> 5
	jshell>

The initial value for number2 is another variable, which is previously defined (number).

Here's what goes on behind the scenes with int number2 = number:

  • A memory slot is allocated for number2 with size of int.
  • Value stored in number's slot is copied to number2's slot.

In example below, a = 100, c = a + b, a = c are called assignments.


	jshell> int a = 5
	a ==> 5
	jshell> int b = 10
	b ==> 10
	jshell> a = 100
	a ==> 100
	jshell> int c
	c ==> 0
	jshell> c = a + b
	c ==> 110
	jshell> a = c
	a ==> 110
	jshell> int d = b + c
	d ==> 120
	jshell>

Variable assignment is allowed to happen in multiple ways:

  • From a literal value, to a variable, having compatible types. The statement a = 100 is one such example.
  • From a variable to another variable, of compatible types.The statement a = c illustrates this case.
  • From a variable expression to a variable. This expression can be formed with variables and literals of compatible types, and is evaluated before the assignment. The statement c = a + bbelow is an example of this.

An assignment to a constant literal is not allowed.


	jshell> 20 = var
	| Error:
	| unexpected type
	| required : variable
	| found : value
	| 20 = var
	| ^^

	jshell>

Summary

In this step, we discussed how to provide variables with initial values and the basics of assigment.

Step 17: Naming Variables

The syntax rules for variable definition are quite strict. Do we have any freedom with the way we name variables? The answer is "yes", to some extent.

Variable Name Rules

Here are the Java rules for variable names, in a nutshell:

A variable name can be a sequence, in any order, of

  • Letters [A-Z, a-z]
  • Numerical digits [0-9]
  • The special characters '$' ("dollar") and '_' ("underscore")

With the following exceptions:

  • The name cannot start with a numerical digit [0-9]
  • The name must not match with a predefined Java keyword

Let's now see what kinds of errors the compiler throws if you violate these naming rules.

Error : Using a invalid character -


	jshell> int test-test
	| Error:
	| ';' expected
	| int test-test
	|         ^

Error : Starting name of a variable with a number


	jshell> int 2test
	| Error:
	| '.class' expected 
	| int 2test
	|     ^
	| Error:
	| not a statement
	| int 2test
	|      ^--^
	| Error:
	| unexpected type
	| required: value
	| found: class
	| int 2test
	| ^--^
	| Error:
	| missing return statement
	| int 2test
	| ^-------^

	jshell>

Error : Using a keyword as the name of variable

In Java, certain special words are called keywords. For example, some of the data types we looked at - int, double. These keywords cannot be used as variable names.


	jshell> int int
	   ...> ;	
	| Error:
	| '.class' expected
	| int int
	|     ^
	| Error:
	| unexpected type
	| required: value
	| found: class
	| int int
	| ^--^
	| Error:
	| missing return statement
	| int int
	| ^------...

Variable Naming Conventions

Good programmers write readable code. Giving proper names to your variables makes your code easy to read.

In a football scorecard application, using a name s for a score variable is vague. Something like score carries more meaning, and is preferred.


	jshell> int s
	s ==> 0
	jshell> int score
	score ==> 0
	jshell>

The Java community, with its wealth of experience, suggests that programmers follow some naming conventions. Above examples is one of these. Violation of these rules does not result in compilation errors. That's why, these are called conventions.

In Java, another convention is to use CamelCase when we have multiple words in variable name.

 
	jshell> int noOfGoals
	noOfGoals ==> 0

noOfGoals is easier to read than noofgoals.

Both noOfGoals and NoOfGoals are equally readable.

But in Java, the convention followed is to start variable names with a lower case letter. So, for a variable, noOfGoals is preferred.

*** NOT RECOMMENDED***

	jshell> int NoOfGoals
	NoOfGoals ==> 0

Your variable names can be very long.


	jshell> int iThinkThisIsQuiteALongName
	iThinkThisIsQuiteALongName ==> 0
	jshell> int iThinkThisIsSuchALongNameThatIMightNeverUseSuchALongNameAgain
	iThinkThisIsSuchALongNameThatIMightNeverUseSuchALongNameAgain ==> 0

However, avoid using very long variable names.

Use the shortest meaningful and readable name possible for your variables.

Summary

In this step, we:

  • Explored the Java language rules for variable names
  • Understood that there are conventions to guide us
  • Looked at a popular variable naming conventions

Step 18: Introducing Primitive Types

The table below lists the primitive types in Java.

Type of ValuesJava Primitive TypeSize (in bits)Range of ValuesExample
Integral Valuesbyte8-128 to 127byte b = 5;
Integral Valuesshort16-32,768 to 32,767short s = 128;
Integral Valuesint32-2,147,483,648 to 2,147,483,647int i = 40000;
Integral Valueslong64-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807long l = 2222222222;
Floating-Point Valuesfloat32approximately ±3.40282347E+38F. NOT very precise (avoid for financial/scientific math)float f = 4.0f;
Floating-Point Valuesdouble64approximately ±1.79769313486231570E+308. NOT very precise, but better than float (also avoid for financial/scientific math)double d = 67.0;
Character Valueschar16'\u0000 to '\uffffchar c = 'A';
Boolean Valuesboolean1true or falseboolean isTrue = false;

Let's now look at how we create data of these types, and store them in memory.

We choose type for data, based on:

  • The type of data we want to store
  • The range of values we would want to store

Note: In the above examples, we used semi-colon ; character at the end. This is the Java statement separator, which is not mandatory in JShell for single statements. However, it is a must when you use code editors and IDE's, to write Java code.

Integer Types

The only difference among the integer types is their storage capacity.


	jshell> byte b = 5
	b ==> 5
	jshell> short s = 128
	s ==> 128
	jshell> int i = 40000
	i ==> 40000
	jshell> long l = 2222222222
	l ==> 2222222222
	jshell>

Floating Value Types

double is the default type for floating type values with size 64 bits.

	jshell> double d = 67.0
	d ==> 67.0

float occupies 32 bits. float literals need to have a suffix 'f' (as in 4.0f).


	jshell> float f = 4.0f
	f ==> 4.0

If this suffix f is omitted, a floating-point number is assumed to be a double. You cannot store a 64 bit value into 32 bits.

	jshell> float f2 = 4.0
	| Error:
	| incompatible types: possible lossy conversion from double to float
	| float f2 = 4.0
	|            ^-^

You can store float value in double. Remember, both types store similar kind of values and a float value is only 32 bits where as double has 64 bits.

	jshell> double d2 = 67.0f
	d2 ==> 67.0

Character Type

The character type char can store a single character symbol. The symbol must be enclosed within a pair of single quotes, ' and '.


	jshell> char c = 'A'
	c ==> 'A'

Following are a few char declaration errors: Not using single quotes and trying to store multiple characters.

	jshell> char ch = A
	| Error:
	| cannot find symbol
	| symbol: variable A
	| char ch = A
	|           ^

	jshell> char cab = 'AB'
	| Error:
	| unclosed character literal
	| char cab = 'AB'
	|            ^

Boolean Type

The concept of a boolean type is rooted in mathematical logic. The data type can store two possible values, true and false. Both are case-sensitive labels, but not enclosed in quotes.


	jshell> boolean isTrue = false
	isTrue ==> false
	jshell> isTrue = true
	isTrue ==> true
	jshell> boolean isFalse = True
	| Error:
	| cannot find symbol
	| symbol: variable True
	| boolean isFalse = True
	|                   ^--^

	jshell> isFalse = False
	| Error:
	| cannot find symbol
	| symbol: variable False
	| isFalse = False
	|           ^---^

boolean data are mostly used in expressions used to form logical conditions in your code. We will talk more about this - when we explore Java conditionals.

Summary

In this step, we:

  • Looked at the primitive data types provided in Java
  • Understood the categories into which these types are divided
  • Saw what kind of data can be stored in each primitive type

Step 19: Choosing A Data Type

How do we choose the data type for a variable? Let's look at a few examples.

Example 1 : Goals in a Football match

Consider a sports broadcaster that writes a program to track football scores. In a football game there are two teams playing. A game is generally 90 minutes long, with extra time pushing it to 120 minutes at the most. Practically speaking, the scorelines are never huge. From a practical standpoint, the number of goals scored in a match would never exceed 7200 (the number of seconds in 120 minutes). Playing it a bit safe, a short data type would be enough to store the score of each side (though a byte would be more than enough).


	jshell> short numTeamAGoals = 0
	numTeamAGoals ==> 0
	jshell> short numTeamBGoals = 0
	numTeamBGoals ==> 0
	jshell>

Example 2 : How do we store population of the world?

We know that the global count of humans is well over 7 billion now, so the only integer data type that can store it is a long.


	jshell> long globalPopulation = 7500000000;
	globalPopulation ==> 7500000000
	jshell>

Example 3 : How do we store average rainfall in a month?

Rainfall is usually measured in millimeters (mm), and we know computing an average over 30 days is very likely to yield a floating-point number. Hence we can use a float, or for more accuracy, a double to store that average.


	jshell> float avgJanRainfall = 31.77f;
	avgJanRainfall ==> 31.77
	jshell> double averageJanRainfall = 31.77
	averageJanRainfall ==> 31.77
	jshell>

Example 4 : Grades of a Student

Classroom grades in high school are generally A, B, C , ....

For a program that generates a grade report, a char type would be the best bet.


	jshell> char gradeA = 'A'
	gradeA ==> 'A'
	jshell> char gradeB = 'B'
	gradeB ==> 'B'
	jshell> char gradeC = 'C'
	gradeC ==> 'C'
	jshell> char gradeD = 'D'
	gradeD ==> 'D'
	jshell> char gradeF = 'F'
	gradeF ==> 'F'
	jshell>

Example 5 : Is a Number Odd or Even?

A boolean isNumEven is a good bet, with a default initial value of false. It can be changed to true if the number turns out to be even.


	jshell> boolean isNumEven
	isNumEven ==> false
	jshell> isNumEven = true
	isNumEven ==> true
	jshell>

Summary

In this step, we:

  • Understood how to think while choosing a data type
  • Explored cases for integer, floating-point, character and boolean data

Step 20: The Assignment Operator =

We were first exposed to the assignment operator while discussing variable assignment.

We are allowed to use expressions to assign values to variables, using code such as c = a + b.

Let's look at a few additional ways assignment can be done.


	jshell> int i = 10
	i ==> 10
	jshell> int j = 15
	j ==> 15
	jshell> i = j
	i ==> 15
	jshell>

Let's consider the following example:

	jshell> i = i * 2
	i ==> 30
	jshell>

The same variable i appears on both the right-hand-side (RHS) and left-hand-side (LHS). How would that make any sense?

The expression on the RHS is independently evaluated first. The value we get is next copied into the memory slot of the LHS variable.

Using the logic above, the assignment i = i * 2 actually updates the value of i (initially 15) to 30 (doubles it).

Java also does the right thing when it encounters the puzzling statement i = i + i, where i is all over the place! The code doubles the value of i, and this reflects on the JShell output.


	jshell> i = i + i
	i ==> 60

The next example is self explanatory.

	jshell> i = i - i
	i ==> 0

Variable Increment and Decrement

We have already seen increment by assignment:


	jshell> int i = 0
	i ==> 0
	jshell> i = i + 1
	i ==> 1
	jshell> i = i + 1
	i ==> 2
	jshell> i = i + 1
	i ==> 3
	jshell>

Conversely, the statement i = i - 1 is called a variable decrement. This can also be done repeatedly, and i changes value every time.


	jshell> i = i - 1
	i ==> 2
	jshell> i = i - 1
	i ==> 1
	jshell> i = i - 1
	i ==> 0
	jshell>
	

Summary

In this step, we:

  • Looked at the assignment operator = in a more formal way
  • Looked at heavily used scenarios for assignment, such as increment and decrement

Step 21: Assignment Puzzles, and PMT-Challenge revisited

Now that we understand how to define, assign to, and use variables in expressions, it's time to push the boundaries a bit. The following examples explore how we could play around with variables in our code.

Snippet-1 : Pre- and Post- Increment and Decrement

There are two short-hand versions for increment. number++ denotes post-increment. Conversely, ++number means pre-increment.

Operator ++ can be applied only to variables of integer types, which are byte, short, int and long.

number++ is equivalent to the statement number = number + 1


	jshell> int number = 5
	number ==> 5
	jshell> number++
	$1 ==> 5
	jshell> number
	number ==> 6
	jshell> ++number
	$2 ==> 7
	jshell> number
	number ==> 7
	jshell>

number-- is post-decrement. On the other hand, --number is pre-decrement.


	jshell> number--
	$3 ==> 7
	jshell> number
	number ==> 6
	jshell> --number
	$4 ==> 5
	jshell> number
	number ==> 5
	jshell>

What is the difference between prefix and postfix vesions?

Although both prefix and postfix versions achieve the same visible result in above examples, there is a slight difference. We will explore this later.

Snippet-2 : Compound Assignment Operators

The compound assignment operator combines the = with a numeric operator.

i += 2 : Add 2 to the current value of i


	jshell> int i = 1
	i ==> 1
	jshell> i = i + 2
	i ==> 3
	jshell> i += 2
	$1 ==> 5
	jshell>

i -= 1 : Subtract 1 from the current value of i


	jshell> i
	i ==> 5
	jshell> i -= 1
	$2 ==> 4
	jshell> i
	i ==> 4
	jshell>

i *= 4 : Multiply i with 4, and store the result back into i


	jshell> i *= 4
	$3 ==> 20
	jshell> i
	i ==> 20
	jshell>

i /= 4 : Divide i by 4, and store the result back into i


	jshell> i /= 4
	$4 ==> 5
	jshell> i
	i ==> 5
	jshell>

i %= 2 : Divide i by 2, and store the remainder back into i


	jshell> i %= 2
	$5 ==> 1
	jshell> i
	i ==> 1
	jshell>

Summary

In the step, we:

  • Looked at the built-in Java increment and decrement operators
  • Explored the side-effects of prefix and postfix versions of these operators
  • Seen the advantages of compound assignment

Step 22: Some JShell Usage Tips

  • Shortcuts
    1. Toggling to limits of current prompt entry
      • 'Ctrl+a' : to start of line
      • 'Ctrl+e' : to end of line
    2. Moving up and down history of completed prompt inputs
      • up-arrow key : move back in time
      • down-arrow key : move forward in time
    3. Reverse-keyword-search
      • Search for a term, in reverse order of JShell prompt inputs history : input 'Ctrl+r'
      • Scrolling within matches (in reverse order of history) : repeatedly input 'Ctrl+r'
  • /exit : resets and exits the JShell session, clearing all stored variables values.
  • JShell internal variables : $1, $2, and so on.
    • When expressions involving literals and/or previously declared variables are entered as-is, without assignment, those expressions are still evaluated. The result is stored in such an internal variable, and is available for use until the JShell session is reset.
  • Variable Declaration rules relaxation
    1. Single Java statements need not be terminated with the separator ';'.
    2. If multiple statements are entered on a single line at the prompt, successive statements must be separated by the ';'. However, the trailing ';' can still be omitted.

Summary

In this step, we:

  • Explored some useful keyboard shortcuts for JShell commands
  • Understood the idea behind JShell internal variables
  • Observed how JShell reduces typing effort, by relaxing some coding rules

Step 23: Introducing Conditionals - the if

The PMT-Challenge needs us to print a total of 10 table entries. The for loop is a suitable iteration mechanism to get this done. The word loop means exactly what the English dictionary says.

As i varies from 1 through 10, do some stuff involving i

For the PMT-Challenge, do some stuff would be the call to System.out.printf().

The way a for loop is structured is:


	for(initialization; condition; update) {
		statement1;
		statement2;
	}

Here's how above code runs

  1. Execute initialization code.
  2. If condition evaluates to true, execute statements. Else, go out of loop.
  3. Execute update
  4. Repeat 2 and 3

Does it sound complex? Let's break it down.

Let's start with understanding what condition is all about.

Logical Operators

condition represents a logical value(a true or a false).

Turns out Java has a class of logical operators, which can be used with operands within logical expressions, evaluating to a boolean value.

While in school, you probably used the = symbol to compare numbers.

The world of Java is a little different. = is assignment operator. == is the comparison operator.


	jshell> int i = 10
	i ==> 10
	jshell> i == 10
	$1 ==> true
	jshell> i == 11
	$2 ==> false

These are other comparison operators as well, such as < and >.


	jshell> i < 5
	$3 ==> false
	jshell> i > 5
	$4 ==> true

<= and >= are simple extensions.


	jshell> i <= 5
	$4 ==> false
	jshell> i <= 10
	$5 ==> true
	jshell> i >= 10
	$6 ==> true
	jshell>

Conditionals: The "if" Statement

We would want to execute specific lines of code only when a condition is true.

Enter if statement.

An if statement is structured this way:


	if (condition) {
		statement;
	}

statement is executed only if condition evaluates to true.

Typically, all the code that we write is executed always.

In the example below, i is less than 5 is always printed.


	jshell> int i = 10
	i ==> 10
	jshell> System.out.println("i is less than 5")
	i is less than 5

Using the if statement, we can control the execution of System.out.println("i is less than 5");.


	jshell> if (i < 5)
	   ...> System.out.println("i is less than 5");
	jshell> 

The condition i < 5 will evaluate to false, since i is currently 10. Nothing is printed to console.

Let's change i to 4 and execute the if condition.


	jshell> i = 4
	i ==> 4
	jshell> if (i < 5)
	   ...> System.out.println("i is less than 5");
	i is less than 5
	jshell>

i is less than 5 is printed to console.

By controlling the value stored in the variable i, we are able to control whether the statement System.out.println("i is less than 5"); actually runs.

Hurrah! We just achieved conditional execution!

Just as we can compare a variable with a literal, it is possible to compare the values of two variables. The same set of comparison operators, namely ==, <, >, <= and >= can be used.


	jshell> int number1 = 5
	number1 ==> 5
	jshell> int number2 = 7
	number2 ==> 7
	jshell> if (number2 > number1)
	   ...> System.out.println("number2 is greater than number1");
	number2 is greater than number1

	jshell> number2 = 3
	number2 ==> 3
	jshell> if (number2 > number1)
	   ...> System.out.println("number2 is greater than number1");

	jshell>

Summary

In this step, we:

  • Understood the need for a conditionals
  • Were introduced to the concept of logical expressions, and conditional operators
  • Explored usage of the Java if statement

Step 24: Programming Exercise PE-04


  1. Create four integer variables a, b, c and d. Write an if statement to print if the sum of a and b is greater than the sum of c and d.

  2. Store three numerical values as proposed angles of a triangle in integer variables angle1, angle2 and angle3. Create an if statement to state whether these three angles together can form a triangle.

    Hint: A triangle is a closed geometric figure with three angles, whose sum must exactly equal 180 degrees.

  3. Have a variable store an integer. Create an if statement to find out if it's an even number.

    Hint: Use operator %.

Step 25: Solution to PE-04

Solution 1


	jshell> int a = 5
	a ==> 5
	jshell> int b = 7
	b ==> 7
	jshell> int c = 4
	c ==> 4
	jshell> int d = 3
	d ==> 3
	jshell> if (a + b > c + d)
	   ...> System.out.println("a and b together tower above c plus d");
	a and b together tower above c plus d

	jshell>

Solution 2


	jshell> int angleOne = 55
	angleOne ==> 55
	jshell> int angleTwo = 65
	angleOne ==> 55
	jshell> int angleThree = 60
	angleOne ==> 55
	jshell> if (angleOne + angleTwo + angleThree == 180)
	   ...> System.out.println("The three angles together form a triangle");
	The three angles together form a triangle

	jshell> angleThree = 75
	angleOne ==> 55
	jshell> if (angleOne + angleTwo + angleThree == 180)
	   ...> System.out.println("The three angles together form a triangle");

	jshell>

Solution 3


	jshell> int num = 10
	num ==> 10
	jshell> if (num % 2 == 0)
	   ...> System.out.println("The number is even");
	The number is even

	jshell> num++
	num ==> 11
	jshell> if (num % 2 == 0)
	   ...> System.out.println("The number is even");

	jshell>

Step 26: if Statement again

Let's look at a few more examples of if statements.

Snippet-1

Here's a basic example of conditional execution.


	jshell> int i = 5
	i ==> 5
	jshell> if (i == 5)
	   ...> System.out.println("i is odd");
	i is odd

Let's add two statements to the second line.

	jshell> if (i == 5)
	   ...> System.out.println("i is odd"); System.out.println("i is prime");
	i is odd
	i is prime

	jshell>

Both text messages are printed out.

Let's change value of i to 6 and execute again.


	jshell> i = 6
	i ==> 6
	jshell> if (i == 5)
	   ...> System.out.println("i is odd"); System.out.println("i is prime");
	i is prime

	jshell>

i is prime is printed to console. Why?

Why is this statement executed when the condition is false?

The if statement, by default, binds only to the next statement.

It does not control the execution of System.out.println("i is prime");, which in fact runs unconditionally, always.

Is there a way we can ensure conditional execution of a two statements? And more than two?

Snippet-2 : if with statement blocks

We seem to have pulled a rabbit out of the hat here, haven't we! The rabbit lies in the pair of braces : '{' and '}'.

They are used to group a sequence of statements together, into a block. Depending on the condition value (true or false), either all the statements in this block are run, or none at all.


	jshell> int i = 5
	i ==> 5
	jshell> if (i == 5) {
	   ...> System.out.println("i is odd");
	   ...> System.out.println("i is prime");
	   ...> }
	i is odd
	i is prime

	jshell> i = 6
	i ==> 6
	jshell> if (i == 5) {
	   ...> System.out.println("i is odd");
	   ...> System.out.println("i is prime");
	   ...> }

	jshell>

It is considered good programming practice to always use blocks in an if conditional. Here is an example:


	if (i == 5) {
		System.out.println("i is odd");
	}

A block can also consist of a single statement! This improves readability of code.

Summary

In this step, we:

  • Saw the importance of using statement blocks with if conditionals
  • Understood how control flow can be made more readable

Step 27: Introducing Loops: The for Statement

The PMT-Challenge needs us to print a total of 10 table entries. The for loop is a suitable iteration mechanism to get this done.

The word loop means exactly what the English dictionary says. As i varies from 1 through 10, do some stuff involving i

for loop is built this way:


	for(initialization; condition; update) {
		statement1;
		statement1;
	}

Here's how above code runs:

  1. Execute initialization code.
  2. If condition evaluates to true, execute statements. Else, go out of loop.
  3. Execute update
  4. Repeat 2 and 3

We've already seen these components in isolation:

  • initialization : int i = 1
  • condition : i <= 10
  • update : i++

Let's now put them together to get the bigger picture. Here is how it might look:


	for (int i = 1; i <= 10; i++) {
		System.out.println("Hello World");
	}

This loop, when executed, prints the message "Hello World" on a separate line, for a total of 10 times.

Snippet-1 : PMT-Challenge Solution

We need to replace the "Hello World" message with the console print of a table entry. This print is controlled by i taking values from 1 through 10.


	jshell> int i
	i ==> 0
	jshell> for (i=0; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 5, i, 5*i).println();
	   ...> }
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 2
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50

Snippet-1 Explained
  1. The first step is the initialization: i = 1.
  2. After this, the statement System.out.printf("%d * %d = %d", 5, i, 5*i).println(); is executed once.
  3. Then, the update occurs: i++.
  4. Immediately after, the condition i<=10 is evaluated. It returns true. Progress happens. Since it is a for loop, the statement is executed again.
  5. Thereafter, this sequence is executed until i gets a value of 11 (due to successive updates).
  6. The moment i reaches 11, , the condition becomes false. The looping within the for terminates.

Meanwhile, the Multiplication Table for 5, for entries 1 through 10 has been displayed!

Now, wasn't that really elegant? It sure was!

Let's pat ourselves on the back for having reached this stage of learning. This elegant, yet powerful technique (loops) is used in almost every Java program that's written.

Summary

In this step, we:

  • Observed why we need a looping construct, such as the for
  • Understood the mechanism of a for loop
  • Used a for loop in iteration, to solve our PMT-Challenge

Step 28: Programming Exercise PE-05

  1. Repeat the entire process at arriving at the Multiplication Table Print problem, now for the number 7. Start with a fresh JShell session, if you're still using an existing one for quite some time (Rinse, and repeat!).
  2. Use the final solution to print Multiplication Tables for 6 and 10.
  3. Print the integers from 1 to 10.
  4. Print the integers from 10 to 1.
  5. Print the squares of the integers from 1 to 10.
  6. Print the squares of the first 10 even integers.
  7. Print the squares of the first 10 odd integers.

Step 29: Solution to PE-05

Solution 2


	jshell> int i
	i ==> 0
	jshell> for (i=0; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 6, i, 6*i).println();
	   ...> }
	6 * 1 = 6
	6 * 2 = 12
	6 * 3 = 18
	6 * 4 = 24
	6 * 5 = 30
	6 * 6 = 36
	6 * 7 = 42
	6 * 8 = 48
	6 * 9 = 54
	6 * 10 = 60

	jshell> i = 0
	i ==> 0
	jshell> for (i=0; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 10, i, 10*i).println();
	   ...> }
	10 * 1 = 10
	10 * 2 = 20
	10 * 3 = 30
	10 * 4 = 40
	10 * 5 = 50
	10 * 6 = 60
	10 * 7 = 70
	10 * 8 = 80
	10 * 9 = 90
	10 * 10 = 100

Solution 3


	jshell> for (int i=1; i<=10; i++) {
	   ...> System.out.printf(i).println();
	   ...> }
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10

Solution 4

This is the first time we are using i--. Isn't this interesting?


	jshell> for (int i=10; i>0; i--) {
	   ...> System.out.printf(i).println();
	   ...> }
	10
	9
	8
	7
	6
	5
	4
	3
	2
	1

Solution 5


	jshell> for (int i=1; i<=10; i++) {
	   ...> System.out.printf(i*i).println();
	   ...> }
	1
	4
	9
	16
	25
	36
	49
	64
	81
	100

Solution 6

update of a for loop can do a lot of things. Here, we are using i += 2.


	jshell> for (int i=2; i<20; i += 2) 
	   ...> System.out.printf(i*i).println();
	   ...> }
	4
	16
	36
	64
	100
	144
	196
	256
	324
	400

Solution 7


	jshell> for (int i=1; i<=19; i += 2) {
	   ...> System.out.printf(i*i).println();
	   ...> }
	1
	9
	25
	49
	81
	121
	169
	225
	289
	361

Step 30: Puzzling You With for

In the conceptual form of the for construct:


	for (initialization; condition; updation) {
		statement;
		statement;
		//...
		statement;
	}

It may surprise you that each one of initialization, condition, updation and statements block is optional. They can all be left out individually, in combination, or all altogether!! Let's examine a few interesting cases in code.

  1. Empty initialization, Empty Statement

Increments the control variable in quick succession until the condition evaluates to false.


	jshell> int i = 1
	i ==> 1
	jshell> for (; i<=10; i++);
	jshell> i
	i ==> 11
	jshell>

  1. Multiple initializations, Empty Statement

You can have multiple statements in initialization and update separated by ,.


	jshell> int j
	i ==> 11
	jshell> for (i=1, j=2; i<=10; i++, j++);
	jshell> i
	i ==> 11
	jshell> j
	j ==> 12
	jshell>

In the example below, i is incremented and j is decremented.


	jshell> for (i=1, j=2; i<=10; i++, j--);
	jshell> i
	i ==> 11
	jshell> j
	j ==> -8
	jshell>

  1. Infinite Loop

An infinite loop is one where the condition is left empty. An empty condition always evaluates to true. Since a for loop only terminates when the condition becomes false, such a loop this never terminates.

It can only be terminated externally with a keyboard interrupt (CTRL + c).


	jshell> for (;;);

	^C
	jshell>

  1. Statement Block in for

As in case of the if conditional statement, we can have statement blocks in for loops as well. As before, we enclose the statement set between braces ('{' and '}'). The statements are executed repeatedly, in the same order as they appear in the block.


	jshell> for (i=1; i<=5; i++) {
	   ...> System.out.println("No 1");
	   ...> System.out.println("No 2");
	   ...> }
	No 1
	No 2
	No 1
	No 2
	No 1
	No 2
	No 1
	No 2
	No 1
	No 2

Summary

In this step, we saw that all components of a for loop are optional:

  • initialization
  • condition
  • updation
  • statement block

Step 31: A Review Of Basic Concepts

Before we go further, let's quickly get a Big Picture of what we are doing here!

A computer is a machine that does a job for you and me. It is can be used to run tasks that we find complicated, time-consuming, or even boring! For instance, a laptop can play music from a CD, videos from the web, or fire a print job.

We have mobile phones around us, which are mini versions of computers. Then there are others, ranging from blood-sugar monitors to weather-forecast systems. Computers surround us, wherever we go!

Any computer is made up of two basic layers:

  • The hardware: Consists of all the electronic and mechanical parts of the computer, including the electronic circuits.
  • The software: Describes the instructions fed into the computer, which are stored and run on its hardware.

If the human body were a computer,

  • Its hardware would consist of the various organs (such as limbs, blood and heart)
  • Its software would be the signals from the nervous system, which drive these organs.

Computer programming involves writing software instructions to run tasks on a computer. The user who gives these instructions is called the programmer. Often, computer programming involves solving challenging, and very interesting problems.

In the previous steps, we introduced you to the basic Java language concepts and constructs.

We solved a programming challenge, the PMT-Challenge using basic Java constructs.

We used JShell REPL to learn the following concepts, Step by-step:

  • Expressions, Operators and Statements
  • Variables and Formatted Output
  • Conditionals and Loops

At each step, we applied fresh knowledge to enhance our solution to the PMT-Challenge

Hope you liked the journey thus far. Next sections delve deeper into Java features, using the same Step by-step approach. We will catch up again soon, hopefully!

Understanding Methods

Feeling good about where you are right now? You just created an elegant, yet powerful solution to the PMT-Challenge, using:

  • Operators, variables and expressions
  • Built-in formatted output
  • Conditionals for control-flow, and
  • Iteration through loops

And guess what we ended up with? A good-looking display of a Multiplication Table! There's a good chance people in your circles want to see it, use it and maybe share it among their friends.

However, some might be unhappy that it works only for 5, and not for 8 and 7. Maybe it would, but then they would need to type in those lines of code again. This might disappoint them, and your new found popularity would slide downhill.

Surely a more elegant solution exists, a pattern waiting to unravel itself.

Exist it does, and the mechanism to use it lies with Java methods. A method is a feature that allows you to group together a set of statements, and give it a name. This name represents the functionality of that set, which can be re-used when necessary.

A method is essentially a routine that performs a certain task, and can do it any number of times it is asked to. It may also return a result for the task it performs. The syntax for a method definition is along these lines:

ReturnType   methodName () {
  method-body
}

Where

  • methodName is the name of the routine
  • method-body is the set of statements
  • a pair of braces { and } enclose method-body
  • ReturnType is the type of methodName's return value

Summary

In this step, we:

  • Examined the need for labeling code, and its reuse
  • Learned that a Java method fits the bill
  • Saw how a method definition looks like, conceptually

Step 01 : Defining A Simple Method

We will start off, by writing a simple method that prints "Hello World" twice on your screen.


	jshell> void sayHelloWorldTwice() {
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> }
	| created method sayHelloWorldTwice()

A little bit of theory:

  • Above code for the method is called method definition.
  • void indicates that the method does not return any computed result - We will examine return values from methods, a little later.

When the code ran, it didn't exactly welcome us twice, did it? All we got was a boring message from JShell, mumbling created method sayHelloWorldTwice().

That's because defining a method does NOT execute its statement body.

Since the statement block is not stand-alone anymore, its functionality needs to be invoked. This is done by writing a method call.

Let's look at a few examples for method calls.


	jshell> sayHelloWorldTwice
	| Error:
	| cannot find symbol
	| symbol: variable sayHelloWorldTwice
	| sayHelloWorldTwice
	| ^----------------^

	jshell> sayHelloWorldTwice()
	Hello World
	Hello World
	

All that we had to do was to add parantheses to name of the method.

The trailing ';' can be left out in JShell, and is another example of syntax rules being relaxed.

Method names need to follow the same rules as variable names.

Summary

In this step we:

  • Got our hands dirty coding our first method
  • Learned that defining and invoking methods are two different steps

Step 02: Exercise-Set PE-01

Let's now reinforce our basic understanding of methods, by trying out a few exercises.

Exercise Set -5

  1. Write and execute a method named sayHelloWorldThrice to print Hello World thrice.

  2. Write and execute a method that prints the following four statements:

    I've created my first variable

    I've created my first loop

    I've created my first method

    I'm excited to learn Java

Solutions to PE-01

Solution-1


	jshell> void sayHelloWorldThrice() {
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> }
	| created method sayHelloWorldThrice()

	jshell> sayHelloWorldThrice()
	Hello World
	Hello World
	Hello World

Solution-2

 
	jshell> void sayFourThings() {
	   ...> System.out.println("I've created my first variable");
	   ...> System.out.println("I've created my first loop");
	   ...> System.out.println("I've created my first method");
	   ...> System.out.println("I'm excited to learn Java");
	   ...> }
	| created method sayFourThings()

	jshell> sayFourThings()
	I've created my first variable
	I've created my first loop
	I've created my first method
	I'm excited to learn Java

Step 03: Editing A Method Definition (Jshell Tips)

Snippet-01: Editing sayHelloWorldTwice()

	jshell> void sayHelloWorldTwice() {
	   ...> System.out.println("Hello World");
	   ...> System.out.println("Hello World");
	   ...> }
	| created method sayHelloWorldTwice()

The /methods command lists out the methods defined in the current session.

	jshell> /methods
	| void sayHelloWorldTwice()
	jshell>

The /list command lists the code of the specified method.


	jshell> /list sayHelloWorldTwice
	59 : void sayHelloWorldTwice() {
	System.out.println("HELLO WORLD");
	System.out.println("HELLO WORLD");
	}
	jshell>

The /edit command allows you to modify the method definition, in a separate editor window.


	jshell> /edit sayHelloWorldTwice
	| modified method sayHelloWorldTwice
	jshell> sayHelloWorldTwice()
	HELLO WORLD
	HELLO WORLD
	jshell>

The /save method takes a file name as a parameter. When run, it saves the session method definitions to a file.

	
	jshell> /save backup.txt
	jshell> /exit
	| Goodbye

in28minutes$>

Summary

In this step, we explored a few JShell tips that make life easier for you while defining methods

Step 04: Methods with Arguments

We wrote the method sayHelloWorldTwice to say Hello World twice. In the programming exercise, we wanted to print Hello World thrice and we wrote a new method sayHelloWorldThrice.

Imagine you're in the Java classroom, where your teacher wants to test your Java skills by saying: "I want you to print Hello World an arbitrary number of times".

Now, that probably would test your patience as well!

How to write a method to print Hello World an arbitrary number of times?

The thing to note is the word "arbitrary", which means the method body should have no clue! This number has to come from outside the method, which can only happen with a method call.

External input to a method is given as a method argument, or parameter.

To support arguments during a call, the concept of a method needs to be tweaked to:


	ReturnType methodName(ArgType argName) {

		method-body

	}

The only addition to the concept of a method, is the phrase

ArgType argName

within the parentheses. argName represents the argument, and ArgType is its type. The next example should clear the air for you.

Snippet-01: Method with an argument: Definition

Let's look at a method definition using an argument numOfTimes.


	jshell> void sayHelloWorld(int numOfTimes) {
	   ...> }
	| created method sayHelloWorld(int)

Let's try to call the method.

	jshell> sayHelloWorld()
	| Error:
	| method sayHelloWorld in class cannot be applied to given types;
	| required : int
	| found : no arguments
	| reason : actual and formal argument lists differ in length
	| sayHelloWorld(
	|^-----------------^
	jshell> sayHelloWorld(1)
	jshell>

Method call must include the same number and types of arguments, that it is defined to have. sayHelloWorld() is an error because sayHelloWorld is defined to accept one parameter. sayHelloWorld(1) works.

However, the method does not do anything. Isn't it sad?

Snippet-02 : Passing and accessing a parameter

The next example will show you how method body code can access arguments passed during a call. Not only that, the argument values can be used during computations.


void sayHelloWorld(int numOfTimes) {
	System.out.println(numOfTimes);
}

System.out.println(numOfTimes) prints the value of argument passed.

A method can be invoked many times within a program, and each time different values could be passed to it. The following example will illustrate this fact.


	jshell> sayHelloWorld(1)
	1
	jshell> sayHelloWorld(2)
	2
	jshell> sayHelloWorld(4)
	4
	jshell> /edit sayHelloWorld
	| modified method sayHelloWorld(int)
	jshell>

Snippet-03: More complex method

Code inside a method can be any valid Java code! For instance, you could write code for iteration, such as a for loop.

Let's look at an example:


	void sayHelloWorld(int numOfTimes) {
		for (int i=1; i<=numOfTimes; i++) {
			System.out.println(numOfTimes);
		}
	}

In the above example, we printed numOfTimes a total of numOfTimes for each method call.

We print 2 two times and 4 four times.


	jshell> sayHelloWorld(2)
	2
	2
	jshell> sayHelloWorld(4)
	4
	4
	4
	4
	jshell>

Snippet-4 : Saying "Hello World", Again and again...

We wanted to print "Hello World" multiple times. Let's update the method:

	void sayHelloWorld(int numOfTimes) {
		for (int i=1; i<=numOfTimes; i++) {
			System.out.println("Hello World");
		}
	}

Isn't this cool?

	jshell> sayHelloWorld(1)
	Hello World
	jshell> sayHelloWorld(2)
	Hello World
	Hello World
	jshell> sayHelloWorld(4)
	Hello World
	Hello World
	Hello World
	Hello World
	jshell>

You can now proudly demonstrate this code to your Java instructor. Your program can print "Hello World" an arbitrary number of times!

What started off giving you a headache, will probably keep you in her good books, for the rest of your course!

Armed with this confidence booster, let's now see how Java treats mistakes you may make. .

Snippet-5 : Parameter type mismatch

Java is a strongly typed language, with strict rules laid out for type compatibility. We saw that with variables, and how they play out with expressions and assignments. The same type compatibility rules are enforced by the compiler, when it needs to match the arguments from method calls with method definition.


	jshell> sayHelloWorld("value")
	| Error:
	| incompatible types: java.lang.String cannot be converted to int
	| sayHelloWorld("value")
	|               ^-----^
	jshell> sayHelloWorld(4.5)
	| Error:
	| incompatible types: possibly lossy conversion from double to int
	| sayHelloWorld(4.5)
	|               ^-^
	jshell>

Summary

In this step, we:

  • Understood why Java supports method arguments, and how we may use them
  • Observed how method arguments lead to convenience and reuse
  • Decided to abide by type compatibility for actual arguments

Step 05: Exercise Set PE-02 (With Solutions)

Exercises

  1. Write a method printNumbers(int n) that prints all successive integers from 1 to n.
  2. Write a method printSquaresOfNumbers(int n) that prints the squares of all successive integers from 1 to n.

Solution-01


	jshell> void printNumbers(int n) {
	   ...> for(int i=0; i< n; i++) {
	   ...> System.out.println(i);
	   ...> }
	   ...> }
	| created method printNumbers(int)
	

jshell>

Solution 2


	jshell> void printSquaresOfNumbers(int n) {
	   ...> for(int i=0; i< n; i++) {
	   ...> System.out.println(i*i);
	   ...> }
	   ...> }
	| created method printSquaresOfNumbers(int)
	jshell>

Step 07: PMT-Challenge Revisited (And Some Puzzles)

A method, in its own right, provides an elegant way to name and reuse a code block. In addition, its behavior can be controlled with parameters.

Can we top-up the existing solution to the PMT-Challenge, with even more elegance? You're right, we're talking about:

  1. Writing a method to print the multiplication table for 5.
  2. Using this method to print the multiplication table for any number.

Want to take a look? Dive right in.

Here's what we did earlier:


	jshell> for (int i=1; i<=10; i++) {
	   ...> System.out.printf("%d * %d = %d", 5, i, 5*i).println();
	   ...> }
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50

Let's wrap this in a method:


	void printMultiplicationTable() {
		for (int i=1; i<=10; i++) {
		System.out.printf("%d * %d = %d", 5, i, 5*i).println();
		}
	}

You can call it to print 5 table.


	jshell> printMultiplicationTable()
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50
	jshell>
	

Summary

In this step, we:

  • Revisited the PMT-Challenge solution we had earlier
  • Enclosed its logic within a method definition, printMultiplicationTable()
  • Haven't fully explored its power yet!

Step 08: Methods With Arguments, And Overloading

The real power of a definition such as printMultiplicationTable() is when we arm it with arguments. Not verbal arguments, but "value" ones. That's right!

We will modify printMultiplicationTable() to have it accept a parameter, which would make it more flexible.

	void printMultiplicationTable(int number) {
		for (int i=1; i<=10; i++) {
			System.out.printf("%d * %d = %d", number, i, number*i).println();
		}
	}

We can now print the multiplication table of any number, by calling the method printMultiplicationTable(number).


	jshell> printMultiplicationTable(6)
	6 * 1 = 6
	6 * 2 = 12
	6 * 3 = 18
	6 * 4 = 24
	6 * 5 = 30
	6 * 6 = 36
	6 * 7 = 42
	6 * 8 = 48
	6 * 9 = 54
	6 * 10 = 60
	jshell>
	

Nothing new to explain here. We have only combined stuff you have been learning so far, most recently adding the flavor of methods to the existing code.

Soak in the power, simplicity and elegance of this program, folks!

Overloaded Methods

It turns out we can call both versions of the method, printMultiplicationTable() and printMultiplicationTable(5) :


	jshell> printMultiplicationTable()
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50
	jshell>

and


	jshell> printMultiplicationTable(5)
	5 * 1 = 5
	5 * 2 = 10
	5 * 3 = 15
	5 * 4 = 20
	5 * 5 = 25
	5 * 6 = 30
	5 * 7 = 35
	5 * 8 = 40
	5 * 9 = 45
	5 * 10 = 50
	jshell>

You can have multiple methods with same name but different number of parameters. This is called method overloading.

Summary

In this step, we:

  • Enhanced the logic of printMultiplicationTable() by passing arguments
  • Added flexibility to the PMT-Challenge solution
  • Were introduced to the concept of method overloading

Step 09: Methods With Multiple Arguments

It is possible, and pretty useful, to define methods that accept more than one argument.

We have already seen how to call two in-built Java methods, Math.max and Math.min, which accept 2 arguments each.

Time now to enrich our understanding, by writing one such method ourselves as well.

A method void sum(int, int) that computes the sum of two integers, and prints their output.


	jshell> void sum(int firstNum, int secondNum) {
	   ...> int sum = firstNum + secondNum;
	   ...> System.out.println(sum);
	   ...> }
	| created method sum(int, int)
	jshell> sum(5, 10)
	15
	jshell>

A method void sum(int, int, int) that computes the sum of three integers, and prints their output.


	jshell> void sum(int firstNum, int secondNum, int thirdNum) {
	   ...> int sum = firstNum + secondNum + thirdNum;
	   ...> System.out.println(sum);
	   ...> }
	| created method sum(int,int,int)
	jshell> sum(5, 10, 15)
	30

There are overloaded methods. They have same name sum and have different number of arguments.

Summary

In this step, we:

  • Used our understanding of method overloading to define our own methods

Step 10: Returning From A Method

A method can also be coded to return the result of its computation. Such a result is called a return value.

A lot of built-in Java methods have return values, the most notable we have seen being Math.min() and Math.max().

	jshell> Math.max(15, 25)
	$1 ==> 25
	jshell> $1
	$1 ==> 25

Math.max() does return a value, which is stored in the JShell variable $1.

A return mechanism is quite important, as it provides you the flexibility of:

  • Sharing computed results with other code and methods
  • Improving the breaking down of a problem, into sub-problems

The next example explains how you can collect a method's return value.

	jshell> int max = Math.max(15, 25)
	max ==> 25
	jshell> max
	max ==> 25
	jshell>

We are storing the return value in a variable int max.

We could define our own method that returns a value, in a similar manner. In the method sumOfTwoNumbers above, instead of displaying sum at once, we could return it to the calling-code.


	jshell> int sumOfTwoNumbers(int firstNum, int secondNum) {
	   ...> int sum = firstNum + secondNum;
	   ...> return sum;
	   ...> }
	| created method sumOfTwoNumbers(int,int)
	jshell> sumOfTwoNumbers(1, 10)
	$2 => 11

The statement return sum; is called a return statement.

When the code sum = sumOfTwoNumbers(1, 10) is run, sum collects the result returned by sumOfTwoNumbers(). You could now print sum on the console, store it in another variable, or even invoke a different method by passing it as an argument!

	jshell> sum = sumOfTwoNumbers(1, 10)
	sum => 11_
	jshell> sum = sumOfTwoNumbers(15, 15)
	sum => 30
	jshell>

Summary

In this step, we:

  • Understood the need for a return mechanism with methods
  • Explored the syntax for a return statement
  • Wrote our own method sumOfTwoNumbers() with a return value, and saw how it became more flexible

Step 11: Exercise-Set PE-04 (With Solutions)

Let's now try a few exercises on methods that return values.

Exercises

  1. Write a method that returns the sum of three integers.
  2. Write a method that takes as input two integers representing two angles of a triangle, and computes the third angle. Hint: The sum of the three angles of a triangle is 180 degrees.

Solution-01


	jshell> int sumOfThreeNumbers(int firstNum, int secondNum, int thirdNum) {
	   ...> int sum = firstNum + secondNum + thirdNum;
	   ...> return sum;
	   ...> }
	| created method sumOfThreeNumbers(int,int, int)
	jshell>

Solution-02


	jshell> int getThirdAngle(int firstAngle, int secondAngle) {
	   ...> int sumOfTwo = firstAngle + secondAngle;
	   ...> return 180 - sum;
	   ...> }
	| created method getThirdAngle(int,int)
	jshell>
	

Step 12: Java Methods, A Review

In this section, we introduced you to the concept of methods in Java.

  • We understood that methods are routines that perform a unit of computation. They group a set of statements together into a block, and need to be run by being invoked, through a method call.
  • We can define methods that accept no arguments, a single argument and multiple arguments.
  • A method can also be defined to return results of its computation, and this makes it your program more flexible.

Understanding the Java Platform

JShell is amazing to start with the basics of Java programming. It abstracts all complexities behind writing, compiling and running Java code.

What's happening behind the screens? Let's find out.

Step 01: The Java Platform - An Introduction

A computer only understands binary code, which are sequences of 0’s and 1’s (called bits). All instructions to a computer should be converted to 0’s and 1’s before execution.

When we wrote our code in JShell, how was it converted to binary code?

We write our programs in a high-level language, such as Java, as it is easier to learn, remember and maintain.

Who converts it to binary code?

Typically, Compiler is a program which understands the syntax of your programming language and converts it into binary code.

Java designers wanted it to be Platform independent. Compile the code once and run it anywhere.

However, different Operating Systems have different instruction sets - different binary code.

Java provides an interesting solution:

  • All Java compilers translate source code to an intermediate representation ( bytecode ).
  • To run Java programs (bytecode), you need a JVM (Java Virtual Machine).
    • JVM understands bytecode and runs it.
    • There are different JVM's for different operating systems. Windows JVM converts bytecode into Windows executable instructions. Linux JVM converts bytecode into Linux executable instructions.

The Java compiler translates Java source code to bytecode, which is stored as a .class file on the computer.

Summary

In this step, we:

  • Understood the role of the Java compiler in translating source code
  • Realized the need for an Intermediate Representation (IR) such as bytecode
  • Understood how the (Compiler + JVM + OS) combination ensure source code portability

Step 02: Creating a Java class

First, let's understand the concept of a class.

Let's consider an example:

A Country is a concept. India, USA and Netherlands are examples or instances of Country.

Similarly, a class is a template. Objects are instances of a class.

We will discuss more about class and object in the section on Object Oriented Programming.

The syntax to create a class, and its objects, is very simple.


	jshell> class Country {
	   ...> }
	created class Country

Let's create an instance of the class:

	jshell> Country india = new Country();
	india ==> Country@6e06451e

The syntax is simple - ClassName objectName = new ClassName().

india is an object of type Country, and is stored in memory at a location indicated by 6e06451e.

Let's create a few more instances of the class:

	jshell> Country usa = new Country();
	usa ==> Country@6e1567f1
	jshell> Country netherlands = new Country();
	netherlands ==> Country@5f134e67
	jshell>

india, usa and netherlands are all different objects of type Country.

We actually left the contents of the class Country bare.

A class does often include both data (member variables) and method definitions. More on this at a relevant time.

Let's consider another example:


	jshell> class Planet {
	   ...>}
	created class Planet
	jshell> Planet planet = new Planet();
	planet ==> Planet@56ef9176
	jshell> Planet earth = new Planet();
	earth ==> Planet@1ed4004b
	jshell> Planet planet = new Planet();
	venus ==> Planet@25bbe1b6

We can also create a class for a different concept, like a Planet.

Planet is now a different template. planet, earth and venus are instances of Planet class.

Summary

In this step, we:

  • Saw how class creation actually creates a new type
  • Understood how to create instances of classes - objects

Step 03: Adding A Method To A class

A method defined within a class, denotes an action than can be performed on objects of that class.

Let's define a method inside Planet - to revolve()!


		jshell> class Planet {
	   ...> void revolve() {
	   ...> System.out.println("Revolve");
	   ...> }
	   ...> }
	replaced class Planet
	update replaced variable planet, reset to null
	update replaced variable earth, reset to null
	update replaced variable venus, reset to null

Syntax of revolve() is similar to other methods we've created before.

The class template got updated as a result of adding new method. Earlier instances planet,earth and venus got reset to null as they are based on the old template

Let's re-instantiate a few objects.

	jshell> Planet earth = new Planet();
	earth ==> Planet@192b07fd
	jshell> Planet planet = new Planet();
	venus ==> Planet@64bfbc86
	jshell>

How do we call the revolve method?


	jshell> Planet.revolve();
	| Error:
	| non-static method revolve() cannot be referenced from a static context
	| Planet.revolve();
	|^-----------------^
	jshell> earth.revolve();
	Revolve
	jshell> venus.revolve();
	Revolve
	jshell>

Our attempt to perform revolve() did not work with the syntax Planet.revolve() as it is not a static method (more on that in a later section).

Invoking revolve() through syntax such as earth.revolve() succeeds, because earth is an object of type Planet.

Summary

In this step, we:

  • Learned how to add a method definition to an existing class
  • Discovered how to invoke it, on objects of the class

Step 04: Writing and Running Java Code in separate Source Files

So far, we have enjoyed creating classes and defining methods within them, all with our friendly neighborhood JShell.

JShell kind of spoiled us kids, by relaxing some Java syntax rules, invoking the compiler on our behalf, and also running the code like room service.

The time has come for us frog princes to outgrow the proverbial well. Yes, you're right! Time to start writing code in a proper code editor, and smell the greener grass on that side.

Let's start with creating a new source code file - 'Planet.java'. Choose any folder on your hard-disk and create the file shown below:

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
	}

You can get the code that we wrote earlier in JShell for Planet by running the command /list Planet, and copying the code.

You can use any text editor of your choice, for now.

The source file name must match the class name it contains. Here, we must name the file Planet.java.

The next course of action would be to compile this code (Stage 2). For that, exit out of JShell, and run back to your system terminal or command prompt. Now, see what plays out!


	jshell> /exit
	|  Goodbye

cd to the folder where you have created the file Planet.java

	in28minutes$> cd in28Minutes/git/JavaForBeginners/
	command-prompt> ls
	Planet.java

Check Java version.

	command-prompt> java -version
	java version "x.0.1"
	Java(TM) SE Runtime Environment (build x.0.1+11)
	Java HotSpot(TM) 64-bit Server VM (build x.0.1+11, mixed mode)

You can compile java code using javac Planet.java. You can see that a new file is created Planet.class. This contains your bytecode.

	command-prompt> javac Planet.java
	command-prompt> ls
	Planet.class         Planet.java_

You can run the class using command java Planet.

	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application
	command-prompt>	

Why is there an error? Let's discuss that in the next step.

Summary

In this step, we:

  • Ventured out of JShell into unexplored territory, to write source code
  • Learned how to invoke the compiler to compile source files, from the terminal

Step 05: Introducing main(), And Running Bytecode

In the previous step, we compiled Planet.java. In this step, let's run the bytecode generated, which lies inside Planet.class.

Snippet-01: Running Planet

Console Commands


	command-prompt> ls
	Planet.class         Planet.java
	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application
	command-prompt>

The code may have compiled without any errors, but what's the use if we cannot run the program to see what stuff it's got!

The main() method is essential to run code defined within any class.

The definition of main() needs to have this exact synatx:

public static void main(String[] args) { /* <Some Code Goes In Here> */ }

A few details:

  • void is its return type
  • main is its name
  • args is its formal argument. Here, it's an array of String.
  • `publicandstatic``` are reserved Java keywords. More on these later sections.

Let's add one such definition within the Planet code. Open up your text editor and add the main method as shown below.

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
		public static void main(String[] args) {

		}
	}

Let's run it now:


	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application

Why is there no change in result?

After changing your Java source file, you need to compile the code again to create a new class file.

	command-prompt> javac Planet.java
	command-prompt> ls
	Planet.class         Planet.java_

Let's try it again.

	command-prompt> java Planet
	command-prompt>

We got a blank stare from the terminal. Why?

What did we write in the main method? Nothing.

		public static void main(String[] args) {

		}

Let's fix it. We need to edit Planet.java once again!

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
		public static void main(String[] args) {
			Planet earth = new Planet();
			earth.revolve();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	command-prompt> ls
	Planet.class         Planet.java
	command-prompt> java Planet
	Revolve
	command-prompt>

Bingo! We finally got what we wanted to see!

Summary

In this step, we:

  • Learned that we need a main() method to run a Java program
  • Discovered that after every code update, we need to compile that source file

Step 06: Puzzles About Planet

In this step, let's play with Planet source code. Get ready for a comedy of errors, by trial-and-error!

Below is the source code for Planet that worked so well for us:

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}
		
		public static void main(String[] args) {
			Planet earth = new Planet();
			earth.revolve();
		}
	}

Here starts our nut-job.

Snippet-01: Messing-up main() - v1

Change method name from main to main1

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main1(String[] args) {
			Planet earth = new Planet();
			earth.revolve();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	command-prompt> java Planet
	Error: Main method not found inside class Planet, please define the main method as
	public static void main(String[] args)
	or a JavaFX application class must extend javax.application.Application
	command-prompt>

Don't mess with the method-name of main().

Other parts also need to remain the same, such as:

  • The return-type: void
  • Argument type: String[]
  • The presence of keywords public and static.
Snippet-02: Messing-up main() - v2

Remove semicolons after statements Planet earth = new Planet() and earth.revolve().

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main(String[] args) {
			Planet earth = new Planet()
			earth.revolve()
		}
	}

Console Commands


	command-prompt> javac Planet.java
	Planet.java:6: error: ';' expected
	Planet earth =  new Planet()
	|_______________________^
	Planet.java:7: error: ';' expected
	earth.revolve()
	|_____________^
	2 errors
	command-prompt>

The ; symbol is the Java statement separator, which is mandatory.

It is not needed in JShell but mandatory when you write separate Java source files.

Snippet-03: Messing-up main() - v3

Make a typo Planet earth = new Plane();

Planet.java


	class Planet {
		
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main(String[] args) {
			Planet earth = new Plane();
			earth.revolve();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	Planet.java:6: error: cannot find symbol
	Planet earth =  new Plane();
	|________________^
	symbol: class Plane
	location: class Planet
	1 error
	command-prompt>

We misspelled Planet as Plane, and the compiler trapped this error. It shows us a red flag with a message to help us correct our mistake.

Snippet-04: Messing-up main() - v4

Call a non existing method earth.revolve1();.

Planet.java


	class Planet {
		void revolve() {
			System.out.println("Revolve");
		}

		public static void main(String[] args) {
			Planet earth = new Planet();
			earth.revolve1();
		}
	}

Console Commands


	command-prompt> javac Planet.java
	Planet.java:7: error: cannot find symbol
	earth.revolve1();
	|_____^
	symbol: method revolve1()
	location: variable earth of type Planet
	1 error
	command-prompt>

We misspelled the name of the revolve() method, to revolve1(). Rightly, got rapped on our knuckles by the compiler.

Summary

In this step, we:

  • Learned that the best way to learn about language features is to play around with working code
  • Observed that JShell simplifies coding for us, even relaxing some syntax rules
  • Concluded that developing Java code in code-editors is an empowering feeling!

Step 07: The JVM, JRE And JDK

What are JVM, JRE and the JDK?

Apart from the fact that all start with a 'J', there are important differences in what they contain, and what they do.

The following list gives you a bird's eye view of things.

The JVM runs your program bytecode.

JRE = JVM + Libraries + Other Components

  • Libraries are built-in Java utilities that can be used within any program you create. System.out.println() was a method in java.lang, one such utility.
  • Other Components include tools for debugging and code profiling (for memory management and performance).

JDK = JRE + Compilers + Debuggers

  • JDK refers to the Java Development Kit. It's an acronym for the bundle needed to compile (with the compiler) and run (with the JRE bundle) your Java program.

An interesting way to remember this organization is:

  • JDK is needed to Compile and Run Java programs

  • JRE is needed to Run Java Programs

  • JVM is needed to Run Bytecode generated from Java programs

Let's check a couple of scenarios to test your understanding.

Scenario 1: You give Planet.class file to a friend using a different operating system. What does he need to do to run it?

First, install JRE for his operating system. Run using java Planet on the terminal. He does not need to run javac, as he already has the bytecode.

Scenario 2: You gave your friend the source file Planet.java. What does he need to do to run it?

Install JDK of a compatible version. Compile code using javac Planet.java. Run java Planet on his terminal.

In summary

  • Application Developers need ==> JDK

  • Application Users need ==> JRE

Summary

In this step, we:

  • Understood the differences in the scope-of-work done by the JVM, JRE and JDK
  • Realized how each of them could be invoked by different terminal commands, such as javac and java.

Eclipse

TODO - Need Revision

Introducing Java Software Development with Eclipse

  • Features of the Eclipse IDE (Integrated Development Environment)

    • Installation & Configuration
    • Workspace Creation & Configuration
    • Project Creation & Organization
      • JRE Version Selection and Included Libraries
      • Eclipse Java Perspectives
      • Source Files Organization into Folders
      • Packages?
    • IDE User Interface Description
      • Perspective
      • Views
      • Console Content and Display Options
  • Creating a new Java class in Eclipse (And related source file)

    • Package name

      • A Java solution to solving a problem could be composed of several application components. It is considered good programming arctice to identify a class for each distinct component. Package is the Java way to organize classes in source code.
      • Analogy: Eatables in a Refrigerator (Freezer, Chill-Tray, Vegetable-Tray, Bottle-Rack)
    • Public method stub : can be used to create a default public static void main(String[] args) signature

    • (Include Snapshots)

      • Class creation pop-up, with selected options
      • Default generated source code in editor window
    • Customizing the generated source code to our needs

      • Syntax Highlighting
        • Keywords
        • Built-in Types
        • Constant literals: numbers, strings
      • Auto-suggest feature of eclipse as code is being typed in
    • The "Run as --> Java Application" Option to compile-and-run the source code

      • Option is avaibale only for classes that have a main() method

Using Eclipse in Debug Mode

Execution of the Multiplication Table Program can be done Step by-step. That is, the entire application dies not execute at one go, printing the final output onto the console. We can stall its flow at several steps, by taking control of its execution using the Eclipse IDE. This is possible in a special mode of Eclipse, called Debug Mode.

The process is called Debugging, because this mode is heavily used not just to have fun seeing what happens, but also to detect and fix software bugs. A bug is a defect in the program being written, that leads to its incorrect execution. The process of removing bugs is called debugging. Humans being humans, programming errors are but natural, and a debug mode in the IDE is worth its wight in gold to the programmer. Here is how Eclipse facilitates debugging of Java applications.

  • Prior to debugging application, we need to set few Break-Points. A Break-Point is a statement in the source of the program, before which execution under debug mode is suspended, and control is passed to the programmer.

  • The overall state of the data in the suspended program is available to the programmer at that particular break-point. He/she gets to specify one or more break-points in the program, and when the execution is suspended, a list of possible actions can be performed, including:

    • Reading & modifying data variables
    • Resuming program execution
    • Re-executing current statement
    • Skipping all statements till the next break-point

    and others.

  • The Eclipse IDE provides a very user-friendly and intuitive interface to the programmer for controlling execution of a program in Debug Mode (Provide Snapshots of IDE at various stages of Debug Mode execution).

    • Setting and Removing a Break-point (also Toggling)
    • Stepping over a method call, or into and out of a method body (during a method call)
      • Stepping into int print() and int print(int) and int print(int,int,int) gives us interesting infromation, but stepping into System.out.printf can freak you out! So, you may want to step over it.
    • For nested method calls, examine the method call Stack Trace (Call child, call parent relationship)
      • Example : int print(), int print(int) and int print(int,int,int) method call chain of class MultiplicationTable.
    • Viewing and Modifying current state of data variables, at a break point
    • Stepping through from one statement to another in the source code
      • As we step through, observe the view displaying changes in data variable values
      • Example of for loop control variable i, inside method int print(int,int,int) of class MultiplicationTable
      • Observe that execution exits from the for loop when the condition i<=10 is no longer true.
    • Re-executing a line of code
    • Skipping execution of all statements till next break-point
    • Ignoring all remaining breakpoints, resume execution of code till completion

Eclipse IDE Keyboard Shortcuts

  • Code Text Editor Shortcuts
  • New Project/Class Creation Shortcuts
  • Search for a Class

Differences between JShell and IDE

Variables just declared, but used without an initialization, will flag a compilation error in an IDE! But not so, it seems, in JShell. In regular software, variable initialization at point of declaration (called a "defintion", as we already know) is mandatory.

Snippet-1 : JShell redefines variables on demand

	jshell> int i = 2
	$1 ==> 2
	jshell> int i = 4
	$2 ==> 4
	jshell> long i = 1000
	$3 ==> 1000
	jshell>

When the following code (similar to the one given to JShell) is compiled manually or by IDEs such as Eclipse, it will flag errors!


	package com.in28minutes.firstjavaproject;
	
	public class RedefineTestRunner {
		public static void main(String[] args) {
			int i = 2;
			int i = 4;
			long i = 1000;
			System.out.println(i);
		}
	}

That is because Java source code is governed by strict Scope Rules.

Let's have another look at where we have reached with our solution, to the PMT-Challenge problem. Only now, let's change the code arrangement.

Snippet-01: Revisited - The PMT-Challenge

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;
	public class MultiplicationTable {
		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", 5, i, 5*i).println();
			}
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();	
	}	
}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

Snippet-01 Explained
  • We have now split the code into two source files:
    • MultiplicationTable.java: Houses the MultiplicationTable class definition, with some methods we need.
    • MultiplicationRunner.java: Acts as the client of the MultiplicationTable class, to invoke its functionality. It defines a main() method, that instantiates a MultiplicationTableobject, and invokes its print() method.
  • After this code was rearranged, we still got it to work!
  • We now want to enhance our current solution to this challenge, even though we've come a long way. "Once you get the whiff of success, sky is the limit!". Here is the changes we need:
    • Pass the number whose table needs to be printed, as an argument
    • Pass the (continuous) range of numbers, whose index entries in the table are to be printed. (For example, printing the table entries for 6, with entries for indexes between 15 to 30).

One way to achieve all this, would involve overloading the print() method. The next example is one such attempt.

Snippet-02: print() overloaded

Overloading print() works for us, and we now support three ways in which to display any table:


		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", 5, i, 5*i).println();
			}
		}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

The default table for 5, with entries fixed within 1 to 10.


		public static void print(int number) {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

Console Output

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

Printing a table for any number, but with entries fixed between 1 and 1.


		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

Console Output

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Displaying a table for any number, with entries for any range

The full code:

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;
	
	public class MultiplicationTable {
		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", 5, i, 5*i).println();
			}
		}	
	
		public static void print(int number) {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(8);
			table.print(6, 11, 20);
		}
	}

Issue: Code Duplication In Print-Multiplication-Table

There is an issue with the code for class MultiplicationTable. In the final print format, what if we are asked to replace the multiplication symbol '*' with an 'X', so that school kids like it better? Since there are three calls to System.out.printf(), one in each print() version, we make three changes.

Snippet-3: Code Duplication

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationTable {
		public static void print() {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d X %d = %d", 5, i, 5*i).println();
			}
		}

		public static void print(int number) {
			for(int i=1; i<=10;i++) {
				System.out.printf("%d * %d = %d", number, i, number*i).println();
			}
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d X %d = %d", number, i, number*i).println();
			}
		}
	}

Console Output

5 X 1 = 5

5 X 2 = 10

5 X 3 = 15

5 X 4 = 20

5 X 5 = 25

5 X 6 = 30

5 X 7 = 35

5 X 8 = 40

5 X 9 = 45

5 X 10 = 50

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

6 X 11 = 66

6 X 12 = 72

6 X 13 = 78

6 X 14 = 84

6 X 15 = 90

6 X 16 = 96

6 X 17 = 102

6 X 18 = 108

6 X 19 = 114

6 X 20 = 120

Snippet-3 Explained
  • Humans make mistakes. The programmer missed out on changing the format symbol in the code for void print(int, int), but we don't recommend punishment. He could be overworked, or could only be the maintainer of code someone else wrote years ago! The point is not to blame human flaws (there are many), but to show how code duplication causes errors. This issue arises frequently with overloaded methods, point blank.
  • Instead of trying to change human nature, can we change our software? Let's have a closer look at print():
    • The method void print() prints the multiplication table for 5 only, in the default range 1 to 10.
    • The method void print(int) outputs the table for any number, but only in the fixed range from 1 to 10.
    • The method void print(int,int,int) displays the table for any number, in any range of entries.

A Solution: Code Reuse

There is something huge we observe in the previous example. All overloaded versions of print() have nearly the same code!

  • print(int) has wider usage potential than print(). The latter is a special case, as it prints only the for 5. We can achieve what print() does, by passing a fixed parameter value of 5 to print(int). It's simple: invoke print(int) within print(), by passing 5 to it.
  • The point to note is, that a more specialized function can be implemented-in-terms-of a more general function.

Let's now reorganize this part of the code.

Snippet-4: Code Reuse

MultiplicationTable.java


	public static void print() {
		print(5);
	}

	public static void print(int number) {
		for(int i=1; i<=10;i++) {
			System.out.printf("%d * %d = %d", number, i, number*i).println();
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(8);
		}
	}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

Snippet-4 Explained

When we call a method inside another, the method call statement is replaced by its body (with actual arguments replacing the formal ones). In the new definition of int print() above, the code executed during the call will be:


	for(int i=1; i<=10;i++) {
		System.out.printf("%d * %d = %d", 5, i, 5*i).println();
	}

Extending Code Reuse

  • The method int print(int,int,int) is a more general version of int print(int). We can achieve what the latter computes, by passing fixed range of indexes, namely 1 and 10, as arguments to the former. have look into he code that follows.
Snippet-5 : Extending code reuse

MultiplicationTable.java


	public static void print(int number) {
		print(number, 1, 10);		
	}	

	public static void print(int number, int from, int to) {
		for(int i=from; i<=to;i++) {
			System.out.printf("%d X %d = %d", number, i, number*i).println();
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print(8);
			table.print(6, 11, 20);
		}
	}

Console Output

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Snippet-5 Explained
  • This example merely extended what we did in the previous example. We will will take this extension one level further now! Yes, you guessed right. We will implement print() in terms of print(int,int,int).
Snippet-6 : Extending code reuse (contd.)

MultiplicationTable.java


	public static void print() {
		print(5, 1, 10);
	}

	public static void print(int number, int from, int to) {
		for(int i=from; i<=to;i++) {
			System.out.printf("%d X %d = %d", number, i, number*i).println();
		}
	}

MultiplicationRunner.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(6, 11, 20);
		}
	}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Snippet-6 Explained
  • By extending the same logic of code reuse, the method int print(int,int,int) can be used to implement the logic of int print(). Just pass in a number parameter 5, as well as the fixed range parameters 1 and 10, in a call to the former. int print() is thus implemented-in-terms-of int print(int,int,int).

  • Our new version of class MultiplicationTable looks like this:

Snippet-7: Extending Code Reuse (Contd.)

MultiplicationTable.java


	package com.in28minutes.firstjavaproject;

	public class MultiplicationTable {
		public static void print() {
			print(5, 1, 10);
		}

		public static void print(int number) {
			print(number, 1, 10);
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d X %d = %d", number, i, number*i).println();
			}	
		}
	}

  • The logic of the class MutliplicationRunner does not change at all:

MultiplicationRunner.java:


	package com.in28minutes.firstjavaproject;
	
	public class MultiplicationRunner {
		public static void main(String[] args) {
			MultiplicationTable table = new MultiplicationTable();
			table.print();
			table.print(8);
			table.print(6, 11, 20);
		}
	}

Console Output

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

5 * 6 = 30

5 * 7 = 35

5 * 8 = 40

5 * 9 = 45

5 * 10 = 50

8 * 1 = 8

8 * 2 = 16

8 * 3 = 24

8 * 4 = 32

8 * 5 = 40

8 * 6 = 48

8 * 7 = 56

8 * 8 = 64

8 * 9 = 72

8 * 10 = 80

6 * 11 = 66

6 * 12 = 72

6 * 13 = 78

6 * 14 = 84

6 * 15 = 90

6 * 16 = 96

6 * 17 = 102

6 * 18 = 108

6 * 19 = 114

6 * 20 = 120

Snippet-7 Explained

Neat, isn't it! To make our program school kid friendly, we just need to change one character in the code, take a peek below.

Snippet-8 : Extending Code Reuse (Contd.)

MultiplicationTable.java:


	package com.in28minutes.firstjavaproject;

	public class MultiplicationTable {
		public static void print() {
			print(5, 1, 10);		
		}

		public static void print(int number) {
			print(number, 1, 10);
		}

		public static void print(int number, int from, int to) {
			for(int i=from; i<=to;i++) {
				System.out.printf("%d X %d = %d", number, i, number*i).println();
			}
		}
	}

Console Output

5 X 1 = 5

5 X 2 = 10

5 X 3 = 15

5 X 4 = 20

5 X 5 = 25

5 X 6 = 30

5 X 7 = 35

5 X 8 = 40

5 X 9 = 45

5 X 10 = 50

8 X 1 = 8

8 X 2 = 16

8 X 3 = 24

8 X 4 = 32

8 X 5 = 40

8 X 6 = 48

8 X 7 = 56

8 X 8 = 64

8 X 9 = 72

8 X 10 = 80

6 X 11 = 66

6 X 12 = 72

6 X 13 = 78

6 X 14 = 84

6 X 15 = 90

6 X 16 = 96

6 X 17 = 102

6 X 18 = 108

6 X 19 = 114

6 X 20 = 120

Snippet-8 Explained

Software Development is an iterative process. The best code that we want to write does not happen at one go. It starts off at a certain level, and can always be improved. More importantly, such improvements needs to be remembered, to be applied again at different points in the same program, and across programs. This process is called Code Refactoring. Thought we'd keep you posted.

Summary

In this step, we:

  • Explored how to reorganize the code for PMT-Challenge into a class
  • Understood that overloading works the same way for class methods
  • Observed that code reuse is possible across overloaded versions of a class method

Object Oriented Progamming (OOP)

How do you design great Object Oriented Programs?

Let's find out

Recommended Videos:

Step 01: Object Oriented Progamming (OOP) - Basic Terminology

Let's consider a few examples before we get to Object Oriented Progamming.

Humans think in a step by step process.

Let's say I've to take a flight from London to New York. This is how I would think:

  • Take a cab to London Airport
  • Check in
  • Pass Security
  • Board the flight
  • Wish the Hostess
  • Take Off
  • Cruise
  • Land
  • Get off the plane
  • Take a cab to ..

Procedural programming is just a reflection of this thought process. A procedural program for above process would look something like this:

takeACabToLondonAirport();
checkIn();
passSecurity();
boardPlane();
wishHostess();
takeOff();
cruiseMode();
land();
getOffPlane();
//...

Object Oriented Programming (OOP) brings in a new thought process around this.

How about thinking in terms of the different Actors? How about storing data related to each actor right beside itself? How about giving them some responsiblity and let them do their own actions?

Here's how our program would look like when we think in terms of different actors and give them data and responsibilities


    Person
    	name
    	boardFlight(Plane flight), wishHostess (Hostess hostess), getOffFlight(Plane flight)

    AirPlane
    	altitude, pilot, speed, flightMode
		takeOff(), cruiseMode(), land()

    Hostess
    	welcome()

Do not worry about the implementation details. Focus on the difference in approaches.

We have encapsulated data and methods into these entities, which are now called objects. We have defined object boundaries, and what it can (and cannot) do.

An object has

  • State : Its data
  • Behavior : Its operations

The position of an Airplane can change over time. The operations that can be performed on an Airplane include takeOff(), land() and cruiseMode(). Each of these actions can change its position. Therefore, an object's behavior can affects its own state.

It's now time to introduce you to some core OOP terms, which will make our future discussions easier.

OOP Terminology

Let's visit and enhance the Planet example we had written a few sections ago. This time, let's also explore the conceptual angle.

Planet


	class Planet
		name, location, distanceFromSun // data / state / fields
		rotate(), revolve() // actions / behavior / methods

	earth : new Planet
	venus : new Planet

Let's look at some OOP terminology.

A class is a template. An object is an instance of a class. In above example, Planet is a class. earth and venus are objects.

  • name, location and distanceFromSun compose object state.
  • rotate() and revolve() define object's behavior.

Fields are the elements that make up the object state. Object behavior is implemented through Methods.

Each Planet has its own state:

  • name: "Earth", "Venus"
  • location : Each has its own orbit
  • distanceFromSun : They are at unique, different distances from the sun

Each has its own unique behavior:

  • rotate() : They rotate at different rates (and in fact, different directions!)
  • revolve() : They revolve round the sun in different orbits, at different speeds

Summary

In this step, we:

  • Understood how OOP is different from Prodedural Programming
  • Learned about a few basic OOP terms

Step 02: Programming Exercise PE-01

Exercises

In each of the following systems, identify the basic entities involved, and organize them using object oriented terminology:

  1. Online Shopping System
  2. Person

Solution-1: Online Shopping System


	Customer
		name, address
		login(), logout(), selectProduct(Product)


	ShoppingCart
		items
		addItem(), removeItem()


	Product
		name, price, quantityAvailable
		order(), changePrice()

Solution-2: Person


	Person
		name, address, hobbies, work
		walk(), run(), sleep(), eat(), drink()

Step 03: Creating MotorBike class

In this series of examples, we want to model your pet mode of transport, a motorbike. We want to create motorbike objects and play around with them.

We will start with two java files:

  • MotorBike.java, which contains the MotorBike class definition. This class will encapsulate our motorbike state and behavior
  • MotorBikeRunner.java, with class MotorBikeRunner holding a main method, our program's entry point
Snippet-1: MotorBike Class

MotorBike.java


	package com.in28minutes.oops;
		public class MotorBike {
		//behavior
		void start() {
			System.out.println("Bike started!");
		}
}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();
		}
	}

Console Output

Bike started!

Bike started!

Snippet-1 Explained

We started off creating a simple MotorBike class with a start method. We created a couple of instances and invoked the start method on them.

We created two classes because we believe in Seperation of Concerns:

  • MotorBike class is responsible for all its data and behavior.
  • MotorBikeRunner class is responsible for running MotorBike examples.

Summary

In this step, we:

  • Defined a MotorBike class allowing us to further explore OOP concepts in the next steps

Step 04: Programming Exercise OO-PE-02

Exercises

  1. Write a small Java program to create a Book class, and then create instances to represent the following book titles:
    • "The Art Of Computer Programming"
    • "Effective Java"
    • "Clean Code"

Solution

Book.java


	public class Book {
		private String title;

		public void setTitle(String bookTitle) {
			title = bookTitle;
		}

		public String getTitle() {
			return title;
		}
	}

BookRunner.java


	public class BookRunner {
		public static void main(String[] args) {
			Book taocp = new Book();
			taocp.setTitle("The Art Of Computer Programming");
			Book ej = new Book();
			ej.setTitle("Effective Java");
			Book cc = new Book();
			cc.setTitle("Clean Code");
			System.out.println(taocp.getTitle());
			System.out.println(ej.getTitle());
			System.out.println(cc.getTitle());
		}
	}

Console Output

The Art Of Computer Programming

Effective Java

Clean Code

Step 05: MotorBike - Representing State

An object encapsulates both state and behavior.

State defines "the condition of the object at a given time". State is represented by member variables.

In the MotorBike example, if we need a speed attribute for each MotorBike, here is how we would include it.

Snippet-1 : MotorBike with state variable speed

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		int speed;
		void start() {
			System.out.println("Bike started!");
		}
	}
	

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();

			ducati.speed = 100;
			honda.speed = 80;
			ducati.speed = 20;
			honda.speed = 0;
		}
	}

Console Output

Bike started!

Bike started!

Snippet-4 Explained

int speed; within MotorBike, defines a member variable.

It can be accessed within objects such as ducati and honda, by qualifying it with the object name (ducati or honda).

ducati.speed = 100;
honda.speed = 80;

ducati has its own value for speed, and so does honda. These values are independent of each other. Changing one does not affect the other.

Classroom Exercise CE-OO-01

  1. Update the Book class created previously to include a member variable named noOfCopies, and demonstrate how it can be set and updated independently for each of the three titles specified earlier.

Solution

TODO

Step 07: MotorBike - get() and set() methods

In the previous step. we were merrily modifying the speed attribute within the ducati and honda objects directly, from within the main() program.

	public class MotorBikeRunner {
		public static void main(String[] args) {
			//... Other code
			ducati.speed = 100;
			honda.speed = 0;
		}
	}

This did work fine, but it breaks the fundamental principle of encapsulation in OOP.

"A method of one object, should not be allowed to directly access the state of another object. To do so, such an object should only be allowed to invoke methods on the target object".

In other words, a member variable should not be directly accessible from methods declared outside its class.

Snippet-3 : MotorBike class with private attributes

MotorBike.java


	package com.in28minutes.oops;
	
	public class MotorBike {
		private int speed;
		
		void start() {
			System.out.println("Bike started!");
		}

		void setSpeed(int speed) {
			this.speed = speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();
		
			ducati.setSpeed(100);
			honda.setSpeed(80);
	
			ducati.setSpeed(20);
			honda.setSpeed(0);
		}
	}

Console Output

Bike started!

Bike started!

Snippet-3 Explained

By declaring speed as private, we provide MotorBike with something called access control. Java keywords such as public and private are called access modifiers. They control what external objects can access within a given object.

Let's look at this.speed = speed; in the body of method setSpeed():

  • An member variable always belongs to a specific instance of that class.
  • A method argument behaves just like a local variable inside that method.
  • To differentiate between the two, this is used. The expression this.speed refers to the member variable speed of a Motorbike object. setSpeed() would be invoked on that very object.

Code written earlier within MotorBikeRunner, such as ducati.speed = 100; would now result in errors! The correct way to access and modify speed is to invoke appropriate methods such as setSpeed(), on MotorBike objects.

Classroom Exercise CE-OO-02

  1. Update the class Book to make sure it no longer breaks Encapsulation principles.

Solution

TODO

Summary

In this step, we:

  • Learned about the need for access control to implement encapsulation
  • Observed that Java provides access modifiers (such as public and private) for such control
  • Understood the need for get() and set() methods to access object data

Step 08: Accessing Object State

Encapsulation is needed to protect an object's state from direct access by other objects. We were able to protect the state of MotorBike objects by declaring speed to be private. We have created a sort of rigid situation here, since the private declaration of speed forbids even a get access. How do we address this issue? Again, the answer is to provide a method for reading the current speed.

Snippet-4 : getSpeed() of MotorBike

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//Same as before

		int getSpeed() {
			return this.speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();

			ducati.setSpeed(100);
			honda.setSpeed(80);
			System.out.printf("Current Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Current Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

Console Output

Bike started!

Bike started!

Current Ducati Speed is : 100

Current Honda Speed is : 80

Snippet-4 Explained

Defining a method such as getSpeed() allows us to access the currentspeed of a MotorBike object.

		int getSpeed() {
			return this.speed;
		}

Eclipse has a very handy feature. When the state elements (member variables) of a class have been defined, it can generate default get() and set() methods for each of them. You would want to use this regularly, to save on time and typing effort. Right click on class > Generate Source > Generate Getters and Setters

Summary

In this step, we:

  • Understood how access control forces us to provide get() methods as well
  • Explored a few Eclispe tips to generate get() and set() versions for each class attribute

Step 10: Default Object State

What happens if a data element inside an object is not initialized with a value?

Snippet-5 : Default Initialization of Object State

MotorBike.java

//Same as before

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike honda = new MotorBike();			
			System.out.printf("Current Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

Console Output

Current Honda Speed is : 0

Snippet-6 Explained

When we instantiate an object, all its state elements are always initialized, to the default values of their types. Inside MotorBike, speed is declared to be an int, and so is initialized to 0. This happens even before any method of MotorBike is called, including start().

You can see that honda.getSpeed() printed 0 even though we did not explictly initialize it.

Default

Summary

In this step, we:

  • Learnt that default values are assigned to object member variables.

Step 10: Encapsulation: Its Advantages

At the heart of encapsulation, is the need to protect object's state. From whom? Other objects.

Let's look at an example to understand Encapsulation better.

Snippet-7 : Advantage of Encapsulation

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		private int speed;

		public void start() {
			System.out.println("Bike started!");
		}

		public void setSpeed(int speed) {
			this.speed = speed;
		}

		public int getSpeed() {
			return this.speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {

		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			ducati.start();
			ducati.setSpeed(-100);
			System.out.printf("Current Ducati Speed is : %d", ducati.getSpeed()).println();
		}
	}

Console Output

Bike started!

Current Ducati Speed is : -100

Snippet-01 Explained

For a motorbike, -100 might be an invalid speed. Currently, we do not have any validation. Having a method setSpeed allows us to add validation.

Let's see how to do that.

Snippet-02 : Speed Validity Check

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {

		//Other code as is

		public void setSpeed(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

	}

MotorBikeRunner.java

//Same as before

The output of this snippet is:

Bike started!

Current Ducati Speed is : 0

Snippet-8 Explained

setSpeed() checks if(speed > 0) and does not update speed for negative values.

This is not perfect solution because the caller of the setSpeed method assumes that he was successful. Ideally, we should throw an Exception indicating validation error. We will talk about Exceptions later.

Summary

In this step, we:

  • Explored the first advantage of encapsulation - A provision for adding data validation
  • Highlighted how such validation can be done, using the Motorbike example

Step 11: Encapsulation - Advantages (Code Reuse)

We've understood quite a few things about encapsulation under OOP.

Suppose at different points of time, we want to increase the speeds of both Honda and Ducati bikes by a fixed amount, say 100 mph. The logic would be simple, right? Fetch the current speed of each bike, increment that fetched value by 100, and then set the new value back into that bike's speed. The following example puts the above logic into action.

Snippet-1 : Bulky Speed Increment code

MotorBike.java

// No Change

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();		
			honda.start();
			ducati.setSpeed(100);
			
			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();
		
			int ducatiSpeed = ducati.getSpeed();
			ducatiSpeed = ducatiSpeed + 100;
			ducati.setSpeed(ducatiSpeed);
			
			int hondaSpeed = honda.getSpeed();
			hondaSpeed = hondaSpeed + 100;
			honda.setSpeed(hondaSpeed);
			
			System.out.printf("Later Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Later Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 200

Later Honda Speed is : 100

Snippet-1 Explained

Notice the repeated code within MotorBikeRunner? The code for updating the speed of ducati, is almost the same as that for honda. Remember at the start of this book, we said something like this:

"The goal of any computer program is to make a task easier, less cumbersome and more elegant for the programmer."

OOP achieves all thus through encapsulation! The idea is to encapsulate repeated logic within a method, and pass object-specific information to it as arguments. The next example shows you one way of doing it.

Snippet-2 : Speed Increase through Code Encapsulation

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//Other code same as before
		public void increaseSpeed(int howMuch) {
			this.speed = this.speed + howMuch;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			
			MotorBike duati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();

			ducati.setSpeed(100);

			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();

			ducati.increaseSpeed(100);
			honda.increaseSpeed(100);

			System.out.printf("Later Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Later Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 200

Later Honda Speed is : 100

Snippet-2 Explained

The method increaseSpeed() has been added to MotorBike. It can be invoked on the ducati and honda objects.

Let's now add a feature to MotorBike, by which speed can be decreased.

Snippet-3 : Speed Increase And Decrease through Code Encapsulation

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		// Other methods same as before
		public void decreaseSpeed(int howMuch) {
			this.speed = this.speed - howMuch;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike();
			MotorBike honda = new MotorBike();
			ducati.start();
			honda.start();
	
			ducati.setSpeed(100);
			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();

			ducati.increaseSpeed(100);
			honda.increaseSpeed(100);
			ducati.decreaseSpeed(50);
			honda.decreaseSpeed(50);

			System.out.printf("Later Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Later Honda Speed is : %d", honda.getSpeed()).println();
			
			ducati.decreaseSpeed(200);
			honda.decreaseSpeed(200);

			System.out.printf("Final Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Final Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 150

Later Honda Speed is : 50

Final Ducati Speed is : -50

Final Honda Speed is : -150

Snippet-3 Explained

The method decreaseSpeed() has been added to MotorBike. It can be invoked on the ducati and honda objects inside the main() method of MotorBikeRunner.

On of the things you can observe again is Negative Speed Values. Our validation needs to be improved.

Snippet-4 : Validation across methods, repeated!

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {

		//Same as before

		public void increaseSpeed(int howMuch) {
			if(this.speed + howMuch > 0)
			   this.speed = this.speed + howMuch;
		}

		public void decreaseSpeed(int howMuch) {
			if(this.speed - howMuch > 0)
			   this.speed = this.speed - howMuch;
		}
	}

MotorBikeRunner.java

	//Same as before

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 150

Later Honda Speed is : 50

Final Ducati Speed is : 150

Final Honda Speed is : 50

Snippet-4 Explained

We have achieved data validation, because attempts to decrease the speed of ducati and honda below 0 are now ignored.

But this has come at a cost, which is code bloat.

How do we reduce duplication?

Snippet-5: Validation by code reuse

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//Other methods same as before


		public void setSpeed(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

		public void increaseSpeed(int howMuch) {
			setSpeed(this.speed + howMuch);
		}

		public void decreaseSpeed(int howMuch) {
			setSpeed(this.speed - howMuch);
		}
	}

MotorBikeRunner.java

	//Same as before

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 0

Later Ducati Speed is : 150

Later Honda Speed is : 50

Final Ducati Speed is : 150

Final Honda Speed is : 50

Snippet-5 Explained

The idea behind this solution is, that an update is the same as a set() operation. Since setSpeed() already has a validation check, it can be called inside both increaseSpeed() and decreaseSpeed() with appropriate parameters.

In this way, the validation logic would be reused across update methods.

Be always careful. Duplication of logic makes your code difficult to maintain.

Summary

In this step, we:

  • Started exploring the next advantage of encapsulation - code reuse
  • Mapped this understanding to the MotorBike example, building on data validation

Step 12: Programming Exercise PE-OO-03

Exercises

  1. Use an encapsulation technique to write methods for the Book class, that
    • Increase the number of books
    • Decrease the number of books

Solution

BookRunner.java


	public class BookRunner {
		public static void main(String[] args) {
			Book taocp = new Book();
			taocp.setTitle("The Art Of Computer Programming");
			Book ej = new Book();
			ej.setTitle("Effective Java");
			Book cc = new Book();
			cc.setTitle("Clean Code");
			
			System.out.println(taocp.getTitle());
			System.out.println(ej.getTitle());
			System.out.println(cc.getTitle());

			taocp.increaseCopies(10);
			ej.increaseCopies(15);
			cc.increaseCopies(20);
			taocp.decreaseCopies(5);
			ej.decreaseCopies(10);
			cc.decreaseCopies(15);

			System.out.println(taocp.getNumberOfCopies());
			System.out.println(ej.getNumberOfCopies());
			System.out.println(cc.getNumberOfCopies());
		}
	}

Book.java


	public class Book {
		private String title;
		private int numberOfCopies;

		public void setTitle(String bookTitle) {
			title = bookTitle;
		}

		public String getTitle() {
			return title;
		}

		public void setNumberOfCopies(int numberOfCopies) {	
			if(numberOfCopies > 0) {
				this.numberOfCopies = numberOfCopies;
			}
		}

		public int getNumberOfCopies() {
			return numberOfCopies;
		}

		public void increaseCopies(int howMuch) {
			setNumberOfCopies(numberOfCopies + howMuch);
		}

		public void decreaseCopies(int howMuch) {
			setNumberOfCopies(numberOfCopies - howMuch);
		}
	}

Console Output

The Art Of Computer Programming

Effective Java

Clean Code

5

5

5

Step 13: Introducing Constructors

When we create Ducati and Honda motorbikes, we may want to configure them with some start speeds.

Suppose our whim is that a Ducati bike starts with 100 mph, and a Honda with 200 mph.

Snippet-1: MotorBike Constructor

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		private int speed;

		
		MotorBike(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

		//Same as before

	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike(100);
			MotorBike honda = new MotorBike(200);
			ducati.start();
			honda.start();
			System.out.printf("Earlier Ducati Speed is : %d", ducati.getSpeed()).println();
			System.out.printf("Earlier Honda Speed is : %d", honda.getSpeed()).println();
		}
	}

The output of this snippet is:

Bike started!

Bike started!

Earlier Ducati Speed is : 100

Earlier Honda Speed is : 200

Snippet-1 Explained

We defined a single-argument constructor for MotorBike, whosw definition looks like this:

public MotorBike(int speed){ /* Constructor Code Goes Here */ }

The constructor is a method, whose name is the same as the class name. All Java rules for a method apply to constructors as well. Constructor cannot be directly called.

A constructor is always invoked when a class object is created, using the new keyword. A constructor for a class could accept zero, one or more than one arguments. Let's next write some full-blooded code for a MotorBike constructor.

Summary

In this step, we were introduced to the concept of a class constructor

Programming Exercise PE-OO-04, And More On Constructors

Exercises

  1. Rewrite the Book class solution by using a constructor, which accepts an integer argument specifying the initial number of copies to be published:
    • "The Art Of Computer Programming" : 100 copies
    • "Effective Java" : 75 copies
    • "Clean Code" : 60 copies

Solution To PE-OO-04

BookRunner.java


	public class BookRunner {
		public static void main(String[] args) {
			Book taocp = new Book(100);
			taocp.setTitle("The Art Of Computer Programming");
			
			Book ej = new Book(75);
			ej.setTitle("Effective Java");
			
			Book cc = new Book(60);
			cc.setTitle("Clean Code");

			System.out.println(taocp.getTitle());
			System.out.println(taocp.getNumberOfCopies());

			System.out.println(ej.getTitle());`
			System.out.println(ej.getNumberOfCopies());

			System.out.println(cc.getTitle());
			System.out.println(cc.getNumberOfCopies());
		}
	}

Book.java


	public class Book {
		private String title;
		private int numberOfCopies;
		
		public Book(int numberOfCopies) {
			this.numberOfCopies = numberOfCopies;
		}

		public void setTitle(String bookTitle) {
			title = bookTitle;
		}

		public String getTitle() {
			return title;
		}

		public int getNumberOfCopies() {
			return numberOfCopies;
		}
	}

Console Output

The Art Of Computer Programming

100

Effective Java

75

Clean Code

60

More on Constructors

We enjoyed defining the MotorBike class and checking out the behavior of its instances, ducati and honda.

When we started off , we created instances of MotorBike classes using:

MotorBike ducati = new MotorBike();

Did you notice something familiar? Doesn't the expression new MotorBike() look like a constructor call?

As it turns out, it is a constructor call on MotorBike!

When we define a class in Java (even a seemingly empty one), some behind-the-scene magic happens. Consider one such class Cart:


	class Cart {

	};

This class has neither state, nor behavior. When we try to create instances of this "empty" class:


	class CartRunner {
		public static void main(String[] args) {
			Cart cart = new Cart();
		}
	}

The code seems to compile, execute and get initialized quite smoothly! What happens is, that the compiler silently generates a default constructor for Cart.

A default constructor is one that accepts no arguments. It is as if the Cart class were defined this way:


	class Cart {
		public Cart() {
		}
	};

A constructor may also have overloaded definitions.

Let's now try to create MotorBike instances with default initialization, just as we did with Cart.

Snippet-2 : Default Motorbike Construction?

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {

		private int speed;

		MotorBike(int speed) {
			if(speed > 0)
				this.speed = speed;
		}
	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike(100);
			MotorBike honda = new MotorBike(200);
			MotorBike yamaha = new MotorBike();
		}
	}

Console Output

Compiler Error

Snippet-2 Explained

The compiler flags an error with MotorBikeRunner.java! MotorBike yamaha = new MotorBike(); is failing compilation. Why?

No default constructor is generated here! If you provide any constructor definition in a class, the compiler will not add a default constructor. Do them all yourself, if you don’t like what I do for you! is what it yells back.

If you need the default constructor, you can explicitly add it.

Snippet-3 : Programmer-defined default constructor

MotorBike.java


	package com.in28minutes.oops;

	public class MotorBike {
		//state
		private int speed;

		//behavior
		MotorBike() {
			this(5);
		}

		MotorBike(int speed) {
			if(speed > 0)
				this.speed = speed;
		}

	}

MotorBikeRunner.java


	package com.in28minutes.oops;

	public class MotorBikeRunner {
		public static void main(String[] args) {
			MotorBike ducati = new MotorBike(100);
			MotorBike honda = new MotorBike(200);
			MotorBike yamaha = new MotorBike();
			System.out.printf("Earlier Yamaha Speed is : %d", yamaha.getSpeed()).println();
		}
	}

The output of this snippet is:

Earlier Yamaha Speed is : 5

Snippet-3 Explained

We defined a zero-argument constructor MotorBike(), to enable default object initialization. But what are we doing in its body with the statement this(5);?

We have called the constructor MotorBike(int), qualified with the this keyword, within Motorbike().

Primitive Data Types

Earlier, we looked at basic Java types (including int, double and boolean), and got a little familiar with them.

We used literal values, declared variables and formed expressions using them.

Java primitive types include:

  • Integer Types
    • byte
    • short
    • int
    • long
  • Floating-Point Types
    • float
    • double
  • Character Type
    • char
  • Logical Type
    • boolean

In this section, let's play with each of these types to understand them further.

Step 01: The Integer Types

Integers are not much of a mystery, are they? They've been part of us since our school days, and we normally prefer them over other numbers (they scare us less!).

Java supports them with ease, and we have coded quite a few examples using them, already.

Java also has a wrapper class corresponding to each of them, which make their primitive versions more versatile. The wrapper classes we are talking about are:

  • Byte: for byte
  • Short: matching short
  • Integer corresponding to int
  • Long: about long

Let's see how we can work with them.

Snippet-01 : Integer Sizes

Look at all the information these tiny classes hold for you! As they say, "fore-warned is fore-armed". Depending on the data (range and size) your program handles, you decide which types to use, to store them.


	jshell> Byte.SIZE
	$1 ==> 8
	jshell> Byte.BYTES
	$2 ==> 1
	jshell> Byte.MAX_VALUE
	$3 ==> 127
	jshell> Byte.MIN_VALUE
	$4 ==> -128
	jshell> Short.BYTES
	$5 ==> 2
	jshell> Integer.BYTES
	$6 ==> 4
	jshell> Long.BYTES
	$7 ==> 8
	jshell> Short.MAX_VALUE
	$8 ==> 32767
	jshell> Integer.MAX_VALUE
	$8 ==> 2147483647
	jshell> int i = 100000;
	i ==> 100000
	jshell> long l = 50000000000;
	| Error:
	| integer number too large: 50000000000
	| long l = 50000000000;
	|_________^
	jshell> long l = 50000000000l;
	l ==> 50000000000
	jshell>

Integer Type Conversions

Problems will (and should) arise if we attempt to store large data into smaller bins. The compiler warns the programmer about such issues by flagging errors. However, if the programmer is aware of the risks and intends to go ahead, explicit casts are her tools to push the code through.

Operations in the other direction (storing a smaller data value in a larger bin), is a piece of cake for the compiler. Such a conversion is called an implicit cast.

Snippet-02 : Integer Type Conversions

Attempting to store a long value into an int variable will give us a compiler error. However, you can use an explicit cast, such as i = (int) l;.


	jshell> int i = 100000;
	i ==> 100000
	jshell> long l = 50000000000l;
	l ==> 50000000000
	jshell> i = l;
	| Error :
	| incompatible types: possible lossy conversion from long to int
	| i = l;
	|_____^
	jshell> i = (int) l;
	i ==> -1539607552
	jshell> l = i;
	l ==> -1539607552
	jshell>
	

The compiler is not responsible for the type-safety of this statement. The onus is on me, the programmer.

Remember our earlier statement on possible incorrect program behavior? As you can see, a different value got stored in i.

Summary

In this step, we:

  • Explored the wrapper classes present for the primitive integer types
  • Understood the different capacities and data ranges of these types
  • Examined how to use explicit and implicit casts

Step 02: Integer Representations, And Other Puzzles

In a decimal system, the allowed digits are 0 through 9. When a value of 10 is encountered, the number of digits increases by 1, and its representation is "10".

Those familiar with number systems would know that decimal is not the only system that computers understand.

Other number systems that the Java language supports are Octal (Base-8) and Hexadecimal (Base-16).

In an Octal system, the allowed digits are 0 through 7, and a value 8 is represented by "010". The leading 0 is added only to distinguish the octal format from the decimal one.

In a Hexadecimal system, the allowed digits are 0 through 9, followed by a through f (or A through F). A value of 16 is represented by "0x10". Here, a leading 0x is added to help the compiler recognize Hexa decimal representation.

Let's see how Java supports these three number systems.

Snippet-01 : Storing Octal and Hexadecimal in Integer types

There are no number-system specific integer types in Java! The same int type is used to store decimal, octal and hexadecimal values.

If we adhere to to number system conventions about valid digits and understand the compiler hints, we get no surprises.


	jshell> int eight = 010;
	eight ==> 8
	jshell> int sixteen = 0x10;
	sixteen ==> 16
	jshell> int fifteen = 0xf;
	fifteen ==> 15
	jshell> int eight = 08;//8 is invalid octal digit
	| Error:
	| integer number too large : 08
	| int eight = 08;
	|___________^
	jshell> int big = 0xbbaacc;
	big ==> 12298956
	jshell>

Snippet-02 : More Integer Type-casting

There are two kinds of assignments:

  • Literal-to-variable assignment: With short s = 123456;, the data is clearly out of range (this is known at compile-time). The compiler flags an error.
  • Variable-to-variable assignment: Consider sh = in;. The value stored in int in at that stage was 4567, which is well within the range of the short type. The compiler chooses not to take chances and flags an error. This can again be preempted with a explicit cast sh = (short) in.

	jshell> byte b = 128;
	| Error:
	| incompatible types: possible lossy conversion from int to byte
	| byte b = 128;
	|_________^--^
	jshell> short s = 123456;
	| Error:
	| incompatible types: possible lossy conversion from int to short
	| short s = 123456;
	|__________^-------^
	jshell> short sh = 3456;
	sh ==> 3456
	jshell> int in = 4567;
	in ==> 3456
	jshell> sh = in;
	| Error:
	| incompatible types: possible lossy conversion from int to short
	| sh = in;
	|______^
	jshell> sh = (short) in;
	sh ==> 4567
	jshell> int num = sh;
	num ==> 4567
	jshell>

Built-In Operators For Integer Types

We already had a glimpse of arithmetic operators for the integer types:

  • +
  • -
  • *
  • /
  • %
  • ++ (both prefix and post-fix increment)
  • -- (both prefix and post-fix increment)

The increment and decrement operators are an interesting case, as they are actually short-hands for multiple statements. When we use their prefix and post-fix versions, we need to look out for side-effects.

Snippet-03 : Increment & Decrement Operators

With post-fix increment, such as in int j = i++;, the increment takes place after the assignment is done. j gets the value before increment.


	jshell> int i = 10;
	i ==> 10
	jshell> int j = i++;
	j ==> 10
	jshell> i
	i ==> 11

When prefix increment is involved, as with int n = ++m;, the increment is carried out before the assignment. n gets the value after increment.

	jshell> int m = 10;
	m ==> 10
	jshell> int n = ++m;
	n ==> 11
	jshell> m
	m ==> 11

With post-fix decrement, as with int l = k--;, the decrement occurs after the assignment is done. As far as prefix decrement is concerned, such as in int q = --p;, the decrement is performed before the assignment.

	jshell> int k = 10;
	k ==> 10
	jshell> int l = k--;
	l ==> 10
	jshell> k
	k ==> 9
	jshell> int p = 10;
	p ==> 10
	jshell> int q = --p;
	q ==> 9
	jshell> p
	p ==> 9
	jshell>

Summary:

In this step, we:

  • Looked at the number-systems supported in Java for integers
  • Examined how prefix and post-fix versions work for increment and decrement operators

Step 03: Classroom Exercise CE-01 (With Solutions)

Exercise Set

  1. Create a Java class BiNumber that stores a pair of integers, and has the following functionality:

    • Can be created by passing its initial two numbers to store
    • Must Support Addition and Multiplication operations on the stored integers
    • An operation to double the values of both numbers
    • Operations to access each number individually

In short, we must be able to write code like this in the main method of our runner class:


	BiNumber numbers = new BiNumber(2, 3);
	System.out.println(numbers.add());
	System.out.println(numbers.multiply());
	numbers.double();
	System.out.println(numbers.getNumber1());
	System.out.println(numbers.getNumber2());

Solution to CE-01

BiNumber.java


	package com.in28minutes.primitive.datatypes;
	
	public class BiNumber {
		private int number1;
		private int number2;

		public BiNumber(int number1, int number2) {
			this.number1 = number1;
			this.number2 = number2;
		}

		public int add() {
			return number1 + number2;
		}

		public int multiply() {
			return number1 * number2;
		}

		public void doubleValue() {
			number1 *= 2;
			number2 *= 2;
		}

		public int getNumber1() {`
			return number1;
		}

		public int getNumber2() {
			return number2;
		}

		public void setNumber1(int number1) {
			this.number1 = number1;
		}

		public void setNumber2(int number2) {
			this.number2 = number2;
		}
	}

BiNumberRunner.java


	package com.in28minutes.primitive.datatypes;

	public class BiNumberRunner {
		public static void main(String[] args) {
			BiNumber numbers = new BiNumber(2, 3);
			System.out.println(numbers.add());
			System.out.println(numbers.multiply());
			numbers.doubleValue();
			System.out.println(numbers.getNumber1());
			System.out.println(numbers.getNumber2());
		}
	}

Console Output

5

6

4

6

Step 05: Floating-Point Types

You would recall there are two types in Java to support floating-point numbers:

  • double: The default type for floating-point literals, with a capacity of 8 bytes
  • float: A narrower, less precise representation for floating-point data. It has a capacity of 4 bytes.

Let's quickly refresh what we know, with a few code snippets.

Snippet-01 : double and float

Default floating point type in Java is double. A float literal must be accompanied with a trailing f or F.


	jshell> float f = 34.5;
	| Error:
	| incomaptible types: possible lossy conversion from double to float
	| float f = 34.5;
	|_________^---^
	jshell> float f = 34.5f;
	f ==> 34.5
	jshell> float fl = 34.5F;
	fl ==> 34.5
	jshell> double d = 34.5678;
	d ==> 34.5678
	jshell> float flo = d;
	| Error:
	| incomaptible types: possible lossy conversion from double to float
	| float flo = d;
	|__________^
	jshell> float flo = (float) d;
	flo ==> 34.567
	jshell>

Snippet-02 : Operators for type double

You can use operators ++, -- and % on double.


jshell> double dbl = 34.5678;
dbl ==> 34.5678

jshell> dbl++
$3 ==> 34.5678

jshell> dbl
dbl ==> 35.5678

jshell> dbl--
dbl ==> 35.5678
jshell> dbl % 5
dbl ==> 4.567799999999998

You would need an explicit cast to convert a float to an integer value int i = (int)f.

	jshell> float f = 34.5678f;
	f ==> 34.5678
	jshell> int i = f;
	| Error:
	| incomaptible types: possible lossy conversion from float to int
	| int i = f;
	|_______^
	jshell> int i = (int)f;
	i ==> 34
	jshell> float fl = i;
	fl ==> 34.0
	jshell>

Summary

In this step, we:

  • Saw how we create literals and variables of the floating-point types
  • Understood the differences between double and float

Step 06: Introducing BigDecimal

Compact though they are, double and float are not very precise representations of floating-point numbers.

In fact, they are not used in computations that require high degrees for accuracy, such as scientific experiments and financial applications. The next example shows you why.


	jshell> 34.56789876 + 34.2234
	$1 ==> 68.79129875999999

The literal expression 34.56789876 + 34.2234 should evaluate to 68.79129876. Above addition is not really accurate.

This is due to a flaw in floating-point representations, used in the double and float types.

The BigDecimal class was introduced in Java to tide over these problems.

Accuracy of BigDecimal representation is retained only when String literals are used to build it.


	jshell> BigDecimal number1 = new BigDecimal("34.56789876");
	number1 ==> 34.56789876
	jshell> BigDecimal number2 = new BigDecimal("34.2234");
	number2 ==> 34.2234_

A BigDecimal type can be used to create only immutable objects. The values in an immutable object cannot be changed after creation.

You can see that the value of number1 is not changed on executing number1.add(number2). To get the result of the sum, we create a new variable sum.

	jshell> number1.add(number2);
	$2 ==> 68.79129876
	jshell> number1
	number1 ==> 34.56789876
	jshell> BigDecimal sum = number1.add(number2);
	sum ==> 68.79129876

Summary

In this step, we:

  • Learned that double and float are not very precise data types
  • Were introduced to the BigDecimal built-in data type
  • Understood that BigDecimal is immutable
  • Saw that accuracy is best achieved when you construct BigDecimal data using string literals

Step 06: BigDecimal Operations

Let's look at a few other operations defined in the BigDecimal class.

Snippet-01: Arithmetic Operations

All BigDecimal operations support only BigDecimal operands.


	jshell> BigDecimal number1 = new BigDecimal("11.5");
	number1 ==> 34.56789876
	jshell> BigDecimal number2 = new BigDecimal("23.45678");
	number2 ==> 23.45678
	jshell> number1.add(number2);
	$1 ==> 34.95678

BigDecimal does not jell well with primitive types.

	jshell> int i = 5;
	i ==> 5
	jshell> number1.add(i);
	| Error:
	| incompatible types: int cannot be converted to java.math.BigDecimal
	| number1.add(i);
	|_____________^

We can add, multiple, divide or subtract BigDecimal values.

	jshell> number1.add(new BigDecimal(i));
	$2 ==> 16.5
	jshell> number1.multiply(new BigDecimal(i));
	$3 ==> 67.5
	jshell> number1.divide(new BigDecimal(100));
	$4 ==> 0.115
	jshell>

Summary

In this step, we:

  • Explored the BigDecimal methods for doing some basic arithmetic
  • Found that BigDecimal has constructors accepting most basic Java numeric types

Step 07: Classroom Exercise CE-02

Exercise-Set

Write a Program that does a Simple Interest computation for a Principal amount. Recall that the formula for such a calculation is:

Total amount (TA) = Principal Amount (PA) + ( PA * Simple Interest (SI) Rate * Duration In Years (N))

In essence, write a SimpleInterestCalculator class that can be used in the following manner:


	SimpleInterestCalculator calculator = new SimpleInterestCalculator("4500.00", "7.5");
	BigDecimal totalValue = calculator.calculateTotalValue(5); //5 year duration
	System.out.println(totalValue);

Solution To CE-02

SimpleInterestCalculatorRunner.java


	package com.in28minutes.primitive.datatypes;
	import java.math.BigDecimal;

	public class SimpleInterestCalculatorRunner {
		public static void main(String[] args) {
			SimpleInterestCalculator calculator = new SimpleInterestCalculator("4500.00", 7.5");
			BigDecimal totalValue = calculator.calculateTotalValue(5); //5 year duration
			System.out.println(totalValue);
		}
	}

SimpleInterestCalculator.java


	package com.in28minutes.primitive.datatypes;
	import java.math.BigDecimal;

	public class SimpleInterestCalculatorRunner {
		BigDecimal principal;
		BigDecimal interest;

		public SimpleInterestCalculator(String principal, String interest) {
			this.principal = new BigDecimal(principal);
			this.interest = new BigDecimal(interest).divide(new BigDecimal(100));
		}

		public BigDecimal calculateTotalValue(int noOfYears)
			//Total Value = Principal  + Principal * Interest* Years
			BigDecimal totalValue = prinipal.add(principal.multiply(interest).multiply(new BigDecimal(noOfYears)));
			return totalValue;`
		}	
}

Console Output:

6187.50000

Tip: The import Statement

The Java import statement is Required in each source file that uses a class from another package. Hence, both SimpleInterestCalculator.java (class definition) and SimpleInterestCalculatorRunner.java (runner class definition) need to import class java.math.BigDecimal.

package java.lang.* is imported by default.

The .* suffix indicates that all classes in the package java.lang are being imported.

Summary

In this step, we:

  • Used BigDecimal values in a stand-alone Java program
  • Learnt how to make use of built-in Java packages, through the import statement

Step 08: boolean, Relational and Logical Operators

The Java boolean data type is one that holds only one of two values: true or false. Both labels are case-sensitive. We have seen examples of built-in comparison operators, such as ==, != and >, that evaluate expressions to give us boolean results. Let us do a quick recap of some of these.

Snippet-01 : Relational Operators : Recap

Relational Operators are used mainly for comparison. They accept operands of non-boolean primitive data types, and return a boolean value.


	jshell> int i = 7;
	i ==> 7
	jshell> i > 7;
	$1 ==> false
	jshell> i >= 7;
	$2 ==> true
	jshell> i < 7;
	$3 ==> false
	jshell> i <= 7;
	$4 ==> true
	jshell> i == 7;
	$5 ==> true
	jshell> i == 8;
	$6 ==> false
	jshell>
	

Logical Operators

Java also has logical operators that are used in expressions. Logical operators expect boolean operands. Expressions involving these are used for forming boolean conditions in code, including within if, for and while statements. The prominent logical operators are:

  • && : logical AND
  • || : OR
  • ! : NOT

Let's learn how we use them in our code.

Snippet-02 : Logical Operators

We would want to find if i is between 15 and 25. An expression i >= 15 && i <= 25 can be used. Details below.


	jshell> int i = 17;
	i ==> 17
	jshell> i >= 15
	$1 ==> true
	jshell> i <= 25
	$2 ==> true
	jshell> i >= 15 && i <= 25
	$3 ==> true
	jshell> i == 30;
	i ==> 30
	jshell> i >= 15 && i <= 25
	$4 ==> false
	jshell> i == 5;
	i ==> 30
	jshell> i >= 15 && i <= 25
	$5 ==> false

An expression with&& evaluates to true only if both its boolean operands evaluate to true.

	jshell> true && true
	$6 ==> true
	jshell> true && false
	$7 ==> false
	jshell> false && true
	$8 ==> false
	jshell> false && false
	$9 ==> false
	jshell>

Snippet-02 Explained

The next example helps us visualize truth tables for the prominent logical operators.


	jshell> true || true
	$1 ==> true
	jshell> true || false
	$2 ==> true
	jshell> false || true
	$3 ==> true
	jshell> false || false
	$4 ==> false
	jshell> true ^ true
	$5 ==> false
	jshell> true ^ false
	$6 ==> true
	jshell> false ^ true
	$7 ==> true
	jshell> false ^ false
	$8 ==> false
	jshell> !true
	$9 ==> false
	jshell> !false
	$10 ==> true
	jshell> int x = 6;
	x ==> 6
	jshell> !(x > 7)
	$11 ==> true
	jshell>

Summary

In this step, we:

  • We're introduced to the boolean primitive type
  • Understood where logical operators are used in Java programs
  • Explored the truth-tables of commonly used logical operators

Step 09: Short-Circuit Evaluation (With Puzzles)

Consider code below. The expression j > 15 && i++ > 5 evaluates to false as expected. j>15 is false as j has a value of 15.


	jshell> int j = 15;
	j ==> 15
	jshell> int i = 10;
	i ==> 10
	jshell> j > 15 && i++ > 5
	$1 ==> false
	jshell> j
	j ==> 15
	jshell> i
	i ==> 10

You can also observe that the value of i remains unchanged 10.

Why? Because i++ > 5 was not even evaluated. Why? && is lazy. It saw that j > 15 is false. Irrespective of the result of second expression, the result of this && would be false. So, it does NOT evaluate the second expression.

A more detailed explanation

The expression j > 15 && i++ > 5 was scanned from left to right. As the first operand to && evaluated to false, the compiler got lazy. && avoids evaluating expressions that don't affect the final result. The optimization has a name: Short-Circuit Evaluation, also called lazy evaluation.

The logical operator & is another version of the logical AND operation, that does away with lazy evaluation.

Both operands to & are always evaluated.


	jshell> j > 15 & i++ > 5
	$1 ==> false
	jshell> j
	j ==> 15
	jshell> i
	i ==> 11
	jshell>

Similarly, the logical OR operator also has two versions:

  • The || operator we saw earlier. This exhibits lazy evaluation.
  • The | operator, without lazy evaluation.

It is bad programming practice for our code to depend on the compiler's lazy evaluation. It makes code less readable, and can hide difficult-to-fix software bugs. It obviously adds to the code maintenance burden, so don't do it unless you like being in your peers' bad books.

Summary

In this step, we:

  • Examined conditions involving logical operators, that had lazy evaluation
  • Observed that the lazy evaluation depends on the operator's truth-table
  • Saw versions of the operators without lazy evaluation
  • Learned that code depending on lazy-evaluation, is less readable

Step 10: Character Types

Earlier, we explored how we could store basic keyboard characters(called ascii-code characters), such as:

  • Upper-Case and lower-case letters (A-Z, a-z)
  • Numeric characters (0-9)
  • Punctuation and other special characters (such as ',', '$', '{', etc.)

Turns out Java supports a much larger family of character encoding sets, called Unicode. All Unicode characters can be input to, understood and processed by, as well as output from your code.

Snippet-01 : Unicode characters

Not all Unicode characters can be input from your keyboard. But Java allows you to handle their values from your code, if you deal correctly with their format.

 
	jshell> char ch = '"';
	ch ==> '"'
	jshell> char c = '\u0022';
	c ==> '"'

Integer values can be stored in char variables. If the value is within a meaningful range, it also corresponds to the ascii value of a keyboard character.

	jshell> char cn = 65;
	cn ==> 'A'

Integer arithmetic can be performed on char data.

	jshell> cn++
	$1 ==> 'A'
	jshell> cn
	$2 ==> 'B'
	jshell> ++cn
	$3 ==> 'C'
	jshell> cn + 5
	$4 ==> 72
	jshell> cn
	cn ==> 'C'
	jshell> (int)cn
	cn ==> 67
	jshell>

Summary

In this step, we:

  • Were introduced the the char data type
  • Learned that Unicode takes the character set beyond your keyboard
  • An ascii character is char value, encoded by an integer value

Step 11: Programming Exercise PE-02

Exercise Set

  1. Write a Java class MyChar that is a special type of char. An object of type MyChar is created round an input char data element, and has operations that do the following:
    • Check if the input character is a:
      • Numeric Digit
      • Letter of the Alphabet
      • Vowel (Either upper-case or lower-case)
      • Consonant (Either upper-case or lower-case) NOTE: A letter is a consonant if not a vowel
    • Print all the letters of the Alphabet in
      • Upper-Case
      • Lower-Case

In Essence, a runner class for MyChar would have its main method run code similar to:


	MyChar myChar = new MyChar('c');
	System.out.println(myChar.isDigit());
	System.out.println(myChar.isAlphabet());
	System.out.println(myChar.isVowel());
	System.out.println(myChar.isConsonant());
	myChar.printLowerCaseAlphabets();
	myChar.printUpperCaseAlphabets();

Step 12: Solution To PE-02, Part 1 - isVowel()

MyCharRunner.java


	package com.in28minutes.primitive.datatypes;

	public class MyCharRunner {
		public static void main(String[] args) {
			MyChar myChar = new MyChar('c');
			System.out.println(myChar.isVowel());
		}
	}

MyChar.java


	package com.in28minutes.primitive.datatypes;
	
	public class MyChar {
		private char ch;
		
		public MyChar(char ch) {
			this.ch = ch;
		}

		public boolean isVowel() {
			if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
				return true;
			} 
			if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
				return true;
			}
			return false;
		}
	}

Console Output :

false

Step 13: Solution To PE-02, Part 2 - isDigit()

MyCharRunner.java


	package com.in28minutes.primitive.datatypes;

	public class MyCharRunner {
		public static void main(String[] args) {
			MyChar myChar = new MyChar('c');
			System.out.println(myChar.isDigit());
			System.out.println(myChar.isVowel());
		}
	}

MyChar.java


	package com.in28minutes.primitive.datatypes;

	public class MyChar {
		private char ch;

		public MyChar(char ch) {
			this.ch = ch;
		}

		public boolean isVowel() {
			if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
				return true;
			} 

			if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
				return true;
			}
			return false;
		}

		public boolean isDigit() {
			if(ch >= 48 && ch <= 57) {
				return true;
			}
			return false;
		}

}

Console Output :

false

false

Step 14: Solution To PE-02, Part 3 - Other Methods

MyCharRunner.java


	package com.in28minutes.primitive.datatypes;
	
	public class MyCharRunner {
		public static void main(String[] args) {
			MyChar myChar = new MyChar('c');
			System.out.println(myChar.isDigit());
			System.out.println(myChar.isAlphabet());
			System.out.println(myChar.isVowel());
			System.out.println(myChar.isConsonant());
			myChar.printLowerCaseAlphabets();
			myChar.printUpperCaseAlphabets();
		}
	}

MyChar.java


	package com.in28minutes.primitive.datatypes;

	public class MyChar {
		private char ch;
		
		public MyChar(char ch) {
			this.ch = ch;
		}

		public boolean isVowel() {
			if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
				return true;
			} 
			if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
				return true;
			}
			return false;
		}

		public boolean isConsonant() {
			if(isAlphabet() && !(isVowel())) {
				return true;
			}
			return false;
		}

		public boolean isDigit() {
			if(ch >= 48 && ch <= 57) {
				return true;
			}
			return false;
		}

		public boolean isAlphabet() {
			if(ch >= 97 && ch <= 122) {
				return true;
			}
			if(ch >= 65 && ch <= 90) {
				return true;
			}
			return false;
		}

		public void printLowerCaseAlphabets() {
			for(char ch='a'; ch <= 'z'; ch++) {
				System.out.println(ch);
			}
		}

		public void printUpperCaseAlphabets() {
			for(char ch='A'; ch <= 'Z'; ch++) {
				System.out.println(ch);
			}
		}
	}

Console Output :

false

true

false

true

a

b

c

d

e

f

g

h

i

j

k

l

m

n

o

p

q

r

s

t

u

v

w

x

y

z

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

Step 15: The Primitive Types - A Review

In this section, we built on our knowledge of the primitive Java types.

  • We first got familiar with built-in wrappers for the integer types, that store useful type information.
  • Going from the integer to the floating-point types, we examined type compatibility, and how the compiler warns you about common pitfalls. We used explicit casts to force type conversions, and learned that implicit type conversions are quite common.
  • We moved on to the BigDecimal class, a floating-point type with greater precision and accuracy.
  • Next in line was boolean, where we built on what we know of logical expressions. We focused on the logical operators, more so on short-circuit evaluation of their expressions.
  • We saw how dependency on side-effects, and on lazy evaluation, is not a good programming practice.
  • Finally, we got to the char type, and were pleasantly surprised to know, that the keyboard is not the limit.

Introducing Conditionals - if, switch and more

Decision making is a part of our daily lives. Computers do tasks for humans, so even programs need to make decisions. They do this by checking logical conditions, which evaluate to boolean values.

In the following steps, we will explore the following conditional statements:

  • if
  • if-else
  • if-else if-else
  • switch

What better way to master these basics, than using them to solve a programming challenge?

Here we go!

Programming Challenge : Design A Menu (The Menu-Challenge)

  • Ask the User for input:
    • Enter two numbers
    • Choose the arithmetic to do on those:
      • Add
      • Subtract
      • Multiply
      • Divide
  • Perform the Operation
  • Publish the Result

An example scenario could be:

Enter First Number

2

Enter Second Number

4

1 - Add

2 - Subtract

3 - Multiply

4 - Divide

Enter your choice of operation

3

The Result Is : 8

Summary

In this step, we:

  • Discussed how input affects the control-flow of a program
  • Listed out the conditionals available with Java
  • Selected a programming challenge to help us learn about conditions

Step 01: The if and if-else Conditionals

An if statement is the most basic way to manage control-flow in a program. A boolean condition is tested, and if found to be true, some code is executed. Otherwise, that code is not run.

  • "Do Something when condition is true"

Conceptually, the if statement looks like this:


	if(condition) {
		<if-body>
	}

An if-else statement improves over the plain if. We can now choose between executing two pieces of code, depending on what condition evaluates to.

  • "Do Something when condition is true, something else when condition is false"

An if-else statement boils down to the following:


	if(condition) {
		<if-body>
	} else {
		<else-body>
	}

If condition is found to be true, the statement block <if-body> is executed, otherwise <else-body> is run.

Let's now look at a examples that make use of these conditionals.

Snippet-01 : if behavior

In this example:

  • we have used compound comparison operators such as <= and >=, which also evaluate to boolean values.
  • Also used, are logical operators such as && and ||, which both accept and return values of type boolean.

	jshell> int i = 3;
	i ==> 3
	jshell> if(i==3) {
	   ..>> System.out.println("True");
	   ..>> }
	True
	jshell> if(i<2) {
	   ..>> System.out.println("True");
	   ..>> }
	
	jshell> if(i<=3 || i >= 35) {
	   ..>> System.out.println("True");
	   ..>> }
	True
	jshell> if(i<=3 && i >= 35) {
	   ..>> System.out.println("True");
	   ..>> }

if-else allows us to specify code to execute when a condition is false.

	jshell> if(i==3) {
	   ..>> System.out.println("True");
	   ..>> } else {
	   ..>> System.out.println("i is not 3");
	   ..>> }
	True
	jshell> i = 5;
	i ==> 5
	jshell> if(i==3) {
	   ..>> System.out.println("True");
	   ..>> } else {
	   ..>> System.out.println("i is not 3");
	   ..>> }
	i is not 3
	jshell>

Snippet-02 : chained if-else - v1

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			//int i=25;
			int i=26;
			if(i == 25) {
				System.out.println("i = 25");
			} else {		
				System.out.println("i != 25");
			}
		}
	}

Console Output

i != 25

Snippet-03 : chained if-else v2

We would want to test a number for 3 conditions - value is 24, value is 25 or value is not 24 and 25. Let's consider the code from the example below.

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24
			
			int i=25;
			if(i == 25) {
				System.out.println("i = 25");
			}
			if(i == 24) {
				System.out.println("i = 24"); 
			} else {			
				System.out.println("i != 25 and i != 24");
			}
		}
	}

Console Output

i = 25

i != 25 and i != 24

Snippet-03 Explained

What just happened here? The value of i is set to 25 within the program, so like in the previous example, only i = 25 should have been printed.

Why the extra print?

We started off trying to check fro 3 possibilities: * i being equal to 25 * i being equal to 24 * Neither of the above

We get wrong output, because i == 25 in first if is independent from i == 24 in the if-else that follows it.

Our decision making is not continuous. We need a tighter conditional to deal with more than two alternatives. We will explore this topic in the next step.

Summary

In this step, we:

  • Learned about the if and if-else conditionals
  • Tried out a few examples to see how they are used

Step 02: The if-else if-else Conditional

The if-else if-else statement solves the issue we faced, while trying to test more than two conditions.

Let's see an example.

Snippet-01 : Matching The if Clause

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24

			int i=25;
			if(i == 25) {
				System.out.println("i = 25");
			} else if(i == 24) {
				System.out.println("i = 24"); 
			} else {
				System.out.println("i != 25 and i != 24");
			}
		}
	}

Console Output

i = 25

Let's now try giving i a different value, say 24.

Snippet-02: Matching The else if Clause

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25		
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24
		
			//int i=25;
			int i=24;
			if(i == 25) {
				System.out.println("i = 25");
			} else if(i == 24) {
				System.out.println("i = 24"); 
			} else {
				System.out.println("i != 25 and i != 24");		
			}
		}
	}

Console Output

i = 24

Snippet-02 Explained
  • With i holding 24, a different condition (the one coresponding to i == 24) evaluates to true.

Let's now try to get a match with the else clause, the only one unexplored so far.

Snippet-03: Matching The else Clause

IfStatementRunner.java


	com.in28minutes.ifstatement.examples;

	public class IfStatementRunner {
		public static void main(String[] args) {
			// if i is 25, print i = 25
			//if i is 24, print i = 24
			//otherwise, print i != 25 and i != 24
			
			//int i=24;
			int i=26;
			if(i == 25) {
				System.out.println("i = 25");
			} else if(i == 24) {
				System.out.println("i = 24"); 
			} else {
				System.out.println("i != 25 and i != 24");
			}
		}
	}

Console Output

i != 25 and i != 24

Snippet-03 Explained

When i is given a value of 26, the first two conditions are false. Hence, the code in the else gets executed.

one, and only one clause among those present in an if-else if-else statement ever evaluates to true. Also, the code block corresponding to the matched clause will get executed. This is ensured even if conditions are duplicated, or overlap. In that scenario, only the first such condition, downward from the if in sequence, will evaluate to true. The remaining possible matches are not even checked.

Summary

In this step, we:

  • Learned about the if-else if-else conditional
  • Found out how to test when each different clause gets executed
  • Understood the guarantees made by Java regarding the conditional's code execution

Step 03: Puzzles on if

Try and guess the outputs of the following puzzles.

Programming Puzzle PP-01


	public class puzzleRunner {

		public static void main(String[] args) {
			puzzleOne();
		}

		public static void puzzleOne() {
			int k = 15;
			if(k > 20) {
				System.out.println(1);
			} else if(k > 10) {
				System.out.println(2);
			} else if(k < 20) {
				System.out.println(3);
			} else {
				System.out.println(4);
			}
		}
	}

Answer:

2

Programming Puzzle PP-02


	public class puzzleRunner {
		public static void main(String[] args) {
			puzzleTwo();
		}

		public static void puzzleTwo() {
			int l = 15;
			if(l < 20)
			System.out.println("l < 20");
			if(l > 20)
			System.out.println("l > 20");
			else
			System.out.println("Who Am I?");
		}
	}

Answer:

l < 20

Who Am I?

Programming Puzzle PP-03


	public class puzzleRunner {
		public static void main(String[] args) {
			puzzleThree();
		}
		
		public static void puzzleThree() {
			int m = 15;
			if(m > 20)
			if(m < 20)
			System.out.println("m >  20");	else
			System.out.println("Who Am I?");
		}
	}

Answer:

Nothing is printed. Because the code is structured this way.

if(m > 20) {
	if(m < 20)
		System.out.println("m >  20");	
	else
		System.out.println("Who Am I?");
}

Programming Puzzle PP-04


	jshell> int i = 0;
	i ==> 3
	jshell> if(i) {
	   ..>> System.out.println("i");
	   ..>> }
	| Error:
	| incompatible types: int cannot be converted to boolean
	| if(i)
	|____^
	jshell> if(i=1) {
	   ..>> System.out.println("i");
	   ..>> }
	| Error:
	| incompatible types: int cannot be converted to boolean
	| if(i=1)
	|____^-^
	jshell> if(i==1) {
	   ..>> System.out.println("i");
	   ..>> }
	jshell>

Answer:

Compiler Error

Programming Puzzle PP-05


	public class puzzleRunner {
		public static void main(String[] args) {
			puzzleFive();
		}

		public static void puzzleFive() {
			int number = 5;
			if(number < 0)
			number = number + 10;
			number++;
			System.out.println(number);
		}
	}

**Answer : **

6

In the absence of explicit blocks, Only the statement next to the if statement is considered to be part of the if statement block.

Step 04: Reading User Input


Look at the statement of Menu-Challenge once again:

  • Ask the User for input:
    • Enter two numbers
    • Choose an Arithmetic Operation to perform on them:
      • Add
      • Subtract
      • Multiply
      • Divide
  • Perform the Operation
  • Publish the Result

We have a good idea about how the if-else if-else conditional works.What we don't know, however, is how a such a conditional would behave when fed with random input. To test those scenarios out, the next step would be to learn how to take console input, from within our code.

We will do just that, in our next example.

Snippet-01: Reading console input

Java provides a built-in class named Scanner, to scan user input from the console. Roping in this utility would require you, the programmer, to do the following:

  • import the java.util.Scanner class within your code (here, we were writing code in the Eclipse IDE)
  • Create a scanner object which is of type Scanner. This involves invoking the Scanner constructor through the new operator. You also need to pass System.in as a constructor parameter, which ties scanner to the console input.
  • To read integer input from the console, call the method scanner.nextInt(). The keyboard's key needs to be pressed to complete user input. That number is passed on to your code, whe

Truncated — view the full README on GitHub.

java
java-8
java8
programming
programming-challenges
programming-fundamentals

Significant stargazers

Maheshkumar P

97 followers · starred Jan 2023

shixiong2333

4 followers · starred Mar 2025