The Java Handbook
The Java Handbook
For now, I can tell you that although Java has its fair
share of flaws, it also a has a lot to offer.
Table of Contents
Prerequisites
How to Write Hello World in Java
What’s Going On in the Code?
What is JVM?
What is JRE and JDK?
How To Setup Java on Your Computer?
How To Install a Java IDE on Your Computer?
How To Create a New Project on IntelliJ IDEA
How to Work with Variables in Java
What Are the Rules for Declaring Variables?
What Are final Variables?
What are the Primitive Data Types in Java?
What is Type Conversion or Casting?
What are Wrapper Classes in Java
How to Use Operators in Java
What Are the Arithmetic Operators?
What Are the Assignment Operators?
What Are the Relational Operators?
What Are the Logical Operators?
What Are the Unary Operators?
How to Work with Strings in Java
How to Format a String
How to Get the Length of a String or Check if It's Empty
or Not
How to Split and Join Strings
How to Convert a String to Upper or Lowercase
How to Compare Two Strings
How to Replace Characters or Substring in a String
How to Check If a String Contains a Substring or Not
What Are the Different Ways of Inputting and
Outputting Data?
How to Use Conditional Statements in Java
What is a switch-case statement?
What is Variable Scope in Java?
What Are Default Values of Variables in Java?
How to Work with Arrays in Java
How to Sort an Array
How to Perform Binary Search on an Array
How to Fill an Array
How to Make Copies of an Array
How to Compare Two Arrays
How to Use Loops in Java
For Loop
For-Each Loop
While Loop
Do-While Loop
How to Work with Array Lists in Java
How to Add or Remove Multiple Elements
How to Remove Elements Based on a Condition
How to Clone and Compare Array Lists
How To Check if an Element Is Present or the Array List
Is Empty
How to Sort an Array List
How To Keep Common Elements From Two Array Lists
How To Perform an Action on All Elements of an Array
List
How To Work With Hash Maps in Java
How To Put or Replace Multiple Elements in a Hash Map
How To Check if a Hash Map Contains an Item or if It’s
Empty
How To Perform an Action on All Elements of a Hash
Map
Classes and Objects in Java
What is a Method?
What is Method Overloading?
What are Constructors in Java?
What Are Access Modifiers in Java?
What Are the Getter and Setter Methods in Java?
What is Inheritance in Java?
How to Override a Method in Java
Conclusion
Prerequisites
The only re-requisite for this course is familiarity with
any other programming language such as Python,
JavaScript, and so on.
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
Let's start with the first line:
class Main {
//...
}
This line creates a Main class. A class groups together a
bunch of related code within a single unit.
This is a public class, which means this class is
accessible anywhere in the codebase. One Java source
file (files with the .java extension) can contain only one
top level public class in it.
This top level public class has to be named exactly the
same as the source code filename. That's why the file
named Main.java contains the main class in this project.
To understand why, click on the three dots in the list of
files and click on the Show hidden files option.
This will unveil some new files within the project.
Among them is the Main.class file. This is called a
bytecode. When you hit the Run button, the Java
compiler compiled your code from the Main.java file into
this bytecode.
Now, modify the existing Hello World code as follows:
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
class NotMain {
public static void main(String[] args) {
System.out.println("Not hello world!");
}
}
As you can see, a new class called NotMain has been
added. Go ahead and hit the Run button once more
while keeping your eyes on the Files menu.
A new bytecode named NotMain.class has showed up.
This means that for every class you have within your
entire codebase, the compiler will create a separate
bytecode.
This creates confusion about which class is the entry-
point to this program. To solve this issue, Java uses the
class that matches the source code file name as the
entry-point to this program.
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
The public static void main (String[] args) function is
special in Java. If you have experience with languages
like C, C++ or Go, you should already know that every
program in those languages has a main function. The
execution of the program begins from this main
function.
In Java, you have to write this function as exactly public
static void main (String[] args) otherwise it won't work.
In fact, if you change it even a little bit Java will start to
scream.
The return type has changed from void to int and the
function now returns 0 at the end. As you can see in the
console, it says:
Error: Main method must return a value of type void in class Main, please
define the main method as:
public static void main(String[] args)
Listen to that suggestion and revert your program back
to how it was before.
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
The main method is a public method and
the static means, you can call it without instantiating its
class.
The void means that the function doesn't return any
value and the String[] args means that the function
takes an array of strings as an argument. This array
holds command line arguments passed to the program
during execution.
The System.out.println prints out strings on the terminal.
In the example above, "Hello world!" has been passed to
the function, so you get Hello world! printed on the
terminal.
In Java, every statement ends with a semicolon. Unlike
JavaScript or Python, semicolons in Java are
mandatory. Leaving one out will cause the compilation
to fail.
That's pretty much it for this program. If you didn't
understand every aspect of this section word by word,
don't worry. Things will become much clearer as you go
forward.
java --version
The code will run and the output will be shown in the
integrated terminal at the bottom of the window.
Congratulations, you've successfully recreated the
previously discussed HelloWorld program in IntelliJ IDEA.
How to Work with Variables in Java
To work with different kinds of data in Java, you can
create variables of different types. For example, if you
want to store your age in a new variable, you can do so
like this:
}
You start by writing out the type of data or variable.
Since age is a whole number, its type will be integer
or int for short, followed by the name of the
variable age and a semicolon.
At the moment, you've declared the variable but you
haven't initialized it. In other words, the variable doesn't
have any value. You can initialize the variable as
follows:
// <name> = <value>
age = 27;
// prints the age on the terminal
System.out.println("I am " + age + " years old.");
}
When assigning a value, you start by writing the name
of the variable you want to initialize, followed by an
equal sign (it's called the assignment operator) then the
value you want to assign to the variable. And don't
forget the semicolon at the end.
at variables.Main.main(Main.java:13)
The line The local variable age may not have been
initialized indicates that the variable has not been
initialized.
Instead of declaring and initializing the variable in
different lines, you can do that in one go as follows:
}
The code should be back to normal again. Also, you can
change the value of a variable as many times as you
want in your code.
}
In this code, the value of age will change from 27 to 28
because you're overwriting it just before printing.
Keep in mind, while you can assign values to a variables
as many times as you want, you can not declare the
same variable twice.
}
If you try to compile this code, the compiler will throw
the following error message at you:
at variables.Main.main(Main.java:9)
The line Duplicate local variable age indicates that the
variable has already been declared.
Apart from variables, you may find the term "literal" on
the internet. Literals are variables with hardcoded
values.
Start your variable name with small letter and not any
special character (like an underscore or dollar sign).
If the variable name has multiple words, use camel
case: firstName, lastName
Don't use single letter names: f, l
As long as you follow these rules and conventions,
you're good to go. If you'd like to learn more about
naming conventions in general, checkout my article on
the topic.
What Are final Variables?
A final variable in Java can be initialized only once. So if
you declare a variable as final, you can not reassign it.
public class Main {
age = 28;
}
Since the age variable has been declared as final, the
code will throw the following error message at you:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The final local variable age cannot be assigned. It must be blank and not
using a compound assignment
at variables.Main.main(Main.java:9)
However, if you leave the variable uninitialized while
declaring, the code will work:
age = 28;
}
So, declaring a variable as final will limit your ability to
reassign its value. If you leave it uninitialized, you'll be
able to initialize it as usual.
What are the Primitive Data Types in Java?
At a high level, there are two types of data in Java.
There are the "primitives types" and the "non-primitive"
or "reference types".
TYPE EXPLANATION
byte 8-bit signed integer within the range of -128 to 127
short 16-bit signed integer within the range of -32,768 to 32,767
32-bit signed integer within the range of -2147483648 to
int 2147483647
64-bit signed integer within the range of -
long 9223372036854775808 to 9223372036854775807
single-precision 32-bit floating point within the range of 1.4E-45
float to 3.4028235E38
double-precision 64-bit floating point within the range of 4.9E-
double 324 to 1.7976931348623157E308
boolean It can be either true or false
}
}
If you assign an int to the double, such as 4 instead
of 4.8, the output will be 4.0 instead of 4,
because double will always have a decimal point.
Since double and float are similar, you may think that
replacing the double keyword with float will convert this
variable to a floating point number – but that's not
correct. You'll have to append a f or F after the value:
public class Main {
System.out.println(isWeekend); // false
}
}
As you can imagine, false can be treated as a no
and true can be treated as a yes.
Booleans will become much more useful once you've
learned about conditional statements. So for now, just
remember what they are and what they can hold.
System.out.println(percentSign); // %
}
}
In this example, you've saved the percent sign within
a char variable and printed it out on the terminal.
You can also use Unicode escape sequences to print out
certain symbols.
System.out.println(copyrightSymbol); // ©
}
}
The Unicode escape sequence for the copyright symbol,
for example, is \u00A9 and you can find more Unicode
escape sequences on this website.
Among these 8 types of data, you'll be working
with int, double, boolean, and char majority of the time.
What is Type Conversion or Casting?
Type conversion in Java can be either "implicit" or
"explicit". When the compiler converts a smaller type of
data to a larger one automatically, it's known as an
implicit or narrowing type conversion.
System.out.println(number2); // 8.0
}
}
Since a double is larger than an integer, the compiler
could easily perform the conversion. If you try to do the
reverse however, you'll face the following error from the
compiler:
at operators.Main.main(Main.java:7)
When performing an implicit conversion, the flow of
conversion should be as follows:
package datatypes;
System.out.println(number2); // 8
}
}
Previously you've seen that if you try to convert a larger
data type to a smaller one, the compiler complains. But
when you add the (int) cast operator explicitly, you
show the compiler who's boss.
In doing so, you lose a part of your data. If you change
the initial double number from 8.5 to just 8.0, you'll not
lose any information. So whenever you're performing an
explicit conversion, be careful.
You can also convert a char to an int as follows:
public class Main {
System.out.println(number); // 70
}
}
70 is the ASCII code for the character F – that's why the
output was like this. If you'd like to learn more about
ASCII codes, my colleague Kris Koishigawa has
written an excellent article on the topic.
The flow of conversion in this case will be the opposite
of what you've seen already.
Primitive Wrapper
Type Class
int Integer
long Long
short Short
byte Byte
boolean Boolean
char Character
float Float
double Double
System.out.println(age); // 27
System.out.println(gpa); // 4.8
}
}
All you have to do is replace the primitive data type
with the equivalent wrapper class. These reference
types also have methods for extracting the primitive
type from them.
OPERATO
R OPERATION
+ Addition
- Subtraction
* Multiplication
/ Division
Remainder
% (Modulo/Modulus)
Addition, subtraction, multiplication, and division
operations are pretty self-explanatory. Have a look at
the following code example to understand:
System.out.println(number1 + number2); // 15
System.out.println(number1 - number2); // 5
System.out.println(number1 * number2); // 50
System.out.println(number1 / number2); // 2
System.out.println(number1 % number2); // 0
}
Outputs from the first four operations need no
explanation. In the last operation, you've performed a
modulo/modulus operation using the % symbol. The
result is 0 because if you divide 10 by 2, there'll be
nothing left (no remainder).
Addition and multiplication operations are quite simple.
But, when performing a subtraction, if the first operand
is larger than the second operand, the result will be a
negative number, just like in real life.
System.out.println(number1 / number2); // 1
}
}
Although the result of this operation should've been 1.6
it didn't happen because in Java, if you divide an integer
by another integer, the result will be an integer. But if
you change both or one of them to a float/double,
everything will be back to normal.
}
This principle applies to the modulo operations as well.
If both or one of the operands are a float/double, the
result will be a float/double.
}
}
When you use the = symbol to assign a value to a
variable, it works as an assignment operator. But, this is
not the only form of this operator.
Combining the regular assignment operator with the
arithmetic operators, you can achieve different results.
-= a -= b a = a - b
*= a *= b a = a * b
/= a /= b a = a / b
%= a %= b a = a % b
package operators;
number1 += number2;
System.out.println(number1); // 15
}
}
The other operators work the same. They operate and
then assign the resultant value to the left operand.
I could demonstrate the other ones using code but I
think if you try them out yourself, you'll get a better
understanding. After all, experimentation and practice
are the only ways to solidify your knowledge.
OPERATO
R EXPLANATION USAGE
5 ==
== Is Equal To 8 returns false
5 !=
!= Is Not Equal To 8 returns true
5 >
> Is Greater Than 8 returns false
5 <
< Is Less Than 8 returns true
}
Practical usage of these operators will become much
apparent to you once you've learned about conditional
statements in a later section.
}
What do you think the output of this code will be? Find
out for yourself. Remember the ASCII values of the
characters? They play a role in the output of this
program.
OPERA EXPLANAT
TOR USAGE ION
Evaluates
to true,
only if
Logical both
age >= 18
And && age <= conditions
(&&) 40 are true
Evalu
ates
to
true if
one
of the
two
or
both
condi
tions
Logical `isSchool isLibraryM are
Or (` `) Student ember` true
Not (!) ! Evaluates
isLibraryMe
mber to false if
OPERA EXPLANAT
TOR USAGE ION
the inner
condition
evaluates
to true
and vise
versa
Let's see these operators in code. First, the
logical and operator:
public class Main {
}
In this case, there are two conditions on either side of
the && operator. If and only if both conditions evaluate
to true, the and operation evaluates to true.
If the first condition evaluates to false, the computer
will not evaluate the rest of the conditions and
return false. Because if the first one evaluates to false,
then there is no way for the entire operation to evaluate
to true.
The logical or operator works similarly, but in this case,
if any of the conditions are true then the entire
operation will evaluate to true:
public class Main {
}
If the first condition of a logical or operation evaluates
to true, the computer will not evaluate the rest of the
conditions and return true. Because if the first condition
evaluates to true the operation will evaluate
to true regardless of what the other conditions evaluate
to.
Finally the not operator evaluates to the opposite of
whatever its condition evaluates to. Take a look at the
following code example:
public class Main {
System.out.println(isLibraryMember); // true
System.out.println(!isLibraryMember); // false
}
}
As you can see, the not operator returns the opposite of
the given boolean value. The not operator is a unary
operator, meaning it operates on a single operand.
public class Main {
}
First, the logical or operation will take place and
evaluate to true. The not operator will turn it into false.
Although you've used two operands with each operator,
you can use as many as you want. You can also mix and
match multiple operators together.
}
What do you think the output of this code will be? I'd
recommend you find out by yourself. :)
OPERATOR EXPLANATION
Increment Increments a given
(++) value by 1
Decrement Decrements a given
(--) value by 1
The following code example will demonstrate them
nicely:
score++;
turns--;
System.out.println(score); // 96
System.out.println(turns); // 10
}
}
You can also use the operators as prefixes:
++score;
--turns;
System.out.println(score); // 96
System.out.println(turns); // 10
}
}
So far this is simple. But there are some slight
differences between the postfix and prefix syntaxes
that you need to understand. Look at the following
code:
package operators;
System.out.println(++score); // 96
System.out.println(score); // 96
}
}
This is expected behavior. The prefix decrement
operator will work the same. But look what happens if
you switch to the postfix version:
package operators;
public class Main {
System.out.println(score++); // 95
System.out.println(score); // 96
}
}
Confusing, isn't it? What do you think is the actual value
of the variable right now? It's 96. Let me explain.
}
As you can see, declaring and using a String this way is
not very different from declaring the primitive types in
Java.
The second way to create a new String is by using
the new operator.
public class Main {
public static void main(String[] args) {
// <type> <name> = new <type>(<value>)
String name = new String("Farhan");
}
This program will work exactly like the previous one but
there's a slight difference between the two.
System.out.println(literalString1 == literalString2);
System.out.println(objectString1 == objectString2);
}
As you may already know, the == operator is used for
checking equality. The output of this program will be:
true
false
Since abc was already in the string pool,
the literalString2 variable reuses that. In case of the
object strings however, both of them are different
entities.
How to Format a String
You've already seen the usage of the + operator to sew
strings together or format them in a specific way.
That approach works until you have a lot of additions to
a string. It's easy to mess up the placements of the
quotation marks.
A better way to format a string is
the String.format() method.
public class Main {
public static void main(String[] args) {
String name = "Farhan";
int age = 27;
System.out.println(formattedString);
}
}
The method takes a string with format specifiers as its
first argument and arguments to replace those
specifiers as the later arguments.
}
The method returns the length as an integer. So you
can freely use it in conjunction with the integer format
specifier.
To check if a string is empty or not, you can use
the isEmpty() method. Like the length() method, it also
comes with every string object.
public class Main {
public static void main(String[] args) {
String name = "Farhan";
if (name.isEmpty()) {
System.out.println("There is no name mentioned here");
} else {
System.out.println(String.format("Okay, I'll take care of %s.", name));
}
}
}
The method returns a boolean value so you can use it
directly in if statements. The program checks if the
name is empty or not and prints out different responses
based off of that.
System.out.println(Arrays.toString(name.split(" ")));
}
}
The method returns an array of strings. Each string in
that array will be a substring from the original string.
Here for example, you're breaking the string Farhan Hasin
Chowdhury at each space. So the output will be [Farhan,
Hasin, Chowdhury].
Just a reminder that arrays are collections of multiple
data of the same type.
You can also join this array back into a string like this:
}
The join() method can also help you in joining multiple
strings together outside of an array.
public class Main {
public static void main(String[] args) {
System.out.println(String.join(" ", "Farhan", "Hasin", "Chowdhury")); //
Farhan Hasin Chowdhury
}
System.out.println(name.equals(nameUpperCase)); // false
System.out.println(name.equalsIgnoreCase(nameUpperCase)); // true
}
}
Here, the loremIpsumStd string contains a portion of the
original lorem ipsum text. Then you're replacing the
first line of that string and saving the new string in
the loremIpsumHalfTranslated variable.
How to Check If a String Contains a Substring or Not
The contains() method can check whether a given string
contains a certain substring or not.
public class Main {
public static void main(String[] args) {
String lyric = "Roses are red, violets are blue";
if (lyric.contains("blue")) {
System.out.println("The lyric has the word blue in it.");
} else {
System.out.println("The lyric doesn't have the word blue in it.");
}
}
}
The method returns a boolean value, so you can use the
function in any conditional statement.
import java.util.Scanner;
scanner.close();
}
The java.util.Scanner class is necessary for taking user
inputs. You can bring the class to your program using
the import keyword.
Then, you'll need to create a new instance of
the Scanner class using the new keyword. While creating
the new instance, you'll have to let it know your desired
input stream.
You may want to take input from the user or from a file.
Whatever it is, you'll have to let the compiler know
about it. The System.in stream is the standard input and
output stream.
The scanner object has methods like nextLine() for
taking string input, nextInt() for taking integer
input, nextDouble() for taking double input and so on.
In the code above, the scanner.nextLine() method will ask
for a string from the user and return the given input
with a newline character appended.
Then the scanner.nextInt() method will ask for an integer
and return the given number from the user.
You may be seeing the System.out.printf() method for
the first time here. Well, apart from
the System.out.println() method, there is also
the System.out.print() method that prints out a given
string without appending a newline character to it.
The System.out.printf() is kind of a combination of
the System.out.print() and String.format() methods. You
can use the previously discussed format specifiers in
this method as well.
Once you're done with taking input, you'll need to close
the scanner object. You can do that by simply calling
the scanner.close() method.
Simple right? Let me complicate it a bit.
import java.util.Scanner;
scanner.close();
}
I've added a new scanner.nextLine() statement after
the scanner.nextInt() method call. Will it work?
No, it won't. The program will simply skip the last input
prompt and print out the last line. This behavior is not
exclusive to just scanner.nextInt(). If you
use scanner.nextLine() after any of the
other nextWhatever() methods, you'll face this issue.
In short, this happens because when you press enter on
the scanner.nextInt() method, it consumes the integer
and leaves the newline character in the input buffer.
So when scanner.nextLine() is invoked, it consumes that
newline character as the end of the input. The easiest
solution to this problem is writing an
additional scanner.nextLine() call after the other scanner
method calls.
import java.util.Scanner;
scanner.close();
}
There is another way of solving this problem. But I won't
get into that here. If you're interested, checkout my
article on this topic.
How to Use Conditional Statements in Java
You use conditional statements for making decision
based on conditions.
// if (condition) {...}
if (age >= 18 && age <= 40) {
System.out.println("you can use the program");
}
}
The statement starts with an if and then there is the
condition inside a pair of parenthesis. If the condition
evaluates to true, the code within the curly braces will
be executed.
Code enclosed between a set of curly braces is known
as a code block.
If you change the value of age to 50 the print statement
will not be executed and there'll be no output on the
console. For these kind of situations where the
condition evaluates to false, you can add an else block:
public class Main {
}
Now if the condition evaluates to false, the code within
the else block will execute and you'll see you can not use
the program printed on your terminal.
You can also have multiple conditions within an if-else
if-else ladder:
public class Main {
// if (condition) {...}
if (age >= 18 && age <= 40) {
System.out.println("you can use the program");
} else if (isSchoolStudent || isLibraryMember) {
System.out.println("you can use the program for a short time");
} else {
System.out.println("you can not use the program");
}
}
Now, if the first condition evaluates to false then the
second condition will be tested. If the second one
evaluates to true then the code within curly braces will
be executed. If the conditions in both if statements
evaluate to false, then the else block will be executed.
You can also nest if statements within
other if statements as follows:
package operators;
if (isSchoolStudent || isLibraryMember) {
System.out.println("you can use the program");
}
} else {
System.out.println("you can not use the program");
}
}
In this case, only if the first if statement evaluates to
true will the inner if statement be tested.
What is a switch-case statement?
Apart from the if-else blocks, there are also switch
cases where you can define multiple cases based on a
single switch.
import java.util.Scanner;
switch (operation) {
case "sum":
System.out.printf("%d + %d = %d", a, b, a+b);
break;
case "sub":
System.out.printf("%d - %d = %d", a, b, a-b);
break;
case "mul":
System.out.printf("%d * %d = %d", a, b, a*b);
break;
case "div":
if (b == 0) {
System.out.print("Can't divide by zero!");
} else {
System.out.printf("%d / %d = %d", a, b, a / b);
}
break;
default:
System.out.printf("Invalid Operation!");
}
scanner.close();
}
This is a very simple calculator program. The program
prompts the user for two numbers and then asks what
operation they would like to perform.
if (isSchoolStudent || isLibraryMember) {
// booleans are accessible here
// age variable is accessible here
}
Here, the age variable is declared within the class code
block. That means you can access this variable within
the entire class without any issue. Since the variable is
accessible in the entire class instance, it's an instance
variable.
However,
the isSchoolStudent and isLibraryMember variables have
been declared within the first if statement code block.
So it'll not be accessible outside of that code block.
But, it'll be accessible within any nested code block
inside the first if block. These are called local variables.
There are also class variables declared using
the static keyword but you'll learn about them in the
object-oriented programming sections.
So for now, the rule of thumb is, a variable will be
accessible within the code block it was declared at and
any other code block nested inside the parent block.
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
boolean false
}
}
You start by typing out the type of data you want to
hold in the array, char in this case. Then you write out
the name of the array, vowels followed by a pair of
square braces here. This pair of braces tells Java that
you're declaring an array of characters and not a
regular character variable.
Then you put an equal sign followed by the new operator
used for creating new objects in Java. Since arrays are
reference types in Java, new is required to create new
instances.
You finish off the declaration by writing out the type
again, followed by another pair of square braces
enclosing the length of the array. Here, 5 means the
array will hold five elements and not more than that.
When working with a single variable, you can refer to
the variable simply by its name. But in case of an array,
each element will have an index and arrays are zero-
based. This means the first element in an array will
have 0 as its index and not 1.
To access an element in an array, you start by writing
out the name of the array – in this case vowels followed
by a pair of square braces enclosing your desired index.
So if you want to access the first element in the array,
you can do so as follows:
public class Main {
vowels[0] = 'a';
}
}
At this point, vowels[0] is similar to a regular character
variable. You can print it out, assign new value to it,
perform calculations in case of number types, and so
on.
Since the array is empty at this moment, I'm assigning
the character a to the first index. You can assign the
rest of the vowels to the rest of the indices as follows:
public class Main {
vowels[0] = 'a';
vowels[1] = 'e';
vowels[2] = 'i';
vowels[3] = 'o';
vowels[4] = 'u';
}
}
Since the indices start at 0 they'll end at the length of
the array - 1, which in this case is 4. If you try to assign
another element to the array like vowels[4] = 'x'; the
compiler will throw the following error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5
out of bounds for length 5
at arrays.Main.main(Main.java:18)
Arrays can not be printed like regular variables. You'll
have to use a loop or you'll have to convert the array
into a string. Since, I haven't discussed loops yet, I'll use
the second method.
import java.util.Arrays;
vowels[0] = 'a';
vowels[1] = 'e';
vowels[2] = 'i';
vowels[3] = 'o';
vowels[4] = 'u';
}
}
You'll need to first import the java.util.Arrays; and use
the Arrays.toString() method to convert the array to a
string. This class has a bunch of other interesting
methods, but before discussing them, I'd like to show
you how you can declare and initialize an array in one
go.
import java.util.Arrays;
}
}
The left side of the declaration syntax remains
unchanged. However, after the assignment operator,
instead of using new you write out the individual array
elements separated by comma and enclosed within a
pair of curly braces.
In this case the compiler will count the number of
elements in the array and use that as the length of the
array.
import java.util.Arrays;
System.out.println(Arrays.deepToString(medicineRoutine)); // [[1, 2, 3, 4, 5, 6,
7], [0, 1, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 0], [0, 0, 1, 1, 0, 1, 0]]
}
}
Multidimensional arrays can not be printed out using
the regular Arrays.toString() method, you have to dig
deeper.
Although the output doesn't look anything like the
table, you can make it look like a table using some
clever programming:
import java.util.Arrays;
// [[1, 2, 3, 4, 5, 6, 7]
// [0, 1, 1, 0, 1, 1, 0]
// [1, 0, 1, 0, 1, 0, 0]
// [0, 0, 1, 1, 0, 1, 0]]
You've already learned about the replace() method for
strings. You're just replacing the ending square brace in
each line with a square brace and a newline character.
The first row represents the 7 weekdays and the rest of
the rows are medicine routines for each day. Each line
in this table represents an array.
Arrays.sort(vowels);
System.out.println("The sorted array: " + Arrays.toString(vowels)); // [a, e, i,
o , u]
}
}
The Arrays.sort() method takes the unsorted array as its
argument and sorts it in place. So instead of getting a
new sorted array in return, your original array itself will
be sorted in ascending order.
By default, the method treats the first index of the array
as its starting index and the length of the array as its
ending index.
int startIndex = 1;
int endIndex = 4;
}
}
This time, the method takes the array as the first
parameter, the starting index as the second parameter,
and the ending index as the third parameter. The rest
of the behaviors stay the same as before.
}
}
The Arrays.binarySearch() method takes an array as its
first parameter and the the search key (aka the item
you're looking for) as its second parameter. It'll return
the index of the found item as an integer.
You can store that index in an int and use that to
access the element from the array
as vowels[foundItemIndex].
Note that the array has to be sorted in ascending order.
If you're unsure of the array's ordering, use
the Arrays.sort() method to sort it first.
By default, the method treats the first index of the array
as its starting index and the length of the array as its
ending index. But you can also specify those indices
manually.
}
}
This time the method takes the array you want to
search on as the first parameter, the starting index as
the second parameter, the ending index as the third
parameter, and the search key as the fourth parameter.
Arrays.fill(vowels, 'x');
}
}
Like the Arrays.sort() method, Arrays.fill() also
performs its operation in place. It takes your array as
the first parameter, the value you want to fill the array
with as the second parameter, and updates the original
array in place.
This method also treats the first index as the starting
index and the length of the array as the ending index.
You can specify these indices manually as follows:
import java.util.Arrays;
}
}
This time the method takes your array as the first
argument, the starting index as the second argument,
the ending index as the third argument, and the filler as
the fourth argument.
import java.util.Arrays;
Arrays.fill(oddNumbers, 0);
}
}
Although you've made changes to the source array, the
copy reflects them as well. This happens because when
you use the assignment operator to copy an array, the
copy references the original array in the memory.
Arrays.fill(oddNumbers, 0);
}
}
The method takes the source array as its first argument
and the desired length of the new array as the second
argument. If you want the length to be the same,
simply pass the length of the original array using
the length property.
If you put a smaller length, any value after that will be
cut off and if you put a larger length, the new indices
will be filled with the default value of the array data
type.
int startIndex = 2;
int endIndex = 7;
}
}
This method takes the source array as its first
argument, then the start index and finally the end
index.
import java.util.Arrays;
int startIndex = 2;
int endIndex = oddNumbers.length;
}
}
Now the new array will also include 15 in it. You can
also put a higher number than the length of the source
array. In that case the newly added indices will contain
the default value of the array data type.
int medicineRoutine2[][] = {
{1, 2, 3, 4, 5, 6, 7},
{0, 1, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 0},
{0, 0, 1, 1, 0, 1, 0},
};
System.out.println(Arrays.deepEquals(medicineRoutine, medicineRoutine2));
// true
}
}
This method calls itself each time it encounters a new
array inside the parent array.
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
The flowchart for this loop looks like this:
1. In the beginning of the loop, you initialize a new integer
named number with the initial value of 0.
2. Then you check whether the number is less than or equal
to 10 or not.
3. If its less than or equal to 10, you execute the statement
inside the loop block and print out the number on the
terminal.
4. Then you update the number variable by incrementing
its value by 1.
5. The loop goes back to checking whether the value of
number is still less than or equal or not.
As long as the value of number remains less than or
equal to 10, the loop goes on. The moment the value of
the number variable becomes 11, the loop ends.
You can use a for loop to loop over an array as follows:
// 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
Loops can also be nested. Which means you can put
one loop inside another. You can print out the
multiplication table of all the numbers from 1 to 10
using nested loops:
For-Each Loop
If you want to iterate over a collection like an array and
perform some operation on each element of that
collection, you can use a for...each loop.
While Loop
If you want to execute a bunch of code until a certain
condition is met, you can use a while loop.
// 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
Although, while loops are not as common as for loops in
the real world, learning about them is worth it.
Do-While Loop
The final type of loop you'll learn about is the do-while
loop. It kind of reverses the order of the regular while
loop – so instead of checking the condition before
executing the loop body, you execute the loop body
first and then check the condition.
The multiplication table code implemented using a do-
while loop will be as follows:
do {
System.out.println(String.format("%d x %d = %d", number, multiplier,
number*multiplier));
multiplier++;
} while (multiplier <= 10);
}
}
// 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
Do-while loops are very useful when you need to
perform some operation until the user gives a specific
input. Such as, show a menu until user presses the "x"
key.
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.toString()); // [1, 3, 5, 7, 9]
}
}
To create array lists, you'll need to import
the java.util.ArrayList class at the top of your source
file.
Then you start by writing ArrayList and then inside a
pair of less than-greater than signs, you'll write the data
type for the elements. Then you'll add the name of the
array list itself followed by the assignment operator
and new ArrayList<>().
You can not create array lists of primitive types, so
you'll have to use the corresponding wrapper class.
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.get(2)); // 5
}
}
The get() method will get the value in the given index.
Just like get() you can use the set() method to update
the value of an element.
import java.time.LocalDate;
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
oddNumbers.set(2, 55);
System.out.println(oddNumbers.get(2)); // 55
}
}
The first parameter to the set() method is the index and
the second one is the updated value.
There is no length property like in an array but you can
use the size() method on any array list to find out its
length.
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.size()); // 5
}
}
You can remove elements from an array list using the
remove method:
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
oddNumbers.remove(Integer.valueOf(7));
oddNumbers.remove(Integer.valueOf(9));
System.out.println(oddNumbers.toString()); // [1, 3, 5]
}
}
The remove() method can remove an element by value or
by index. If you pass a primitive integer value to the
method, it'll remove the element in the given index.
But if you pass an object like in this code, the method
will find and delete that given element.
The valueOf() method is present in all wrapper classes
and it can convert a primitive value to a reference type.
How to Add or Remove Multiple Elements
You've already seen examples of
the add() and remove() methods. There are two other
methods addAll() and removeAll() for working with
multiple elements.
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
moreOddNumbers.add(7);
moreOddNumbers.add(9);
moreOddNumbers.add(11);
System.out.println(oddNumbers.toString());
oddNumbers.removeAll(moreOddNumbers);
System.out.println(oddNumbers.toString()); // [1, 3, 5]
}
}
Both methods accept collections as their parameter. In
the code above, you're creating two separate array lists
and joining them using the addAll() method.
Then you remove the elements from the second array
list using the removeAll() method and the array list goes
back to its original state.
You can also drop all elements from an array list using
the clear() method:
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.clear();
System.out.println(oddNumbers.toString()); // []
}
}
The method doesn't require any parameter at all and
also doesn't return any value. It just empties your array
list in a single call.
Here, the removeIf() method will loop over the array list
and pass each element to the lambda expression as the
value of the number variable.
Then the lambda expression will check whether the
given number is divisible by 2 or not and
return true or false based on that.
If the lambda expression returns true,
the removeIf() method will keep the value. Otherwise the
value will be deleted.
How to Clone and Compare Array Lists
To make a duplicate of an array list, you can use
the clone() method.
import java.util.ArrayList;
System.out.println(numbersCloned.equals(numbers)); // true
}
}
The clone() method returns an object, so you'll have to
cast it to a proper array list manually. You can compare
two array lists using the equals() method just like in
arrays.
How to Check if an Element Is Present or the Array List Is
Empty
You can use the contains() method to check if an array
list contains a given element or not:
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.isEmpty()); // false
System.out.println(oddNumbers.contains(5)); // true
}
}
If you want to check if an array list is empty or not, just
call the isEmpty() method on it and you'll get a boolean
in return.
How to Sort an Array List
You can sort an array list in different orders using
the sort() method:
import java.util.ArrayList;
import java.util.Comparator;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(1);
oddNumbers.add(9);
oddNumbers.add(3);
System.out.println(oddNumbers.toString()); [5, 7, 1, 9, 3]
oddNumbers.sort(Comparator.naturalOrder());
System.out.println(oddNumbers.toString()); [1, 3, 5, 7, 9]
}
}
The sort() method takes a comparator as its parameter.
A comparator imposes the order of sorting on the array
list.
You can sort the array list in reverse order just by
changing the passed comparator:
import java.util.ArrayList;
import java.util.Comparator;
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(1);
oddNumbers.add(9);
oddNumbers.add(3);
System.out.println(oddNumbers.toString()); // [5, 7, 1, 9, 3]
oddNumbers.sort(Comparator.reverseOrder());
System.out.println(oddNumbers.toString()); // [9, 7, 5, 3, 1]
}
}
Comparators have other usages as well but those are
out of the scope of this book.
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
moreOddNumbers.add(5);
moreOddNumbers.add(7);
moreOddNumbers.add(9);
oddNumbers.retainAll(moreOddNumbers);
System.out.println(oddNumbers.toString()); // [5]
}
}
The retainAll() method can get rid of the uncommon
elements from the first array list for you. You'll need to
call the method on the array list you want to operate on
and pass the second array list as a parameter.
How to Perform an Action on All Elements of an Array List
You've already learned about looping in previous
sections. Well, array lists have a forEach() method of
their own that takes a lambda expression as parameter
and can perform an action on all the elements of the
array list.
import java.util.ArrayList;
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
oddNumbers.forEach(number -> {
number = number * 2;
System.out.printf("%d ", number); // 2 6 10 14 18
});
System.out.println(oddNumbers.toString()); // [1, 3, 5, 7, 9]
}
}
Last time, the lambda expression you saw was a single
line – but they can be bigger. Here,
the forEach() method will loop over the array list and
pass each element to the lambda expression as the
value of the number variable.
The lambda expression will then multiply the supplied
value by 2 and print it out on the terminal. However,
the original array list will be unchanged.
import java.util.HashMap;
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.putIfAbsent("guava", 2.9);
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.get("banana")); // 1.000000
}
}
There is another variation of the this method.
The getOrDefault() method works like get() but if the
given key is not found, it'll return a specified default
value.
import java.util.HashMap;
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.replace("berry", 2.8);
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.remove("guava");
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.size()); // 5
}
}
Finally if you want to clear a hash map in Java, you can
do so by using the clear() method.
import java.util.HashMap;
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.clear();
System.out.println(prices.toString()); // {}
}
}
Just like in the array lists, the method doesn't take any
argument or return any value.
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.put("jackfruit", 2.9);
prices.put("pineapple", 1.1);
prices.put("tomato", 0.8);
prices.putAll(morePrices);
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.containsKey("banana")); // true
System.out.println(prices.containsValue(2.5)); // true
}
}
Difference between the two methods is that
the containsKey() method checks if the given key exists
or not and the containsValue() method checks if the
given value exists or not.
And if you want to check if a hash map is empty or not,
you can do so by using the isEmpty() method:
import java.util.HashMap;
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.isEmpty()); // false
}
}
Since the method returns a boolean value, you can use
it within if-else statements.
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
user.name = "Farhan";
user.birthDay = LocalDate.parse("1996-07-15");
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
}
Here, the this keyword represents the current instance
of the class. You start by writing out the return type of
the method. Since the age of a user is an integer, the
return type of this method will be int.
After the return type, you write the name of the
method, followed by a pair of parenthesis.
Then you write the method body within a pair of curly
braces. The Period class in Java expresses a time frame
in the ISO-8601 calendar system.
The LocalDate.now() method returns the current date.
So the Period.between(this.birthDay,
LocalDate.now()).getYears() method call will return the
difference between the current date and the date of
birth in years.
Now back in the Main.java file, you can call this method
as follows:
import java.time.LocalDate;
user.name = "Farhan";
user.birthDay = LocalDate.parse( "1996-07-15");
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
user.name = "Farhan";
user.borrow("Carmilla");
user.borrow("Hard West");
import java.util.ArrayList;
}
}
Now let's go back to the User.java file and create a
relationship between the users and the books:
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
this.borrowedBooks.add(book);
}
}
Instead of using an array list of strings, you're now
using an array list of books to store the books borrowed
by this user.
user.borrow(book);
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
user.borrow(book3);
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
import java.util.ArrayList;
import java.util.Arrays;
user.borrow(book);
System.out.printf("%s has borrowed these books: %s", user.name,
user.borrowedBooks.toString()); // Farhan has borrowed these books: [Carmilla, Hard
West]
}
}
Look how much cleaner it already looks. But soon it'll
look better.
Primitive
Type Wrapper Class
Default Accessible within the package
Public Accessible everywhere
Private Accessible within the class
Accessible within the class and
Protected subclasses
For now, I'll discuss the Default, Public and Private access
modifiers. Protected will be discussed in a later section.
You've already learned about classes. Packages are
collections of multiple classes separated by their
functionality.
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
user.borrow(book);
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
this.runTime = runTime;
}
}
The extends keyword lets the compiler know that this
class is a subclass of the Book class. This means that this
class inherits all the properties and methods from the
parent class.
Inside the AudioBook constructor method, you set the run
time for the audio book which is fine – but you'll also
have to manually call the constructor of the parent
class.
The super keyword in Java refers to the parent class,
so super(title, 0, authors) essentially calls the parent
constructor method with the necessary parameters.
Since the audio books don't have any pages, setting the
page count to zero can be an easy solution.
this.runTime = runTime;
}
@Override
public String length() {
return String.format("%s is %d minutes long.", this.title, this.runTime);
}
}
You override a method from the parent class by
rewriting the method in the subclass.
The @Override keyword is an annotation. Annotations in
Java are metadata.
It's not mandatory to annotate the method like this. But
if you do, the compiler will know that the annotated
method overrides a parent method and will make sure
you're following all the rules of overriding.
Conclusion
I would like to thank you from the bottom of my heart
for the time you've spent on reading this book. I hope
you've enjoyed your time and have learned all the
fundamental concepts of Java.
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT