Java Basics
- Understand Java's basic syntax rules, including statements, blocks, and comments
- Declare variables and construct statements using variables and literal (constant) values
- Become familiar with the primitive data types, as well as the String class.
- Understand many of Java's operators and the concept of operator precedence.
- Understand the rules that apply when data is converted from one type to another.
- Declare, write, and use simple methods
Basic Java Syntax
General Syntax Rules
Java is case-sensitive
- main(), Main(), and MAIN() would all be different methods
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
- examples: public, void, static, do, for, while, if
Most keyboard symbol characters (the set of characters other than alphabetic or numeric) have a special meaning
Names may contain alphabetic characters, numeric characters, currency characters, and connecting characters such as the underscore ( _ ) character
- names may not begin with a numeric character
- note that the set of legal characters draws from the entire Unicode character set
- also note that it is probably impossible to write a succinct set of rules about what are valid characters, other than to say a character, that when passed to Character.isJavaIdentifierPart(char ch), results in a true value
The compiler parses your code by separating it into individual entities:
- names (of classes, variables, and methods)
- command keywords
- single or compound symbols (compound symbols are when an operation is signified by a two-symbol combination)
- these entities are 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 names 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)
Java Statements
A statement:
- one step of code, which may take more than one line
- ends with a semicolon (the ; character)
- it is OK to have multiple statements on one line
Program execution is statement by statement, one statement at a time
- from top to bottom (if more than one statement on a line, left to right)
Within a statement, execution of the individual pieces is not necessarily left to right
- there are concepts called operator precedence and associativity that determine the order of operations within a statement
Blocks of Code
A block of code:
- is enclosed in curly braces - start with { and end with }
- consists of zero, one, or more statements
- behaves like a single statement to the outside world
- a complete method is a block
- blocks may be nested - containing one or more blocks inside
- generally, blocks belong to whatever comes before them (although it is perfectly OK to create a block that does not, this is almost never done)
Example
If you want, go ahead and modify your Hello World program to match this example
Comments
A comment:
- is additional non-executable text in a program, used to document code
- may also be used to temporarily disable a section of code (for debugging)
Block comment: preceded by /* and followed by */
- may not be nested
- may be one or more lines
/* this is a block comment * asterisk on this line not necessary, but looks nice */
- may span part of a line, for example, to temporarily disable part of a statement:
x = 3 /* + y */ ;
Comment to end of line: preceded by //
- ends at the end of that line
- may be nested inside block comments
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
- Java contains a self-documentation utility, javadoc, which builds documentation from comments within the code
- javadoc comments begin with /** and end with */
- they only work as javadoc comments when placed at specific locations in your code
(immediately above anything documentable - the class itself and its members),
otherwise they are treated as ordinary comments
/** Represents a person, with a first nanme and last name. */ public class Person { /** The person's first name */ public String firstName; /** The person's last name */ public String lastName; }
Variables
Variables store data that your code can use
There are two fundamental categories of variables, primitive data and references
- with primitive data, the compiler names a memory location and uses to store the actual data - numeric values such as integers, floating point values, and the code values of single individual text characters are stored as primitives
- with references, the data is accessed indirectly - the compiler selects a memory location, associates it with the variable name, and stores in it a value that is effectively the memory address of the actual data - in Java, all objects and arrays are stored using references
In the diagram below, the boxes are areas in memory:
Declaring Variables
Variables must be declared before they are used
A declaration informs the compiler that you wish to:
- create an identifier that will be accepted by the compiler within a section of code (exactly what that section is depends on how and where the variable is declared; that is the concept of scope, which will be addressed later)
- associate that identifier with a specified type of data, and enforce restrictions related to that in the remainder of your code
- create a memory location for the specified type of data
- associate the identifier with that memory location
Java uses many specific data types; each has different properties in terms of size required and handling by the compiler
- the declaration specifies the name and datatype
- generally the declaration also defines the variable, meaning that it causes the compiler to allocate storage space in memory of the requested type's size
- a declaration may also assign in initial value (to initialize the variable)
- multiple variables of the same type can be declared in a comma-separated list
| Code | Effect |
|---|---|
| int a; |
declares the name a to exist, and allocates a memory location to hold a 32-bit integer |
| 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 trying to read data from variables that have not been initialized
- some languages just let the value be whatever happened to be in that memory location already (from some previous operation)
- some languages initialize automatically to 0
- some languages give a compiler or runtime error
- Java uses both of the last two: local variables within methods must be initialized before attempting to use their value, while variables that are fields within objects are automatically set to zero
Advanced Declarations
Local variables, fields, methods, and classes may be given additional modifiers; keywords that determine any special characteristics they may have
- 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 final field does not, however, have to be initialized immediately; the initial assignment may be done once during an object's construction |
| 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 abstract may be instantiated (a class must be abstract if one or more of it's methods is abstract) - covered in depth later |
| 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 strictfp |
| synchronized | methods, code blocks |
no synchronized code may be accessed from multiple threads for the same object instance at the same time |
Data
Primitive Data Types
The primitive data types store single values at some memory location that the compiler selects and maps to the variable name you declared
- primitive values are not objects - they do not have fields or methods
A primitive value is stored at the named location, while an object is accessed using a reference
- an object reference variable does not store the object's data directly - it stores a reference to the block of data, which is somewhere else in memory (technically, the reference stores the memory address of the object, but you never get to see or use the address)
| 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 |
Object Data Types
Objects can be data, which can be stored in variables, passed to methods, or returned from methods.
References
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)
Text Strings
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:
- is accessed through a reference, since it is an object
- has a number of useful methods, for case-sensitive or case-insensitive comparisons, obtaining substrings, determining the number of characters, converting to upper or lower case, etc.
- is immutable; that is, once created it cannot be changed (but you can make your variable reference a different String object at any time)
Literal Values
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)
- a numeric value with no decimal places becomes an int, unless it is immediately assigned into a variable of a smaller type and falls within the valid range for that type
- a value with decimal places becomes a double
- to store a text character, you can put apostrophes around the character
| 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; |
- note: using these prefixes will always result in number that is considered positive (so that 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)
- also note that a 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; |
Escape Sequences for Character Values
There are a number of escape sequences that are used for special characters
| Escape Sequence | Resulting Character |
|---|---|
| \b | backspace |
| \f | form feed |
| \n | a linefeed character - note that it produces exactly one character, Unicode 10 (\u000A in hex) |
| \r | a carriage return |
| \t | a tab |
| \" | a quote mark |
| \' | an apostrophe |
| \\ | a backslash |
| \uNNNN | a Unicode value, where N is a base 16 digit from 0 through F; valid values are \u0000 through \uFFFF |
| \NNN | a 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");
Constants and the final keyword
Java has a means for defining constant values
- like variables in that they have names, but not changeable once set
If a variable is declared as final, it cannot be changed
- even though the variable's value is not changeable once a value has been established, you are allowed to set a unique value once
- local variables within methods may be declared as final
- their values may be set in an explicit initialization, in a separate line of code, or, for method parameters, as the value passed in when the method is called
- fields within a class may be declared as final
- their values may be set in an explicit initialization, in a separate line of code within an initialization block, or in a constructor
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
Code Sample: Java-Basics/Demos/FinalValues.java
import java.io.*;
public class FinalValues {
final int f1 = 1;
final int f2;
{
f2 = 2;
}
final int f3;
public FinalValues(int i) {
f3 = i;
final int f4 = i;
System.out.println("In constructor, f4 = " + f4);
}
public void useFinalParameter(final int f5) {
System.out.println("f5 = " + f5);
}
public void printAll() {
System.out.println("f1 = " + f1);
System.out.println("f2 = " + f2);
System.out.println("f3 = " + f3);
}
public static void main(String[] args) {
FinalValues fv = new FinalValues(3);
fv.useFinalParameter(5);
fv.printAll();
}
}
Mathematics in Java
Looks and behaves like algebra, using variable names and math symbols:
int a, b, c, temp; a = b/c + temp; b = c * (a - b);
Basic Rules
- what goes on the left of the = 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);
- math symbols are known as operators; they include:
Operator Purpose (Operation Performed) + for addition - for subtraction * for multiplication / for division % for modulus (remainder after division) ( and ) for enclosing a calculation - note that integer division results in an integer - any remainder is discarded
Expressions
An expression is anything that can be evaluated to produce a value
- every expression yields a value
Examples (note that the first few of these are not complete statements):
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);
- the value stored in a is the value of the expression b + (5/c)
- since an assignment expression's value is the value that was assigned, the same value is then stored in d
- the order of processing is as follows:
- retrieve the value of b
- retrieve the 5 stored somewhere in memory by the compiler
- retrieve the value of c
- perform 5 / c
- add the held value of b to the result of the above step
- store that value into the memory location for a
- store that same value into the memory location for 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);
- since the 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);
- then the compiler creates code to evaluate 20.0 + 5.0 (at runtime it would become 25.0), reducing the expression to:
d = a + b * Math.sqrt(25.0);
- next, the compiler adds code to call the Math.sqrt method to evaluate its result, which will be 5.0, so the expression reduces to:
d = a + b * 5.0;
- note: the evaluated result of a method is known as the return value, or value returned
- multiplication gets done before addition, the compiler creates that code next, to reduce the expression to:
d = a + 50.0;
- then the code will perform the addition, yielding
d = 55.0;
- and finally, the assignment is performed so that 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
Operator precedence specifies the order of evaluation of an expression
- every language has a "table of operator precedence" that is fairly long and complex
Most languages follow the same general rules
- anything in parentheses gets evaluated before the result is related to what is outside the parentheses
- multiply or divide get done before add and subtract
Example
- in the expression 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
- the equal sign = 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:
Code Sample: Java-Basics/Demos/ExpressionExample.java
public class ExpressionExample {
public static void main(String[] args) {
double a = 5.0, b = 10.0, c = 20.0;
System.out.println("a+b is " + (a + b));
System.out.println("a+b/c is " + (a + b / c));
System.out.println("a*b+c is " + (a * b + c));
System.out.println("b/a+c/a is " + (b / a + c / a));
}
}
Multiple Assignments
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
- generates the random number and stores it in x
- as an expression, that results in the same value, which is then tested for less than 0.5, and the loop body executes if that is true
- the value of x is then available within the block
- after the loop body executes, another random number is generated as the process repeats
It is usually not necessary to code this way, but you will see it often
Order of Evaluation
The order of operand evaluation is always left to right, regardless of the precedence of the operators involved
Code Sample: Java-Basics/Demos/EvaluationOrder.java
public class EvaluationOrder {
public static int getA() {
System.out.println("getA is 2");
return 2;
}
public static int getB() {
System.out.println("getB is 3");
return 3;
}
public static int getC() {
System.out.println("getC is 4");
return 4;
}
public static void main(String[] args) {
int x = getA() + getB() * getC();
System.out.println("x = " + x);
}
}
- 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()
Bitwise Operators
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 = 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 |
Bitwise Shift Operators
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...00000010 |
| 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 |
Compound Operators
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, to use 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 |
Compound Operator Examples
| Statement | Result |
|---|---|
| i++; | increment i |
| i--; | decrement i |
| j = i++; | retrieve current value of i, hold it as the result of the expression, then increment i, then use the held value for the assignment into j |
| 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:
Code Sample: Java-Basics/Demos/IncrementTest.java
public class IncrementTest {
public static void main(String[] args) {
int i = 0, j;
i = i++;
System.out.println("i = " + i);
j = i++ + i;
System.out.println("i = " + i + ", j = " + j);
}
}
- in the first statement, 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!
- in the second part, 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 that Mix Data Types: Typecasting
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
- in general, the processor will choose the larger or more complex unit to work with
- in the first case the value 4 will be promoted to a double, which will then be used in the division
- the conversion is done one expression at a time within a statement; so, in the second example, the division will be performed with integer math, resulting in a value of 3, which will then be promoted to a double to finish the statement
The process of changing the data type of a value is known a typecasting (or casting)
- a widening cast converts a smaller or less precise value into a larger or more precise type - this is done automatically (the compiler does an implicit cast, as above)
- a narrowing cast converts a larger or more precise value into a smaller or less precise type (such as from double to int) - this must be coded with an explicit cast
- to code an explicit typecast, put the desired type in parentheses in front of the expression to be converted; for example:
int a = (int) (15.6 / 4);
- the division will be evaluated as before, meaning the 4 is promoted to a double, and the result is a double
- but, a double can't be stored in a, so the cast to int is necessary
- note that casting is an operation, therefore it has a precedence (which is fairly high on the operator precedence table)
The allowable sequence of implicit casts is shown below
Small Integral Types and Expressions
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:
- if either operand is of type double, the other is converted to double.
- otherwise, if either operand is of type float, the other is converted to float.
- otherwise, if either operand is of type long, the other is converted to long.
- otherwise, both operands are converted to type int.
Creating and Using Methods
The method is the basic complete unit of code to perform one task within an object
- in procedural languages, these are called functions, but in OOP they are usually called methods
- almost all executable code is in some method
- technically, there is one other place an object-oriented program could have executable code, but that is an advanced topic
- examples: calculate a trigonometry function like cosine, print data on the screen, read from a file, open a window
- methods are defined by a name followed by parentheses
- inputs to the method go inside the parentheses; they are called parameters or arguments to the method
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)
- this value is called the return value, and the method is said to return a value
- the following is an example of a method used as an expression within a larger expression:
z = Math.sin(Math.PI / Math.sqrt(x));
Methods must be called with arguments that matching their specified form, known as the function signature
- the signature is the combination of the name of the method with the pattern of its parameters
- the documentation for library-supplied methods will tell you the signature for those methods
- when you call a method, the name of the method and the parameters you pass to the it will determine which method will be called, based on the available signatures
- for each argument, Java expects a value - which could be a literal value, a variable, or expression; it must be either the correct type or a value that can be implicitly typecast to the correct type
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 term on that element)
The following example
Code Sample: Java-Basics/Demos/UseMethodsExample.java
public class UseMethodsExample {
public static void main(String[] args) {
int x = 16;
double y = Math.sqrt(x);
System.out.println("Square root of " + x + " is " + y);
double z = Math.sin(Math.PI / 2);
System.out.println("Sine of pi/2 is " + z);
}
}
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 get called: main()
- the definition of main() is that it provides a start point and end point for your program
- program execution starts with the first statement in main()
- if the last statement in main() gets executed, the program ends
- note that main() does have arguments (any other words typed on the command line)
Creating Methods
There are three things you need to decide for any method
- what it does
- what inputs it needs
- what answer it gives back
[modifiers] dataType methodName(parameterList) {
methodBody
return result;
}
- where emphasized words are concepts; 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 on page 7 of this section
- dataType is a type of data, like int
- methodName is the name of your method
- parameterList is a comma-separated list of parameter names with their data types; 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)
- if a method declares that it returns a value of a certain type, then it must explicitly return a value of that type
Method Examples
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
- the name of the method is sayHello
- this method could be called as follows:
| 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);
}
- again, this method does not calculate a result
- this method could be called as follows:
| 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;
}
- this method does calculate a result; the data type it calculates is int
- it must be given two parameters, both of which are int data
- this method could be called as follows:
| 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 |
Return Values
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
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;
}
- the parameter list declares two variables that will exist in this method: num1 and num2
- the order is important - num1 will be the first value given to the method, num2 will be the second
- the difference between method parameter declarations and the variable declarations we saw before is that the method parameters receive their values when the method is called
Variable Scope
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
- local variables (those within methods) are not visible to any code that precedes the declaration
- object elements are visible to any code within the object, regardless of the order of declaration
Variables declared within a set of curly braces cease to exist after the closing brace (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
- non-overlapping scopes - for example, two different methods could each have a local variable called firstName
- overlapping scopes - it is valid for a method to have a variable whose name conflicts with a property name for that class - in that case, the local variable hides the property, but there is a special syntax that allows the method to access the property; we will cover this later
- it is legal for a method and a property of a class to have the same name, although it is not considered a good practice to do so
- an example of an irresolvable conflict is declaring a local variable within a block when the same name is already in scope in that method as a local variable
Code Sample: Java-Basics/Demos/MethodExample.java
public class MethodExample {
public static void sayHello() {
System.out.println("Hello");
}
public static void showNumber(int number) {
System.out.println("The number is: " + number);
}
public static int calculateSum(int num1, int num2) {
int answer = num1 + num2;
return answer;
}
public static void main(String[] args) {
sayHello();
showNumber(5);
int b = calculateSum(4, 6);
System.out.println("The sum of 4 and 6 is:" + b);
b = calculateSum(4, 6) / 2;
System.out.println("That divided by 2 is: " + b);
}
}
Exercise: Method Exercise
- Create a class called Calculator
- In it create a method called add that accepts two double parameters, adds them together, and returns the result - mark it as public and static, and returning a double
- In a similar manner, create methods called subtract, multiply, and divide
- In main, create three double variables a, and b, initialized with values of your choice, and c, which we can leave uninitialized
- Call each of your methods in turn, passing 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
Java Basics Conclusion
In this lesson of the Java tutorial you have learned:
- About Java's basic syntax rules, variables and their declaration, and primitive types
- To write simple statements using variables and operators.
- To understand the rules that apply when data is converted from one type to another.
- To declare, write, and use simple methods