Welcome to our free Java tutorial. This tutorial is based on Webucator's Introduction to Java Training course.
In this lesson, you will learn about basic syntax, data types, and various writing methods.
Lesson Goals
String
class.Java is case-sensitive. main()
, Main()
, and MAIN()
would all be different methods (the term we use for functions in Java).
There are a limited number of reserved words that have a special meaning within Java. You may not use these words for your own variables or methods.
Some examples of reserved words are:
public
void
static
do
for
while
if
Most keyboard symbol characters (the set of characters other than alphabetic or numeric) have a special meaning.
Identfiers - names we use for methods, variables, or classes - may contain alphabetic characters, numeric characters, currency characters, and connecting characters such as the underscore ( _
) character:
Character.isJavaIdentifierPart(char ch)
, results in a true
value.The compiler parses your code by separating it into individual entities called tokens or symbols in computer science jargon:
Tokens may be separated by spaces, tabs, carriage returns, or by use of an operator (such as +
, -
, etc.).
Since identfiers may not contain spaces, tabs, or carriage returns, or operator characters, these characters imply a separation of what came before them from what comes after them.
Extra whitespace is ignored. Once the compiler knows that two items are separate, it ignores any additional separating whitespace characters (spaces, tabs, or carriage returns).
;
character).A block of code:
{
and end with }
.A complete method is a single block of code, most likely with nested blocks.
The diagram below illustrates how blocks of code can be nested:
If you want, go ahead and modify your Hello World
program to match this example.
A comment:
Block comments are preceded by /*
and followed by */.
Some rules for block comments:
/* this is a block comment * asterisk on this line not necessary, but looks nice */
x = 3 /* + y */ ;
A single line can be a comment by preceding the comment with two forward slashes: //
. Note that:
y = 7; /* * temporarily disable this line * which has a comment to end of line x = 3 + y; // add 3 for some reason */
Java specifies a third type of comment, the javadoc comment:
/**
and end with */
./** * Represents a person, with a first name and last name. */ public class Person { /** The person's first name */ public String firstName; /** The person's last name */ public String lastName; }
Variables store data that your code can use.
There are two fundamental categories of variables, primitive data and references:
In the diagram below, the boxes are areas in memory:
Variables must be declared before they are used.
A declaration informs the compiler that you wish to:
Java uses many specific data types; each has different properties in terms of size required and handling by the compiler:
Code | Effect |
---|---|
int a;
|
declares the name |
int a = 0;
|
same as above, and also assigns an initial value of 0 |
int a = 0, b, c = 3;
|
declares three integer variables and initializes two of them |
Note that different languages have different rules regarding variables that have not been initialized:
Local variables, fields, methods, and classes may be given additional modifiers; keywords that determine special characteristics.
Any modifiers must appear first in any declaration, but multiple modifiers may appear in any order.
Keyword | Usage | Comments |
---|---|---|
final
|
local variables, fields, methods, classes |
The name refers to a fixed item that cannot be changed. For a variable, that means that the value cannot be changed. For a method, the method cannot be overridden when extending the class. A |
static
|
fields, methods, inner classes |
Only for fields and methods of objects. One copy of the element exists regardless of how many instances are created. The element is created when the class is loaded. |
transient
|
fields |
The value of this element will not be saved with this object when serialization is used (for example, to save a binary object to a file, or send one across a network connection). |
volatile
|
fields |
The value of this element may change due to outside influences (other threads), so the compiler should not perform any caching optimizations. |
public, protected, private
|
fields, methods classes |
Specifies the level of access from other classes to this element - covered in depth later. |
abstract
|
methods, classes |
Specifies that a method is required for a concrete extension of this class, but that the method will not be created at this level of inheritance - the class must be extended to realize the method. For a class, specifies that the class itself may not be instantiated; only an extending class that is not |
native
|
methods |
The method is realized in native code (as opposed to Java code) - there is an external tool in the JDK for mapping functions from a DLL to these methods. |
strictfp
|
methods, classes |
For a method, it should perform all calculations in strict floating point (some processors have the ability to perform floating point more accurately by storing intermediate results in a larger number of bits than the final result will have; while more accurate, this means that the results might differ across platforms). For a class, this means that all methods are |
synchronized
|
methods, code blocks |
No |
Primitive Type | Storage Size | Comments |
---|---|---|
boolean
|
1 bit
|
not usable mathematically, but can be used with logical and bitwise operators |
char
|
16 bits
|
unsigned, not usable for math without converting to int
|
byte
|
8 bits
|
signed |
short
|
16 bits
|
signed |
int
|
32 bits
|
signed |
long
|
64 bits
|
signed |
float
|
32 bits
|
signed |
double
|
64 bits
|
signed |
void
|
None
|
not really a primitive, but worth including here |
Objects can be data, which can be stored in variables, passed to methods, or returned from methods.
As we will see later, objects are stored differently than primitives. An object variable stores a reference to the object (the object is located at some other memory location, and the reference is something like a memory address).
A sequence of text, such as a name, an error message, etc., is known as a string.
In Java, the String
class is used to hold a sequence of text characters.
A String
object:
String
object at any time).A value typed into your code is called a literal value.
The compiler makes certain assumptions about literals:
true
and false
are literal boolean
values.null
is a literal reference to nothing (for objects).int
, unless it is immediately assigned into a variable of a smaller type and falls within the valid range for that type.double
.Code | Effect |
---|---|
char e = 'X';
|
Creates a 16-bit variable to hold the Unicode value for the uppercase X character. |
You can add modifiers to values to instruct the compiler what type of value to create (note that all the modifiers described below can use either uppercase or lowercase letters).
Modifying prefixes enable you to use a different number base:
Prefix | Effect |
---|---|
0X or 0x
|
A base 16 value; the extra digits can be either uppercase or lowercase, as in char c = 0x1b;
|
0
|
A base 8 value, as in int i = 0765;
|
0x7F
for a byte
would be OK, but 0x80
would not, since the latter would have a value of 128, outside the range of byte
).long
value would need the L
modifier as discussed below.Modifying suffixes create a value of a different type than the default:
Suffix | Effect |
---|---|
L or l
|
a long value (uses 64 bits of storage), as in long l = 1234567890123456L;
|
Note: An int value will always implicitly be promoted to a long when required, but the reverse is not true; the above notation is necessary because the literal value is larger than 32 bits |
|
F or f
|
A float value, as in float f = 3.7F;
|
There are a number of escape sequences that are used for special characters:
thEscape Sequence | Resulting Character |
---|---|
\b
|
Backspace |
\f
|
Form feed |
\n
|
Linefeed character - note that it produces exactly one character, Unicode 10 (\u000A in hex) |
\r
|
Carriage return |
\t
|
Tab |
\"
|
Quote mark |
\'
|
Apostrophe |
\\
|
Backslash |
\uNNNN
|
Unicode value, where N is a base 16 digit from 0 through F; valid values are \u0000 through \uFFFF |
\NNN
|
Value expressed in octal; ranging from \000 to \377 |
The escape sequences can either be used for single characters or within strings of text:
char c = '\u1234'; System.out.println("\t\tHello\n\t\tWorld");
final
KeywordJava has a means for defining constants, which are like variables in that they have names, but are not changeable once set.
If a variable is declared as final
, it cannot be changed:
final
.final
.Fields of a class may be declared as public static final
- that way they are available to other classes, but cannot be changed by those other classes. An example is Math.PI
.
Classes and methods may also be marked as final
. We will cover this later.
The class has two final fields, scale
and answer
. The scale
is fixed at 100, while the answer
is initialized dynamically, but, once established, the value cannot be changed. Try removing the comment from the line that attempts to set it to 44, and you will see the compiler error message that results.
Looks and behaves like algebra, using variable names and math symbols:
int a, b, c, temp; a = b/c + temp; b = c * (a - b);
=
sign is called an lvalue. Only things that can accept a value can be an lvalue
(usually this means a variable name - you can't have a calculation like a + b
in front of the equal sign).Operator | Purpose (Operation Performed) |
---|---|
+
|
for addition |
-
|
for subtraction |
*
|
for multiplication |
/
|
for division |
%
|
for modulus (remainder after division) |
(
and
)
|
for enclosing a calculation |
An expression is anything that can be evaluated to produce a value. Every expression yields a value.
Two simple expressions:
a + 5 5/c
An expression that contains another expression inside, the (5/c)
part:
b + (5/c)
A statement is an expression; this one that contains another expression inside - the b + (5/c)
part, which itself contains an expression inside it (the 5/c
part):
a = b + (5/c);
Since an assignment statement (using the =
sign) is an expression, it also yields a value (the value stored is considered the result of the expression), which allows things like this:
d = a = b + (5/c);
a
is the value of the expression b + (5/c)
.d
.b
.5
stored somewhere in memory by the compiler.c
.5 / c
b
to the result of the above step.a
.d
.Here is a moderately complicated expression; let's say that a
, b
, and c
are all double
variables, and that a
is 5.0
, b
is 10.0
, and c
is 20.0
:
d = a + b * Math.sqrt(c + 5);
c + 5
is in parentheses, the compiler creates code to evaluate that first, but to perform the c + 5
operation, both elements must be the same type of data, so the thing the compiler creates is a conversion for the 5
to 5.0
as a double
.
d = a + b * Math.sqrt(c + 5.0);
20.0 + 5.0
(at runtime it would become 25.0
), reducing the expression to: d = a + b * Math.sqrt(25.0);
Math.sqrt
method to evaluate its result, which will be 5.0
, so the expression reduces to:d = a + b * 5.0;
d = a + 50.0;
d = 55.0;
55.0
is stored in d
.As implied by the examples we have seen so far, the order of evaluation of a complex expression is not necessarily from left to right. There is a concept called operator precedence that defines the order of operations.
Operator precedence specifies the order of evaluation of an expression.
Every language has a "table of operator precedence" that is fairly long and complex, but most languages follow the same general rules:
a = b + 5/c
, the 5/c
gets calculated
first, then the result is added to b
, then the overall result
is stored in a
.=
) is an operator; where on the table do you think it is located?The basic rule programmers follow is: when in doubt about the order of precedence, use parentheses.
Try the following program:
Every expression has a value. For an assignment expression, the value assigned is the expression's overall value. This enables chaining of assignments:
x = y = z + 1;
is the same as y = z + 1; x = y;
i = (j = k + 1)/2;
is the same as j = k + 1; i = j/2;
Quite often, you may need to calculate a value involved in a test, but also store the value for later use:
double x; if ( (x = Math.random()) < 0.5 ) { System.out.println(x); }
You might wonder why not just generate the random number when we declare x? In this case, that would make sense, but in a loop the approach shown above might be easier such that:
x
.0.5
, and the loop body executes if that is true.It is usually not necessary to code this way, but you will see it often.
The order of operand evaluation is always left to right, regardless of the precedence of the operators involved.
The operands are first evaluated in left to right order, so that the functions are called in the order getA()
, then getB()
, and, lastly, getC()
But, the returned values are combined together by multiplying the results of getB()
and getC()
, and then adding the result from getA()
Java has a number of operators for working with the individual bits within a value.
Operator | Description | |||
---|---|---|---|---|
Example | Effect | Bit Pattern | ||
& | Bitwise AND, combines individual bits with an AND operation, so that in the resulting value, a bit position is only 1 if that position had a 1 for both operands. | |||
int a = 4; |
has the 4 bit set | 0...00000100 | ||
int a = 2; |
has the 2 bit set | 0...00000010 |
||
int b = 6; |
has the 2 and 4 bits set | 0...00000110 |
||
int c = a & b; |
results in 2 | 0...00000010 |
||
|
| Bitwise OR, combines individual bits with an OR operation, so that in the resulting value, a bit position is 1 if that position had a 1 for either operand. | |||
int a = 2;
|
has the 2 bit set |
0...00000010
|
||
int b = 4;
|
has the 4 bit set |
0...00000100
|
||
int c = a | b;
|
results in 6 |
0...00000110
|
||
^
|
Bitwise exclusive OR (XOR), combines individual bits so that any position that is the same in both operands yields a 0, any bits that differ yield a 1 in that position; this is often used in encryption, since repeating the operation on the result yields the original value again | |||
int a = 3;
|
has the 1 and 2 bits set |
0...00000011
|
||
int b = 6;
|
has the 2 and 4 bits set |
0...00000110
|
||
int c = a ^ b;
|
results in 5 |
0...00000101
|
||
int d = c ^ b;
|
results in 3 again |
0...00000011
|
||
~
|
Bitwise complement. Reverses the state of all bits. | |||
int a = 0;
|
has no bits set |
0...00000000
|
||
int b = ~a;
|
has all bits set |
1...11111111
|
These operators shift the bits left or right within a 32-bit int
value (they do not work with any other type).
Operator | Description | ||
---|---|---|---|
Example | Effect | Bit Pattern | |
<<
|
left shift the bits by the second operand | ||
int a = 4;
|
has the 4 bit set |
0...00000100
|
|
int b = a << 2;
|
now has the 16 bit set |
0...00001000
|
|
>>
|
right shift the bits by the second operand with sign-extension (if the first bit is a 1, new bits introduced to fill in on the left come in as 1 bits) | ||
int a = -126;
|
has all bits except the rightmost set to 1 |
10...0000010
|
|
int b = a >> 1;
|
now has all bits set to 1 (the 0 rolled off the right end, and a 1 was added on the left to match the original leftmost bit; the resulting value is 63) |
110...000001
|
|
>>>
|
right shift the bits by the second operand without sign-extension (bits added on the left always come in as 0) | ||
int a = -1;
|
has all bits set to 1 |
11...1111111
|
|
int b = a >>> 31;
|
now has all bits set to 0 except the rightmost (all bits except the first rolled off the right end, and 0's were added on the left |
0000000...01
|
You can try out the bitwise operators and bitwise shift operators with the file Java-Basics/Demos/Bitwise.java.
Combine multiple effects in one operation: calculation and storage into memory
Operator | Purpose (Operation Performed) |
---|---|
++
|
increment a variable |
--
|
decrement a variable; note that ++ and -- can precede or follow a variable |
if preceding (called prefix), apply the operator and then use the resulting value | |
if following (called postfix), retrieve the value of the variable first, use it as the result of the expression, and then apply the operator | |
+=
|
add an amount to a variable |
-=
|
subtract an amount from a variable |
*=
|
multiply a variable by an amount |
/=
|
divide a variable by an amount |
%=
|
set variable equal to remainder after division by an amount |
&=
|
perform bitwise AND between left and right, store result into left operand |
|=
|
perform bitwise OR between left and right, store result into left operand |
^=
|
perform bitwise XOR between left and right, store result into left operand |
>>=
|
shift the variable's bits to the right by an amount with sign-extension |
>>>=
|
shift the variable's bits to the right by an amount without sign-extension |
<<=
|
shift the variable's bits to the left by an amount |
Statement | Result |
---|---|
i++;
|
increment i
|
i--;
|
decrement i
|
j = i++;
|
retrieve current value of i, hold it as the result of the expression, assign its value to j , then increment i
|
j = ++i;
|
increment i , then j = i;
|
x *= 3;
|
x = x * 3;
|
y -= z + 5;
|
y = y - (z + 5);
|
It is inevitable that a certification exam will ask a question that requires understanding the steps involved in a postfix increment or decrement: try the following program:
i = i++;
, the original value of i
(0) is retrieved and held. Then, i
is incremented. But, after that, the held value of 0 is put back into i
, overwriting the 1!j = i++ + i;
, the operands are evaluated from left to right, but each operand is fully evaluated before proceeding to the next. Which means that the increment part of i++
has taken effect before the second appearance of i
in the equation, so that the expression reduces to 0 + 1 (recall that the previous operation resulted in i
being 0).Expressions will often mix different types of data, for example:
double x = 15.6 / 4; double y = 12.2 + 15 / 4;
The compiler must choose a specific type of data (either integer or floating-point, and the specific size) for each individual expression it evaluates within a statement.
double
, which will then be used in the division.double
to finish the statement.The process of changing the data type of a value is known a typecasting (or casting):
double
to int
) - this must be coded with an explicit cast.int a = (int) (15.6 / 4);
double
, and the result of the division is a double
, but a double
can't be stored in a,
so the cast to int
is necessary.The allowable sequence of implicit casts is shown below:
One aspect of Java that is important to understand is the result of expressions involving the small integral types: byte
, char
, and short
any expression involving these types, other than the compound assignment expressions, is done with int
values, so that the result will always be an int
.
Try the following (it is the same as the earlier postfix increment example, using byte
instead of int
):
byte i = 0, j = 6, k; i++; k = i + j; System.out.println("i = " + i + ", j = " + j);
Note that the increment expression is accepted by the compiler; it is the simple addition in the third line that causes an error.
The Java Language Specification states the promotion rules as follows (note that this concept does not apply to all operators; again, the operators that include assignment do not use it):
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value of a numeric type, the following rules apply, in order, using widening conversions to convert operands as necessary:
double
, the other is converted to double
. float
, the other is converted to float
. long
, the other is converted to long
. int
. The method is the basic complete unit of code to perform one task within an object:
Using a method in your code, causing it to run, is known as calling the method.
A method call is an expression, so it may result in a value (the method call is evaluated like any other expression).
z = Math.sin(Math.PI / Math.sqrt(x));
Methods must be called with arguments that match their specified form, known as the function signature:
All methods in Java must be defined within a class definition. They have complete access to all other elements of the class (fields and other methods, regardless of the access modifier used for that element).
This class calls two methods from the Math
class: sqrt
and sin
, both of which expect one parameter which is a double
.
When we call sqrt
and pass an integer, the compiler converts that to a double
to provide the type of data that sqrt
expects
Note that even if your program does not call any methods, it has one method that will be called: main()
. Things to note:
main()
is that it provides a start point and end point for your program.main()
.main()
is executed, the program ends.main()
does have arguments (any other words typed on the command line).There are three things you need to decide for any method:
[modifiers] dataType methodName(parameterList) { methodBody return result; }
fixed-font
words are keywords, and brackets []
indicate optional elements:modifiers
include the accessibility of this method from outside the class (public
, private
, protected
, or left blank) as well as other possibilities listed earlier in this section.dataType
is a type of data, like int
.methodName
is the name of your method.parameterList
is a comma-separated list of parameters; each parameter is listed with its data type first, then its name.methodBody
is the set of statements that perform the task of the method.return
is a keyword that says to use the result
expression value as the result of calling the method, and send that value back to the code that called the method (as an expression, a call to a method evaluates to the returned value; i.e., calling Math.sqrt(4)
evaluates to the value that sqrt
returned).public void sayHello() { System.out.println("Hello"); }
public
methods are accessible to any other class.void
is a keyword for a returned data type that means no data at all - this method does not calculate a result.sayHello
.Code | When Used |
---|---|
sayHello();
|
from within the class |
x.sayHello();
|
from outside the class, for an instance x of this class |
public void showNumber(int number) { System.out.println("The number is: " + number); }
Code | When Used |
---|---|
showNumber(5);
|
from within the class |
x.showNumber(5);
|
from outside the class, for an instance x of this class |
public int calculateSum(int num1, int num2) { int answer = num1 + num2; return answer; }
int
.int
data types.Code | When Used |
---|---|
int value = calculateSum(4, 6);
|
from within the class |
int value =
x.calculateSum(4, 6);
|
from outside the class, for an instance x of this class |
Note that the listing of a data type word in front of a name is something we have seen before, in declaring variables. The purpose is the same - to state what type of data this element provides when used in an expression.
The first statement below states that the value of a
is an int
, so that the compiler knows what memory size to allocate and what type of processing to use with it when it evaluates the second statement.
int a; int b = a / 2;
The effect is no different using a method; recall the function signature (the first line) of our calculateSum
method:
public int calculateSum(int num1, int num2)
It states that the result of evaluating calculateSum
is an int
, so that the compiler knows what memory size to allocate for the result, and what type of processing to use with it when it evaluates a statement like:
int b = calculateSum(4, 6) / 2;
When this statement gets processed, the calculateSum
method will run and return its result (which will be the value 10 as an int
).
Thus the statement in effect is reduced to:
int b = 10 / 2;
Method parameters are also declarations. They declare a type of data received by the method, and also provide a name for each value so it can be used within the method.
Back to our method:
public int calculateSum(int num1, int num2) { int answer = num1 + num2; return answer; }
num1
and num2
.num1
will be the first value given to the method, num2
will be the second.The variable scope rules are similar to those in C++.
Variables can be declared at any point in your code, not just at the top of a block:
Variables declared within a set of curly braces cease to exist after the closing brace has been reached (it is said that they go out of scope); therefore, local variables exist only within that method.
Variables can be declared in the control portion of a for
loop, and will exist for the duration of the loop
Parameters to a method are local variables within that method
It is legal to use the same variable name in different scopes, as long as the two scopes have no irresolvable conflicts. Some explanation:
firstName
.add
that accepts two double
parameters, adds them together, and returns the result - mark it as public
and static
, and returning a double
.subtract
, multiply
, and divide
.main
, create three double
variables a
, and b
, initialized with values of your choice, and c
, which we can leave uninitialized.a
and b
, and accepting the returned value into c
, and printing all three values.We will cover the concept of static
elements later, but, for now, since main
is static
, the methods it calls must be static
as well.