Home » C++ Programs
Given a number, we have to reverse it using class and object approach.
Submitted by Shubh Pachori, on August 05, 2022
Example:
Input: 1234 Output: 4321
C++ Code to find the reverse of a number using class and object approach
#include using namespace std; // Create a class class Reverse { // Private data member private: int number; // Public function with an int type parameter public: void reverse[int n] { // Copying value of parameter in the data member number = n; // Declaring two int type variable for storing reversed // number and operations int remain, reverse = 0; // While loop for reversing the number while [number] { // The last digit of number is stored in remain // by % operator remain = number % 10; // The number which is in remain will be added in reverse // with a multiply of 10 at each iteration reverse = [reverse * 10] + remain; // Number is divided by 10 to discard the last digit number = number / 10; } // Printing the reversed number cout? @ A B C D E 7 F G H I J K L M N O 8 P Q R S T U V W X Y 9 Z [ \ ] ^ _ ` a b c 10 d e f g h i j k l m 11 n o p q r s t u v w 12 x y z { | } ~
SP | ! | " | # | $ | % | & | ' | [ | ] | * | + | , | - | . | / |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
@ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ |
In Java, a char
can be treated as its underlying integer in the range of [0, 65535]
in arithmetic operations. In other words, char
and integer are interchangeable in arithmetic operations. You can treat a char
as an int,
you can also assign an integer value in the range of [0, 65535]
to a char
variable. For example,
char letter = 'a'; char anotherLetter = 98; System.out.println[letter]; System.out.println[anotherLetter]; anotherLetter += 2; System.out.println[anotherLetter];
Special characters are represented by so-called escape sequence, which begins with a back-slash [\
]
followed by a pattern, e.g., \t
for tab, \n
for newline. The commonly-used escape sequences are:
\t | Tab | 9 | 0009H |
\n | Newline [or Line-feed] | 10 | 000AH |
\r | Carriage-return | 13 | 000DH |
\" | Double-quote [Needed to be used inside double-quoted String ]
| - | - |
\' | Single-quote [Needed to be used inside single-quoted char , i.e., '\'' ]
| - | - |
\ | Back-slash [Needed as back-slash is given a special meaning] | - | - |
\uhhhh | Unicode number hhhh [in hex], e.g., \u60a8 is 您, \u597d is 好
| - | hhhhH |
For examples,
char tabChar = '\t'; char anotherTabChar = 9; char newlineChar = '\n'; char backSlashChar = '\\'; char singleQuoteChar = '\''; char doubleQuoteChar = '"'; System.out.println["A tab " + tabChar + " before this; end with two newlines!" + newlineChar + newlineChar];
String
Literals and Escape SequencesA String
is a sequence of characters. A String
literal is composed of zero of more characters surrounded by a pair of double quotes. For examples,
String directionMsg = "Turn Right"; String greetingMsg = "Hello"; String statusMsg = "";
You need to use an escape sequence for special non-printable characters, such as newline [\n
] and tab [\t
]. You also need to use escape sequence for double-quote [\"
] and backslash [\\
] due to conflict. For
examples,
String str1 = "hello\tworld\n"; String str2 = "a double quoted \"hello\""; String str3 = "1 back-slash \\, another 2 back-slashes \\\\"; String str1 = "A \"string\" nested \\inside\\ a string" String str2 = "Hello, \u60a8\u597d!"
Single-quote ['
] inside a String
does not require an escape sequence because there is no ambiguity, e.g.,
String str3 = "Hi, I'm a string!"
It is important to take note that \t
or \"
is ONE single character, NOT TWO!
Exercise: Write a program to print the following animal picture using System.out.println[]
. Take note that you need to use escape sequences to print some characters, e.g., \"
for "
, \\
for \
.
'__' [oo] +========\/ / || %%% || * ||-----|| "" ""End-of-Line [EOL]
Newline [0AH
] and Carriage-Return [0DH
], represented by the escape sequence \n
, and \r
respectively, are used as line delimiter [or end-of-line, or EOL] for text files. Take note that Unix and macOS use \n
[0AH
] as EOL, while Windows use \r\n
[0D0AH
].
boolean
LiteralsThere are only two boolean
literals, i.e., true
and false
. For example,
boolean done = true; boolean gameOver = false; boolean isValid; isValid = false;Example on Literals
public class LiteralTest {
public static void main[String[] args] {
String name = "Tan Ah Teck";
char gender = 'm';
boolean isMarried = true;
byte numChildren = 8;
short yearOfBirth = 1945;
int salary = 88000;
long netAsset = 8234567890L;
double weight = 88.88;
float gpa = 3.88f;
System.out.println["Name is: " + name];
Name is: Tan Ah Teck
System.out.println["Gender is: " + gender];
System.out.println["Is married is: " + isMarried];
System.out.println["Number of children is: " + numChildren];
System.out.println["Year of birth is: " + yearOfBirth];
System.out.println["Salary is: " + salary];
System.out.println["Net Asset is: " + netAsset];
System.out.println["Weight is: " + weight];
System.out.println["GPA is: " + gpa];
}
}
var
- Local
Variable Type Inference [JDK 10]
JDK 10 introduces a new way to declare variables via a new keyword var
, for examples,
var v1 = 0; var v2 = 0.0; var v3 = 1.0f; var v4 = '0'; var v5 = "hello"; var v6; compilation error: cannot use 'var' on variable without initializer
Clearly, you need to initialize the variable, so that the compiler can infer its type.
Basic Operations
Arithmetic Operators
Java supports the following binary/unary arithmetic operations:
+ | Binary Unary | x + y
| Addition Unary positive | 1 + 2 ⇒ 3
|
- | Binary Unary | x - y
| Subtraction Unary negate | 1 - 2 ⇒ -1
|
* | Binary | x * y
| Multiplication | 2 * 3 ⇒ 6
|
/ | Binary | x / y
| Division | 1 / 2 ⇒ 0 1.0 / 2.0 ⇒ 0.5 |
% | Binary | x % y
| Modulus [Remainder] | 5 % 2 ⇒ 1
|
These operators are typically binary infix operators, i.e., they take two operands with the operator in between the operands [e.g., 11 + 12
]. However, '-'
and '+'
can also be interpreted as unary "negate" and "positive" prefix operator, with the operator in front of the operand. For examples,
int number = -9; number = -number;
Arithmetic Expressions
In programming, the following arithmetic expression:
must be written as [1+2*a]/3 + [4*[b+c]*[5-d-e]]/f - 6*[7/g+h]
. You cannot omit the multiplication sign [*
] as in Mathematics.
Like Mathematics:
- Parentheses
[]
have the highest precedence and can be used to change the order of evaluation. - Unary
'-'
[negate] and'+'
[positive] have next higher precedence. - The multiplication [
*
], division [/
] and modulus [%
] have the same precedence. They take precedence over addition [+
] and subtraction [-
]. For example,1+2*3-4/5+6%7
is interpreted as1+[2*3]-[4/5]+[6%7]
. - Within the same precedence level [i.e., addition/subtraction and multiplication/division/modulus], the expression is evaluated from left to right [called left-associative]. For examples,
1+2-3+4
is evaluated as[[1+2]-3]+4
, and1*2%3/4
is[[1*2]%3]/4
.
Type Conversion in Arithmetic Operations
Your program typically contains data of many types, e.g., count
and sum
are int
, average
and gpa
are double
, and message
is a String
. Hence, it is important to understand how Java handles types in your programs.
The arithmetic operators [+
, -
, *
, /
, %
] are only applicable to primitive number types: byte
, short
, int
, long
,
float
, double
, and char
.
They are not applicable to boolean
.
int
, long
, float
, double
If BOTH operands are int
, long
, float
or double
, the binary arithmetic operations are carried in that type, and evaluate to a value of that type, i.e.,
int ⊕ int ⇒ int
, where⊕
denotes a binary arithmetic operators such as+
,-
,*
,/
,%
.long ⊕ long ⇒ long
float ⊕ float ⇒ float
double ⊕ double ⇒ double
int
DivisionIt is important to take note int
division produces an int
, i.e., int / int ⇒
int
, with the result truncated. For example, 1/2 ⇒ 0
[int
], but 1.0/2.0 ⇒ 0.5
[double / double ⇒ double
].
byte
, short
, char
: Convert to int
If BOTH operands are byte
, short
or char
, the binary operations are carried out in int
, and evaluate to a value of int
. A char
is treated as an
integer of its underlying Unicode number in the range of [0, 65535]
. That is,
byte ⊕ byte ⇒ int ⊕ int ⇒ int
, where⊕
denotes a binary arithmetic operators such as+
,-
,*
,/
,%
.short ⊕ short ⇒ int ⊕ int ⇒ int
char ⊕ char ⇒ int ⊕ int ⇒ int
Take note that NO arithmetic operations are carried out in byte
, short
or char
.
For examples,
byte b1 = 5, b2 = 9, b3;
b3 = b1 + b2;
b3 = [byte][b1 + b2];
However, if compound arithmetic operators [+=
, -=
, *=
, /=
, %=
] [to be discussed later] are
used, the result is automatically converted to the LHS. For example,
byte b1 = 5, b2 = 9; b2 += b1;Mixed-Type Arithmetic Operations
If the two operands belong to different types, the value of the smaller type is promoted automatically to the larger type [known as implicit type-casting]. The operation is then carried out in the larger type, and evaluated to a value in the larger type.
byte
,short
orchar
is first promoted toint
before comparing with the type of the other operand. [In Java, no operations are carried out inbyte
,short
orchar
.]- The order of promotion is:
int ⇒ long ⇒ float ⇒ double
.
For examples,
int / double ⇒ double / double ⇒ double
. Hence,1/2 ⇒ 0, 1.0/2.0 ⇒ 0.5, 1.0/2 ⇒ 0.5, 1/2.0 ⇒ 0.5
9 / 5 * 20.1 ⇒ [9 / 5] * 20.1 ⇒ 1 * 20.1 ⇒ 1.0 * 20.1 ⇒ 20.1
[You probably don't expect this answer!]char '0' + int 2 ⇒ int 48 + int 2 ⇒ int 50
[Result is anint
, need to explicitly cast back tochar
'2'
if desired.]char ⊕ float ⇒ int ⊕ float ⇒ float ⊕ float ⇒ float
byte ⊕ double ⇒ int ⊕ double ⇒ double ⊕ double ⇒ double
The type-promotion rules for binary operations can be summarized as follows:
- If one of the operand is
double
, the other operand is promoted todouble
; - else if one of the operand is
float
, the other operand is promoted tofloat
; - else if one of the operand is
long
, the other operand is promoted tolong
; - else both operands are promoted to
int
.
The type-promotion rules for unary operations [e.g., negate '-'
] can be summarized as follows:
- If the operand is
double
,float
,long
orint
, there is no promotion; - else the operand is
byte
,short
,char
, the operand is promoted toint
.
More on Arithmetic Operators
Modulus [Remainder] OperatorTo evaluate the remainder for negative and floating-point operands, perform repeated subtraction until the absolute value of the remainder is less than the absolute value of the second operand.
For example,
-5 % 2 ⇒ -3 % 2 ⇒ -1
5.5 % 2.2 ⇒ 3.3 % 2.2 ⇒ 1.1
Java does not have an exponent operator. [The ^
operator denotes exclusive-or, NOT exponent]. You need to use JDK method Math.exp[x, y]
to evaluate x
raises to power y
; or write your own code.
Overflow/Underflow
Study the output of the following program:
public class OverflowTest { public static void main[String[] args] { int i1 = 2147483647; System.out.println[i + 1]; System.out.println[i + 2]; System.out.println[i + 3]; System.out.println[i * 2]; System.out.println[i * i]; int i2 = -2147483648; System.out.println[i2 - 1]; System.out.println[i2 - 2]; System.out.println[i2 * i2]; } }
In arithmetic operations, the resultant value wraps around if it exceeds its range [i.e., overflow]. Java runtime does NOT issue an error/warning message but produces an incorrect result.
On the other hand, integer division produces a truncated integer and results in so-called underflow. For example, 1/2
gives 0
, instead of 0.5
. Again, Java runtime does NOT issue an error/warning message, but produces an imprecise result.
It is important to take note that checking of overflow/underflow is the programmer's responsibility. i.e., your job!!!
Why computer does not flag overflow/underflow as an error? This is due to the legacy design when the processors were very slow. Checking for overflow/underflow consumes computation power. Today, processors are fast. It is better to ask the computer to check for overflow/underflow [if you design a new language], because few humans expect such results.
To check for arithmetic overflow [known as secure coding] is tedious. Google for "INT32-C. Ensure that operations on signed integers do not result in overflow" @ www.securecoding.cert.org.
More on Integer vs. Floating-Point Numbers
Integers [byte
, short
, int
, long
] are precise [exact]. But float
and double
are not precise but close approximation. Study the results of the following program:
public class TestPreciseness {
public static void main[String[] args] {
System.out.println[2.2 + 4.4]; 6.6000000000000005
System.out.println[6.6 - 2.2 - 4.4];
System.out.println[[6.6] == [2.2 + 4.4]];
int i1 = 123456789;
System.out.println[i1*10];
float f1 = 123456789.0f;
System.out.println[f1];
System.out.println[f1*10];
}
}
Always use int
if you do not need the fractional part,
although double
can also represent most of the integers [e.g., 1.0
, 2.0
, 3.0
]. This is because:
int
is more efficient [faster] thandouble
in arithmetic operations.- 32-bit
int
takes less memory space than 64-bitdouble
. int
is exact [precise] in representing ALL integers within its range.double
is an approximation - NOT ALL integer values can be represented bydouble
.
Type Casting
In
Java, you will get a compilation "error: incompatible types: possible lossy conversion from double|float|long
to int
" if you try to assign a double
, float
, or long
value of to an int
variable. This is because the fractional part would be truncated and lost. For example,
double d = 3.5; int i = d; Compilation error: incompatible types: possible lossy conversion from double to int int sum = 55.66f; Compilation error: incompatible types: possible lossy conversion from float to int long lg = 123; int count = lg; Compilation error: incompatible types: possible lossy conversion from long to intExplicit Type-Casting and Type-Casting Operator
To assign the a double
value to an int
variable, you need toinvoke the so-called type-casting operator - in the form of
[int]doubleOperand
- to operate on the double
operand and return a truncated value in int
. In other words, you tell the compiler you consciously perform the truncation and you are fully aware of the "possible lossy conversion". You can then assign the truncated int
value to the int
variable. For example,
double d = 3.5; int i; i = [int]d;
Type casting is an operation which takes one operand. It operates on its operand, and returns an equivalent value in the specified type. The syntax is:
[type]variable [type]literal
There are two kinds of type-casting in Java:
- Explicit type-casting via a type-casting operator, as described above, and
- Implicit type-casting performed by the compiler automatically, if there is no loss of precision.
Explicit type-casting is not required if you assign an int
value to a double
variable, because there is no loss of precision. The
compiler will perform the type-casting automatically [i.e., implicit type-casting]. For example,,
int i = 3; double d; d = i; d = [double]i; double aDouble = 55; double nought = 0;
The following diagram shows the order of implicit type-casting performed by compiler. The rule is to promote the smaller type to a bigger type to prevent loss of precision, known as widening conversion. Narrowing conversion requires explicit type-cast to inform the compiler that you are aware of the possible loss of precision. Take note that char
is treated as an integer in the
range of [0, 65535]
. boolean
value cannot be type-casted [i.e., converted to non-boolean
].
Example: Suppose that you want to find the average [in double
] of the running integers from 1
and 100
. Study the following code:
public class Average1To100 { public static void main[String[] args] { int sum = 0; double average; for [int number = 1; numberBinary x > y
Greater than [x > y] ⇒ false
>= Binary x >= y
Greater than or equal to [x >= 5] ⇒ true
< Binary x < y
Less than [y < 8] ⇒ false
= 0] && [x = 180] && [weight >= 65] && [weight = 180] || [weight >= 90]]; } } Write an expression for all unmarried male, age between 21 and 35, with height above 180, and weight between 70 and 80.
Exercise: Given the
year
,month
[1-12], andday
[1-31], write aboolean
expression which returnstrue
for dates before October 15, 1582 [Gregorian calendar cut-over date].Ans:
Equality Comparison[year < 1582] || [year == 1582 && month < 10] || [year == 1582 && month == 10 && day < 15]
==
You can use
==
to compare two integers [byte
,short
,int
,long
] andchar
. But do NOT use==
to compare two floating-point numbers [float
anddouble
] because they are NOT precise. To compare floating-point numbers, set a threshold for their difference, e.g.,public class FloatComparisonTest { public static void main[String[] args] { double d1 = 2.2 + 4.4; double d2 = 6.6; System.out.println[d1 == d2]; System.out.println[d1]; final double EPSILON = 1e-7; System.out.println[Math.abs[d1 - d2] < EPSILON]; } }You also CANNOT use
Logical Operator Precedence==
to compare twoString
s becauseString
s are objects. You need to usestr1.equals[str2]
instead. This will be elaborated later.The precedence from highest to lowest is:
'!'
[unary],'^'
,'&&'
,'||
'. But when in doubt, use parentheses!System.out.println[true || true && false]; System.out.println[true || [true && false]]; System.out.println[[true || true] && false]; System.out.println[false && true ^ true]; System.out.println[false && [true ^ true]]; System.out.println[[false && true] ^ true];Short-Circuit OperationsThe binary AND [
&&
] and OR [||
] operators are known as short-circuit operators, meaning that the right-operand will not be evaluated if the result can be determined by the left-operand. For example,false && rightOperand
givesfalse
andtrue || rightOperand
givetrue
without evaluating the right-operand. This may have adverse consequences if you rely on the right-operand to perform certain operations, e.g.false && [++i < 5]
but++i
will not be evaluated.
String
and'+'
Concatenation OperatorIn Java,
'+'
is a special operator. It is overloaded. Overloading means that it carries out different operations depending on the types of its operands.
- If both operands are numeric [
byte
,short
,int
,long
,float
,double
,char
],'+'
performs the usual addition. For examples,1 + 2 ⇒ 3 1.2 + 2.2 ⇒ 3.4 1 + 2.2 ⇒ 1.0 + 2.2 ⇒ 3.2 '0' + 2 ⇒ 48 + 2 ⇒ 50- If both operands are
String
s,'+'
concatenates the twoString
s and returns the concatenatedString
. For examples,"Hello" + "world" ⇒ "Helloworld" "Hi" + ", " + "world" + "!" ⇒ "Hi, world!"- If one of the operand is a
String
and the other is numeric, the numeric operand will be converted toString
and the twoString
s concatenated, e.g.,"The number is " + 5 ⇒ "The number is " + "5" ⇒ "The number is 5" "The average is " + average + "!" [suppose average=5.5] ⇒ "The average is " + "5.5" + "!" ⇒ "The average is 5.5!" "How about " + a + b [suppose a=1, b=1] ⇒ "How about 1" + b ⇒ "How about 11" [left-associative] "How about " + [a + b] [suppose a=1, b=1] ⇒ "How about " + 2 ⇒ "How about 2"We use
String
concatenation operator'+'
frequently in theprint[]
andprintln[]
to produce the desired outputString
. For examples,System.out.println["The sum is: " + sum]; System.out.println["The square of " + input + " is " + squareInput];Flow Control
There are three basic flow control constructs - sequential, conditional [or decision], and loop [or iteration], as illustrated below.
Sequential Flow Control
A program is a sequence of instructions executing one after another in a predictable manner. Sequential flow is the most common and straight-forward, where programming statements are executed in the order that they are written - from top to bottom in a sequential manner.
Conditional Flow Control
There are a few types of conditionals, if-then, if-then-else, nested-if, switch-case-default, and conditional expression.
if
-then andif
-then-else
SyntaxExampleFlowchart // if-then if [booleanTest] { trueBlock; } // next statement int mark = 80; if [mark >= 80] { System.out.println["Well Done!"]; System.out.println["Keep it up!"]; } System.out.println["Life goes on!]; double temperature = 80.1; if [temperature > 80] { System.out.println["Too Hot!"]; } System.out.println["yummy!"]; // if-then-else if [booleanTest] { trueBlock; } else { falseBlock; } // next statement int mark = 50; // Assume that mark is [0, 100] if [mark >= 50] { // [50, 100] System.out.println["Congratulation!"]; System.out.println["Keep it up!"]; } else { // [0, 49] System.out.println["Try Harder!"]; } System.out.println["Life goes on!"]; double temperature = 80.1; if [temperature > 80] { System.out.println["Too Hot!"]; } else { System.out.println["Too Cold!"]; } System.out.println["yummy!"];Braces: You could omit the braces
{ }
, if there is only one statement inside the block. For example,int absValue = -5; if [absValue < 0] absValue = -absValue; int min = 0, value = -5; if [value < min] { min = value; System.out.println["Found new min"]; } int mark = 50; if [mark >= 50] System.out.println["PASS"]; else { System.out.println["FAIL"]; System.out.println["Try Harder!"]; } int number1 = 8, number2 = 9, absDiff; if [number1 > number2] absDiff = number1 - number2; else absDiff = number2 - number1;However, I recommend that you keep the braces to improve the readability of your program, even if there is only one statement in the block.
Nested-if
SyntaxExampleFlowchart // nested-if if [booleanTest1] { block1; } else if [booleanTest2] { block2; } else if [booleanTest3] { block3; } else if [booleanTest4] { ...... } else { elseBlock; } // next statement int mark = 62; // Assume that mark is [0, 100] if [mark >= 80] { // [80, 100] System.out.println["A"]; } else if [mark >= 65] { // [65, 79] System.out.println["B"]; } else if [mark >= 50] { // [50, 64] System.out.println["C"]; } else { // [0, 49] System.out.println["F"]; } System.out.println["Life goes on!"]; double temperature = 61; if [temperature > 80] { // > 80 System.out.println["Too Hot!"]; } else if [temperature > 75] { // [75, 80] System.out.println["Just right!"]; } else { // = 80] { System.out.println["A"]; } else if [mark >= 65] { System.out.println["B"]; } else if [mark >= 50] { System.out.println["C"]; } else { System.out.println["F"]; } if [mark < 50] { System.out.println["F"]; } else if [mark < 65] { System.out.println["C"]; } else if [mark < 80] { System.out.println["B"]; } else { System.out.println["A"]; }Dangling-else
ProblemThe "dangling-
else
" problem can be illustrated as follows:int i = 0, j = 0; if [i == 0] if [j == 0] System.out.println["i and j are zero"]; else System.out.println["xxx"];The
else
clause in the above code is syntactically applicable to both the outer-if
and the inner-if
, causing the dangling-else
problem.Java compiler resolves the dangling-
else
problem by associating theelse
clause with the innermost-if
[i.e., the nearest-if
]. Hence, the above code shall be interpreted as:int i = 0, j = 0; if [i == 0] if [j == 0] System.out.println["i and j are zero"]; else System.out.println["xxx"];Dangling-
else
can be prevented by applying explicit parentheses. For example, if you wish to associate theelse
clause with the outer-if
, do this:int i = 0, j = 0; if [i == 0] { if [j == 0] System.out.println["i and j are zero"]; } else { System.out.println["i is not zero"]; } int i = 0, j = 0; if [i == 0] { if [j == 0] { System.out.println["i and j are zero"]; } else { System.out.println["i is zero, j is not zero"]; } }Nested-if
vs. Sequential-if
Study the following code:
int mark = 81; if [mark > 80] { grade = 'A'; } if [mark > 65 && mark = 50 && mark 80] { grade = 'A'; } else if [mark > 65 && mark = 50 && mark 80] { grade = 'A'; } else if [mark > 65] { grade = 'B'; } else if [mark >= 50] { grade = 'C'; } else { grade = 'F'; }switch-case-default
SyntaxExampleFlowchart // switch-case-default switch [selector] { case value1: block1; break; case value2: block2; break; case value3: block3; break; ...... case valueN: blockN; break; default: // not the above defaultBlock; } // next statement // Selector Types: // byte, short, int, // char, String // Print number in word int number = 3; switch [number] { // "int" selector case 1: // "int" value System.out.println["ONE"]; break; case 2: System.out.println["TWO"]; break; case 3: System.out.println["THREE"]; break; default: System.err.println["OTHER"]; } // Select arithmetic operation char operator = '*'; int num1 = 5, num2 = 8, result; switch [operator] { // "char" selector case '+': // "char" value result = num1 + num2; break; case '-': result = num1 - num2; break; case '*': result = num1 * num2; break; case '/': result = num1 / num2; break; default: System.out.println["Unknown operator]; }"
switch-case-default
" is an alternative to the "nested-if
" for fixed-value tests [but not applicable for range tests]. You can use anint
,byte
,short
, orchar
variable as the case-selector, but NOTlong
,float
,double
andboolean
. JDK 1.7 supportsString
as the case-selector.In a
switch-case
statement, abreak
statement is needed for each of the cases. Ifbreak
is missing, execution will flow through the following case, which is typically a mistake. However, we could use this property to handle multiple-value selector. For example,char inChar = 'x'; switch [inChar] { case 'a': case 'b': case 'c': System.out.print[2]; break; case 'd': case 'e': case 'f': System.out.print[3]; break; case 'g': case 'h': case 'i': System.out.print[4]; break; case 'j': case 'k': case 'l': System.out.print[5]; break; ...... default: System.out.println["Invalid Input"]; }Conditional Expression [ ...?
...:
... ]A conditional operator is a ternary [3-operand] operator, in the form of
booleanExpr ? trueExpr : falseExpr
. Depending on thebooleanExpr
, it evaluates and returns the value oftrueExpr
orfalseExpr
.
SyntaxExamples // Conditional Expression booleanExpr ? trueExpr : falseExpr // An expression that returns // the value of trueExpr // or falseExpr int num1 = 9, num2 = 8, max; max = [num1 > num2] ? num1 : num2; // RHS returns num1 or num2 // same as if [num1 > num2] { max = num1; } else { max = num2; } int value = -9, absValue; absValue = [value > 0] ? value : -value; // RHS returns value or -value // same as if [value > 0] absValue = value; else absValue = -value; int mark = 48; System.out.println[[mark >= 50] ? "PASS" : "FAIL"]; // Return "PASS" or "FAIL" // same as if [mark >= 50] System.out.println["PASS"]; else System.out.println["FAIL"];Conditional expression is a short-hand for
if-else
. But you should use it only for one-liner, for readability.Exercises on Getting Started and Conditional
LINK
Loop Flow Control
Again, there are a few types of loops: for, while-do, and do-while.
SyntaxExampleFlowchart // while-do loop while [booleanTest] { body; } // next statement // Sum from 1 to upperbound int sum = 0; final int UPPERBOUND = 100; int number = 1; // init while [number = '1' && hexChar = 'a' && hexChar = 'A' && hexChar 0 if [items.length > 0] { System.out.print["Enter the value of all items [separated by space]: "]; for [int i = 0; i < items.length; ++i] { items[i] = in.nextInt[]; } } in.close[]; // Print array contents, need to handle first item and subsequent items differently System.out.print["The values are: ["]; for [int i = 0; i < items.length; ++i] { if [i == 0] { // Print the first item without a leading commas System.out.print[items[0]]; } else { // Print the subsequent items with a leading commas System.out.print[", " + items[i]]; } } System.out.println["]"]; } }Arrays.toString[]
[JDK 5]JDK 5 provides an built-in methods called
Arrays.toString[anArray]
, which returns aString
in the form[a0, a1, ..., an]
. You need toimport java.util.Arrays
. For examples,import java.util.Arrays; public class TestArrayToString { public static void main[String[] args] { int[] a1 = {6 ,1, 3, 4, 5}; int[] a2 = {}; double[] a3 = new double[1]; System.out.println[Arrays.toString[a1]]; System.out.println[Arrays.toString[a2]]; System.out.println[Arrays.toString[a3]]; a3[0] = 2.2; System.out.println[Arrays.toString[a3]]; } }Code Example: Horizontal and Vertical Histograms
The following program prompts user for the number of students, and the grade of each student. It then print the histogram, in horizontal and vertical forms, as follows:
Enter the grade for student 1: 98 Enter the grade for student 2: 100 Enter the grade for student 3: 9 Enter the grade for student 4: 3 Enter the grade for student 5: 56 Enter the grade for student 6: 58 Enter the grade for student 7: 59 Enter the grade for student 8: 87 0- 9: ** 10- 19: 20- 29: 30- 39: 40- 49: 50- 59: *** 60- 69: 70- 79: 80- 89: * 90-100: ** * * * * * * * * 0-9 10-19 20-29 30-39 40-49 50-59 60-69 70-79 80-89 90-100Notes:import java.util.Scanner; import java.util.Arrays; // for Arrays.toString[] /** * Print the horizontal and vertical histograms of grades. */ public class GradesHistograms { public static void main[String[] args] { // Declare variables int numStudents; int[] grades; // Declare array name, to be allocated after numStudents is known int[] bins = new int[10]; // int array of 10 histogram bins for 0-9, 10-19, ..., 90-100 Scanner in = new Scanner[System.in]; // Prompt and read the number of students as "int" System.out.print["Enter the number of students: "]; numStudents = in.nextInt[]; // Allocate the array grades = new int[numStudents]; // Prompt and read the grades into the int array "grades" for [int i = 0; i < grades.length; ++i] { System.out.print["Enter the grade for student " + [i + 1] + ": "]; grades[i] = in.nextInt[]; } in.close[]; // Print array for debugging System.out.println[Arrays.toString[grades]]; // Populate the histogram bins for [int grade : grades] { if [grade == 100] { // Need to handle 90-100 separately as it has 11 items. ++bins[9]; } else { ++bins[grade/10]; } } // Print array for debugging System.out.println[Arrays.toString[bins]]; // Print the horizontal histogram // Rows are the histogram bins[0] to bins[9] // Columns are the counts in each bins[i] for [int binIdx = 0; binIdx < bins.length; ++binIdx] { // Print label if [binIdx != 9] { // Need to handle 90-100 separately as it has 11 items System.out.printf["%2d-%3d: ", binIdx*10, binIdx*10+9]; } else { System.out.printf["%2d-%3d: ", 90, 100]; } // Print columns of stars for [int itemNo = 0; itemNo < bins[binIdx]; ++itemNo] { // one star per item System.out.print["*"]; } System.out.println[]; } // Find the max value among the bins int binMax = bins[0]; for [int binIdx = 1; binIdx < bins.length; ++binIdx] { if [binMax < bins[binIdx]] binMax = bins[binIdx]; } // Print the Vertical histogram // Columns are the histogram bins[0] to bins[9] // Rows are the levels from binMax down to 1 for [int level = binMax; level > 0; --level] { for [int binIdx = 0; binIdx < bins.length; ++binIdx] { if [bins[binIdx] >= level] { System.out.print[" * "]; } else { System.out.print[" "]; } } System.out.println[]; } // Print label for [int binIdx = 0; binIdx < bins.length; ++binIdx] { System.out.printf["%3d-%-3d", binIdx*10, [binIdx != 9] ? binIdx * 10 + 9 : 100]; // Use '-' flag for left-aligned } System.out.println[]; } }
- We use two arrays in this exercise, one for storing the grades of the students [of the length
numStudents
] and the other to storing the histogram counts [of length10
].- We use a
10
-elementint
arrays calledbins
, to keep the histogram counts for grades of[0, 9]
,[10, 19]
, ...,[90, 100]
. Take note that there are101
grades between[0, 100]
, and the last bin has11
grades [instead of 10 for the rest]. Thebins
's index isgrade/10
, exceptgrade
of100
.Code Example: Hexadecimal to Binary [
Hex2Bin
]The following program prompts user for a hexadecimal string and convert it to its binary equivalence. For example,
Enter a Hexadecimal string: 1bE3 The equivalent binary for "1bE3" is "0001101111100011"Notesimport java.util.Scanner; /** * Prompt user for a hexadecimal string, and print its binary equivalent. */ public class Hex2Bin { public static void main[String[] args] { // Define variables String hexStr; // The input hexadecimal String int hexStrLen; // The length of hexStr char hexChar; // Each char in the hexStr String binStr =""; // The equivalent binary String, to accumulate from an empty String // Lookup table for the binary sub-string corresponding to Hex digit '0' [index 0] to 'F' [index 15] final String[] BIN_STRS = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; // Prompt and read input as "String" Scanner in = new Scanner[System.in]; System.out.print["Enter a Hexadecimal string: "]; hexStr = in.next[]; hexStrLen = hexStr.length[]; in.close[]; // Process the string from the left [most-significant hex digit] for [int charIdx = 0; charIdx < hexStrLen; ++charIdx] { hexChar = hexStr.charAt[charIdx]; if [hexChar >= '0' && hexChar = 'a' && hexChar = 'A' && hexChar 0] { int hexDigit = dec % radix; // 0-15 hexStr = HEX_CHARS[hexDigit] + hexStr; // Append in front of the hex string corresponds to reverse order dec = dec / radix; } System.out.println["The equivalent hexadecimal number is " + hexStr]; } }
- We use modulus/divide algorithm to get the hex digits [
0-15
] in reserve order. See "Number System Conversion".- We look up the hex digit
'0'-'F'
from an array using index0-15
.Exercises on Arrays
LINK
Multi-Dimensional Array
In Java, you can declare an array of arrays. For examples:
int grid[][] = new int[12][8]; grid[0][0] = 8; grid[1][1] = 5; System.out.println[grid.length]; System.out.println[grid[0].length]; System.out.println[grid[11].length];In the above example,
grid
is an array of 12 elements. Each of the elements [grid[0]
togrid[11]
] is an 8-elementint
array. In other words,grid
is a "12-element array" of "8-element int arrays". Hence,grid.length
gives12
andgrid[0].length
gives8
.public class Array2DTest { public static void main[String[] args] { int[][] grid = new int[12][8]; // A 12x8 grid, in [row][col] or [y][x] final int NUM_ROWS = grid.length; // 12 final int NUM_COLS = grid[0].length; // 8 // Fill in grid for [int row = 0; row < NUM_ROWS; ++row] { for [int col = 0; col < NUM_COLS; ++col] { grid[row][col] = row*NUM_COLS + col + 1; } } // Print grid for [int row = 0; row < NUM_ROWS; ++row] { for [int col = 0; col < NUM_COLS; ++col] { System.out.printf["%3d", grid[row][col]]; } System.out.println[]; } } }
To be precise, Java does not support multi-dimensional array directly. That is, it does not support syntax like
grid[3, 2]
like some languages. Furthermore, it is possible that the arrays in an array-of-arrays have different length.Take note that the right way to view the "array of arrays" is as shown, instead of treating it as a 2D table, even if all the arrays have the same length.
For example,
public class Array2DWithDifferentLength { public static void main[String[] args] { int[][] grid = { {1, 2}, {3, 4, 5}, {6, 7, 8, 9} }; // Print grid for [int y = 0; y < grid.length; ++y] { for [int x = 0; x < grid[y].length; ++x] { System.out.printf["%2d", grid[y][x]]; } System.out.println[]; } // Another 2D array int[][] grid1 = new int[3][]; grid1[0] = new int[2]; grid1[1] = new int[3]; grid1[2] = new int[4]; // Print grid - all elements init to 0 for [int y = 0; y < grid1.length; ++y] { for [int x = 0; x < grid1[y].length; ++x] { System.out.printf["%2d", grid1[y][x]]; } System.out.println[]; } } }
Methods [Functions]
Why Methods?
At times, a certain portion of code has to be used many times. Instead of re-writing the code many times, it is better to put them into a "subroutine", and "call" this "subroutine" many time - for ease of maintenance and understanding. Subroutine is called method [in Java] or function [in C/C++].
The benefits of using methods are:
- Divide and conquer: Construct the program from simple, small pieces or components. Modularize the program into self-contained tasks.
- Avoid repeating code: It is easy to copy and paste, but hard to maintain and synchronize all the copies.
- Software Reuse: You can reuse the methods in other programs, by packaging them into library code [or API].
Using Methods
Two parties are involved in using a method: a caller, who calls [or invokes] the method, and the method called.
The process is:
- The caller invokes a method and passes arguments to the method.
- The method:
- receives the arguments passed by the caller,
- performs the programmed operations defined in the method's body, and
- returns a result back to the caller.
- The caller receives the result, and continue its operations.
Example: Suppose that we need to evaluate the area of a circle many times, it is better to write a method called
getArea[]
, and re-use it when needed.public class EgMethodGetArea { // The entry main method public static void main[String[] args] { double r = 1.1, area, area2; // Call [Invoke] method getArea[] and return area = getArea[r]; System.out.println["area is " + area]; // Call method getArea[] again and return area2 = getArea[2.2]; System.out.println["area 2 is " + area2]; // Call method getArea[] one more time and return System.out.println["area 3 is " + getArea[3.3]]; } // Method getArea[] Definition. // Compute and return the area [in double] of circle given its radius [in double]. public static double getArea[double radius] { return radius * radius * Math.PI; } }
The expected outputs are:
area is 3.8013271108436504 area 2 is 15.205308443374602 area 3 is 34.21194399759284In the above example, a reusable method called
getArea[]
is defined, which receives an argument indouble
from the caller, performs the calculation, and return adouble
result to the caller. In themain[]
, we invokegetArea[]
methods thrice, each time with a different parameter.Take note that there is a transfer of control from the caller to the method called, and from the method back to the caller, as illustrated.
Tracing Method InvocationYou can trace method operations under Eclipse/NetBeans [Refer to the the Eclipse/NetBeans How-to article]:
Method Definition Syntax
- Step Over: Treat the method call as one single step.
- Step Into: Step into the method, so that you can trace the operations of the method.
- Step Out: Complete the current method and return to the caller.
- Set "Breakpoints" inside the method, and "resume" running to the next breakpoint.
The syntax for method definition is as follows:
public static returnValueType methodName[arg-1-type arg-1, arg-2-type arg-2,... ] { body; }public static double getArea[double radius] { return radius * radius * Math.PI; } public static int max[int number1, int number2] { if [number1 > number2] { return number1; } else { return number2; } }Take note that you need to specify the type of the arguments and the return value in method definition.
Calling MethodsTo call a method, simply use
methodName[arguments]
. For examples, to call the above methods:double area1 = getArea[1.1]; double r2 = 2.2; double area2 = getArea[r2]; double r3 = 3.3; System.out.println["Area is: " + area[r3]]; int result1 = max[5, 8]; int i1 = 7, i2 = 9; int result2 = max[i1, i2]; System.out.println["Max is: " + max[15, 16]];Take note that you need to specify the type in the method definition, but not during invocation.
Method Naming ConventionA method's name shall be a verb or verb phrase [action], comprising one or more words. The first word is in lowercase, while the rest are initial-capitalized [called camel-case]. For example,
getArea[]
,setRadius[]
,moveDown[]
,isPrime[]
, etc.Another Example:
public class EgMinMaxMethod { public static void main[String[] args] { int a = 6, b = 9, max, min; max = max[a, b]; min = min[a, b]; System.out.println[max + "," + min]; System.out.println[max[5, 8]]; System.out.println[min[5, 8]]; } public static int max[int number1, int number2] { if [number1 > number2] { return number1; } else { return number2; } } public static int min[int number1, int number2] { return [number1 < number2] ? number1 : number2; } }The "
return
" statementInside the method body, you could use a
return
statement to return a value [of thereturnValueType
declared in the method's signature] to return a value back to the caller. The syntax is:return aReturnValue; return;The "
void
" Return-TypeSuppose that you need a method to perform certain actions [e.g., printing] without a need to return a value to the caller, you can declare its return-value type as
void
. In the method's body, you could use a "return;
" statement without a return value to return control to the caller. In this case, thereturn
statement is optional. If there is noreturn
statement, the entire body will be executed, and control returns to the caller at the end of the body.Notice that
main[]
is a method with a return-value type ofvoid
.main[]
is called by the Java runtime, perform the actions defined in the body, and return nothing back to the Java runtime.Actual Parameters vs. Formal Parameters
Recall that a method receives arguments from its caller, performs the actions defined in the method's body, and return a value [or nothing] to the caller.
In the above example, the variable
[double radius]
declared in the signature ofgetArea[double radius]
is known as formal parameter. Its scope is within the method's body. When the method is invoked by a caller, the caller must supply so-called actual parameters or arguments, whose value is then used for the actual computation. For example, when the method is invoked via "area1=getArea[radius1]
",radius1
is the actual parameter, with a value of1.1
.Code Example: Magic Number
The following program contains a
boolean
method calledisMagic[int number]
, which returnstrue
if the givennumber
contains the digit8
, e.g., 18, 108, and 1288. The signature of the method is:public static boolean isMagic[int number];It also provides the
main[]
method to test theisMagic[]
. For example,Enter a positive integer: 1288 1288 is a magic number Enter a positive integer: 1234567 1234567 is not a magic numberimport java.util.Scanner; /** * This program contains a boolean method called isMagic[int number], which tests if the * given number contains the digit 8. */ public class MagicNumber { public static void main[String[] args] { // Declare variables int number; Scanner in = new Scanner[System.in]; // Prompt and read input as "int" System.out.print["Enter a positive integer: "]; number = in.nextInt[]; // Call isMagic[] to test the input if [isMagic[number]] { System.out.println[number + " is a magic number"]; } else { System.out.println[number + " is not a magic number"]; } in.close[]; } /** * Check if the given int contains the digit 8, e.g., 18, 82, 1688. * @param number The given integer * @return true if number contains the digit 8 * @Precondition number > 0 [i.e., a positive integer] */ public static boolean isMagic[int number] { boolean isMagic = false; // shall change to true if found a digit 8 // Extract and check each digit while [number > 0] { int digit = number % 10; // Extract the last digit if [digit == 8] { isMagic = true; break; // only need to find one digit 8 } number /= 10; // Drop the last digit and repeat } return isMagic; } }
Take note of the proper documentation comment for the method.
Code Example:
int
Array MethodsThe following program contains
various method for
int
array with signatures as follows:public static void print[int[] array]; public static int min[int[] array]; public static int sum[int[] array]; public static double average[int[] array];It also contains the main[] method to test all the methods. For example,
Enter the number of items: 5 Enter the value of all items [separated by space]: 8 1 3 9 4 The values are: [8, 1, 3, 9, 4] The min is: 1 The sum is: 25 The average [rounded to 2 decimal places] is: 5.00import java.util.Scanner; /** * Test various int[] methods. */ public class IntArrayMethodsTest { public static void main[String[] args] { // Declare variables final int NUM_ITEMS; int[] items; // Declare array name, to be allocated after numItems is known // Prompt for a non-negative integer for the number of items; // and read the input as "int". No input validation. Scanner in = new Scanner[System.in]; System.out.print["Enter the number of items: "]; NUM_ITEMS = in.nextInt[]; // Allocate the array items = new int[NUM_ITEMS]; // Prompt and read the items into the "int" array, if array length > 0 if [items.length > 0] { System.out.print["Enter the value of all items [separated by space]: "]; for [int i = 0; i < items.length; ++i] { items[i] = in.nextInt[]; } } in.close[]; // Test the methods System.out.print["The values are: "]; print[items]; System.out.println["The min is: " + min[items]]; System.out.println["The sum is: " + sum[items]]; System.out.printf["The average [rounded to 2 decimal places] is: %.2f%n", average[items]]; } /** * Prints the given int array in the form of [x1, x2, ..., xn] * @param array The given int array * @Postcondition Print output as side effect */ public static void print[int[] array] { System.out.print["["]; for [int i = 0; i < array.length; ++i] { System.out.print[[i == 0] ? array[i] : ", " + array[i]]; } System.out.println["]"]; } /** * Get the min of the given int array * @param array The given int array * @return The min value of the given array */ public static int min[int[] array] { int min = array[0]; for [int i = 1; i < array.length; ++i] { if [array[i] < min] min = array[i]; } return min; } /** * Get the sum of the given int array * @param array The given int array * @return The sum of the given array */ public static int sum[int[] array] { int sum = 0; for [int item: array] sum += item; return sum; } /** * Get the average of the given int array * @param array The given int array * @return The average of the given array */ public static double average[int[] array] { return [double][sum[array]] / array.length; } }
Pass-by-Value for Primitive-Type Parameters
In Java, when an argument of primitive type is pass into a method, a copy is created and passed into the method. The invoked method works on the cloned copy, and cannot modify the original copy. This is known as pass-by-value.
For example,
public class PassByValueTest { public static void main[String[] args] { int number = 8, result; System.out.println["In caller, before calling the method, number is: " + number]; // 8 result = increment[number]; // invoke method with primitive-type parameter System.out.println["In caller, after calling the method, number is: " + number]; // 8 System.out.println["The result is " + result]; // 9 } // Return number + 1 public static int increment[int number] { System.out.println["Inside method, before operation, number is " + number]; // 8 ++number; // change the parameter System.out.println["Inside method, after operation, number is " + number]; // 9 return number; } }
Notes:
- Although there is a variable called
number
in both themain[]
andincrement[]
method, there are two distinct copies - one available inmain[]
and another available inincrement[]
- happen to have the same name. You can change the name of either one, without affecting the program.Pass-by-Reference for Arrays and Objects
As mentioned, for primitive-type parameters, a cloned copy is made and passed into the method. Hence, the method cannot modify the values in the caller. It is known as pass-by-value.
For arrays [and objects - to be described in the later chapter], the array reference is passed into the method and the method can modify the contents of array's elements. It is known as pass-by-reference. For example,
import java.util.Arrays; public class PassByReferenceTest { public static void main[String[] args] { int[] testArray = {9, 5, 6, 1, 4}; System.out.println["In caller, before calling the method, array is: " + Arrays.toString[testArray]]; increment[testArray]; System.out.println["In caller, after calling the method, array is: " + Arrays.toString[testArray]]; } public static void increment[int[] array] { System.out.println["Inside method, before operation, array is " + Arrays.toString[array]]; for [int i = 0; i < array.length; ++i] ++array[i]; System.out.println["Inside method, after operation, array is " + Arrays.toString[array]]; } }Varargs - Method with Variable Number of Formal Arguments [JDK 5]
Before JDK 5, a method has to be declared with a fixed number of formal arguments. C-like
printf[]
, which take a variable number of argument, cannot not be implemented. Although you can use an array for passing a variable number of arguments, it is not neat and requires some programming efforts.JDK 5 introduces variable arguments [or varargs] and a new syntax "
Type...
". For example,public PrintWriter printf[String format, Object... args] public PrintWriter printf[Local l, String format, Object... args]Varargs can be used only for the last argument. The three dots [
...
] indicate that the last argument may be passed as an array or as a sequence of comma-separated arguments. The compiler automatically packs the varargs into an array. You could then retrieve and process each of these arguments inside the method's body as an array. It is possible to pass varargs as an array, because Java maintains the length of the array in an associated variablelength
.public class VarargsTest { // A method which takes a variable number of arguments [varargs] public static void doSomething[String... strs] { System.out.print["Arguments are: "]; for [String str : strs] { System.out.print[str + ", "]; } System.out.println[]; } // A method which takes exactly two arguments public static void doSomething[String s1, String s2] { System.out.println["Overloaded version with 2 args: " + s1 + ", " + s2]; } // Cannot overload with this method - crash with varargs version // public static void doSomething[String[] strs] // Test main[] method // Can also use String... instead of String[] public static void main[String... args] { doSomething["Hello", "world", "again", "and", "again"]; doSomething["Hello", "world"]; String[] strs = {"apple", "orange"}; doSomething[strs]; // invoke varargs version } }
Notes:
- If you define a method that takes a varargs
String...
, you cannot define an overloaded method that takes aString[]
.- "varargs" will be matched last among the overloaded methods. The
varargsMethod[String, String]
, which is more specific, is matched before thevarargsMethod[String...]
.- From JDK 5, you can also declare your
main[]
method as:public static void main[String... args] { .... }Implicit Type-Casting for Method's Parameters
A method that takes a
double
parameter can accept any numeric primitive type, such asint
orfloat
. This is because implicit type-casting is carried out. However, a method that take aint
parameter cannot accept adouble
value. This is because the implicit type-casting is always a widening conversion which prevents loss of precision. An explicit type-cast is required for narrowing conversion. Read "Type-Casting" on the conversion rules.Method Overloading
In Java, a method [of a particular method name] can have more than one versions, each version operates on different set of parameters - known as method overloading. The versions shall be differentiated by the numbers, types, or orders of the parameters.
Example 1public class AverageMethodOverloading { public static void main[String[] args] { System.out.println[average[8, 6]]; System.out.println[average[8, 6, 9]]; System.out.println[average[8.1, 6.1]]; System.out.println[average[8, 6.1]]; //average[1, 2, 3, 4] } public static int average[int n1, int n2] { System.out.println["version 1"]; return [n1 + n2]/2; } public static int average[int n1, int n2, int n3] { System.out.println["version 2"]; return [n1 + n2 + n3]/3; } public static double average[double n1, double n2] { System.out.println["version 3"]; return [n1 + n2]/2.0; } }
The expected outputs are:
version 1 7 version 2 7 version 3 7.1 version 3 7.05Example 2: ArraysSuppose you need a method to compute the sum of the elements for
int[]
,short[]
,float[]
anddouble[]
, you need to write all overloaded versions - there is no shortcut.public class SumArrayMethodOverloading { public static void main[String[] args] { int[] a1 = {9, 1, 2, 6, 5}; System.out.println[sum[a1]]; double[] a2 = {1.1, 2.2, 3.3}; System.out.println[sum[a2]]; float[] a3 = {1.1f, 2.2f, 3.3f}; //System.out.println[sum[a3]]; } public static int sum[int[] array] { System.out.println["version 1"]; int sum = 0; for [int item : array] sum += item; return sum; } public static double sum[double[] array] { System.out.println["version 2"]; double sum = 0.0; for [double item : array] sum += item; return sum; } }
Notes:
- Unlike primitives, where
int
would be autocasted todouble
during method invocation,int[]
is not casted todouble[]
.- To handle all the 7 primitive number type arrays, you need to write 7 overloaded versions to handle each array types!
"
boolean
" MethodsA
boolean
method returns aboolean
value to the caller.Suppose that we wish to write a method called
isOdd[]
to check if a given number is odd./** * Testing boolean method [method that returns a boolean value] */ public class BooleanMethodTest { // This method returns a boolean value public static boolean isOdd[int number] { if [number % 2 == 1] { return true; } else { return false; } } public static void main[String[] args] { System.out.println[isOdd[5]]; // true System.out.println[isOdd[6]]; // false System.out.println[isOdd[-5]]; // false } }
This seemingly correct code produces
false
for-5
, because-5%2
is-1
instead of1
. You may rewrite the condition:public static boolean isOdd[int number] { if [number % 2 == 0] { return false; } else { return true; } }The above produces the correct answer, but is poor. For boolean method, you can simply return the resultant
boolean
value of the comparison, instead of using a conditional statement, as follow:public static boolean isEven[int number] { return [number % 2 == 0]; } public static boolean isOdd[int number] { return ![number % 2 == 0]; }Mathematical Methods
JDK provides many common-used Mathematical methods in a class called
Math
. The signatures of some of these methods are:double Math.pow[double x, double y] double Math.sqrt[double x] double Math.random[] double Math.sin[] double Math.cos[]The
Math
class also provide two constants:Math.PI Math.ETo check all the available methods, open JDK API documentation ⇒ select module "
java.base
" ⇒ select package "java.lang
" ⇒ select class "Math
" ⇒ choose method [@ //docs.oracle.com/javase/10/docs/api/java/lang/Math.html for JDK 10].For examples,
int secretNumber = [int]Math.random[]*100; double radius = 5.5; double area = radius*radius*Math.PI; area = Math.pow[radius, 2]*Math.PI; int x1 = 1, y1 = 1, x2 = 2, y2 = 2; double distance = Math.sqrt[[x2-x1]*[x2-x1] + [y2-y1]*[y2-y1]]; int dx = x2 - x1; int dy = y2 - y1; distance = Math.sqrt[dx*dx + dy*dy];Exercises on Methods
LINK
Command-Line Arguments
Java's
main[String[] args]
method takes an argument:String[] args
, i.e., aString
array namedargs
. This is known as "command-line arguments", which corresponds to the augments provided by the user when the java program is invoked. For example, a Java program calledArithmetic
could be invoked with additional command-line arguments as follows [in a "cmd" shell]:java Arithmetic 12 3456 +Each argument, i.e.,
"12"
,"3456"
and"+"
, is aString
. Java runtime packs all the arguments into aString
array and passes into themain[]
method asargs
. For this example,args
has the following properties:args = {"12", "3456", "+"} args.length = 3 args[0] = "12" args[1] = "3456" args[2] = "+" args[0].length[] = 2 args[1].length[] = 4 args[2].length[] = 1Code Example:
Arithmetic
The program
Arithmetic
reads three parameters form the command-line, two integers and an arithmetic operator ['+'
,'-'
,'*'
, or'/'
], and performs the arithmetic operation accordingly. For example,java Arithmetic 3 2 + 3+2=5 java Arithmetic 3 2 - 3-2=1 java Arithmetic 3 2 / 3/2=1public class Arithmetic { public static void main [String[] args] { int operand1, operand2; char theOperator; operand1 = Integer.parseInt[args[0]]; // Convert String to int operand2 = Integer.parseInt[args[1]]; theOperator = args[2].charAt[0]; // Consider only 1st character System.out.print[args[0] + args[2] + args[1] + "="]; switch[theOperator] { case ['+']: System.out.println[operand1 + operand2]; break; case ['-']: System.out.println[operand1 - operand2]; break; case ['*']: System.out.println[operand1 * operand2]; break; case ['/']: System.out.println[operand1 / operand2]; break; default: System.out.printf["%nError: Invalid operator!"]; } } }
Exercises on Command-Line Arguments
LINK
[Advanced] Bitwise Operations
Bitwise Logical Operations
Bitwise operators perform operations on one or two operands on a bit-by-bit basis, as follows, in descending order of precedences.
Example
OperatorModeUsageDescriptionExample ~ Unary ~x
Bitwise NOT [inversion] & Binary x & y
Bitwise AND | Binary x | y
Bitwise OR ^ Binary x ^ y
Bitwise XOR public class TestBitwiseOp { public static void main[String[] args] { int x = 0xAAAA_5555; // a negative number [sign bit [msb] = 1] int y = 0x5555_1111; // a positive number [sign bit [msb] = 0] System.out.printf["%d%n", x]; // -1431677611 System.out.printf["%d%n", y]; // 1431638289 System.out.printf["%08X%n", ~x]; // 5555AAAAH System.out.printf["%08X%n", x & y]; // 00001111H System.out.printf["%08X%n", x | y]; // FFFF5555H System.out.printf["%08X%n", x ^ y]; // FFFF4444H } }
Compound operator
&=
,|=
and^=
are also available, e.g.,x &= y
is the same asx = x & y
.Take note that:
'&'
,'|'
and'^'
are applicable when both operands are integers [int
,byte
,short
,long
andchar
] orboolean
s. When both operands are integers, they perform bitwise operations. When both operands areboolean
s, they perform logical AND, OR, XOR operations [i.e., same as logical&&
,||
and^
]. They are not applicable tofloat
anddouble
. On the other hand, logical AND [&&
] and OR [||
] are applicable toboolean
s only.System.out.println[true & true]; System.out.println[0x1 & 0xffff]; System.out.println[true && true];- The bitwise NOT [or bit inversion] operator is represented as '~', which is different from logical NOT [
!
].- The bitwise XOR is represented as
'^'
, which is the same as logical XOR [^
].- The operators' precedence is in this order:
'~'
,'&'
,'^'
,'|'
,'&&'
,'||'
. For example,System.out.println[true | true & false]; System.out.println[true ^ true & false];Bitwise operations are powerful and yet extremely efficient. [Example on advanced usage.]
Bit-Shift Operations
Bit-shift operators perform left or right shift on an operand by a specified number of bits. Right-shift can be either signed-extended [
>>
] [padded with signed bit] or unsigned-extended [>>>
] [padded with zeros]. Left-shift is always padded with zeros [for both signed and unsigned].
OperatorModeUsageDescriptionExample Binary x >> count
Right-shift and padded with sign bit [signed-extended right-shift] >>> Binary x >>> count
Right-shift and padded with zeros [unsigned-extended right-shift] Since all the Java's integers [byte, short, int and long] are signed integers, left-shift > operators perform signed-extended bit shift. Signed-extended right shift >> pads the most significant bits with the sign bit to maintain its sign [i.e., padded with zeros for positive numbers and ones for negative numbers]. Operator >>> [introduced in Java, not in C/C++] is needed to perform unsigned-extended right shift, which always pads the most significant bits with zeros. There is no difference between the signed-extended and unsigned-extended left shift, as both operations pad the least significant bits with zeros.
Examplepublic class BitShiftTest { public static void main[String[] args] { int x = 0xAAAA5555; // a negative number [sign bit [msb] = 1] int y = 0x55551111; // a positive number [sign bit [msb] = 0] System.out.printf["%d%n", x]; // -1431677611 System.out.printf["%d%n", y]; // 1431638289 System.out.printf["%08X%n", x1]; // D5552AAAH System.out.printf["%d%n", x>>1]; // negative System.out.printf["%08X%n", y>>1]; // 2AAA8888H System.out.printf["%08d%n", y>>1]; // positive System.out.printf["%08X%n", x>>>1]; // 55552AAAH System.out.printf["%d%n", x>>>1]; // positive System.out.printf["%08X%n", y>>>1]; // 2AAA8888 System.out.printf["%d%n", y>>>1]; // positive // More efficient to use signed-right-right to perform division by 2, 4, 8,... int i1 = 12345; System.out.println["i1 divides by 2 is " + [i1 >> 1]]; System.out.println["i1 divides by 4 is " + [i1 >> 2]]; System.out.println["i1 divides by 8 is " + [i1 >> 3]]; int i2 = -12345; System.out.println["i2 divides by 2 is " + [i2 >> 1]]; System.out.println["i2 divides by 4 is " + [i2 >> 2]]; System.out.println["i2 divides by 8 is " + [i2 >> 3]]; } }
As seen from the example, it is more efficient to use sign-right-shift to perform division by 2, 4, 8... [power of 2], as integers are stored in binary.
[More example on advanced usage.]
Types and Bitwise Operations
The bitwise operators are applicable to integral primitive types:
byte
,short
,int
,long
andchar
.char
is treated as unsigned 16-bit integer. There are not applicable tofloat
anddouble
. The'&'
,'|'
,'^'
, when apply to twoboolean
s, perform logical operations. Bit-shift operators are not applicable toboolean
s.Like binary arithmetic operations:
byte
,short
andchar
operands are first promoted toint
.- If both the operands are of the same type [
int
orlong
], they are evaluated in that type and returns a result of that type.- If the operands are of different types, the smaller operand [
int
] is promoted to the larger one [long
]. It then operates on the larger type [long
] and returns a result in the larger type [long
].Algorithms
Before writing a program to solve a problem, you have to first develop the steps involved, called algorithm, and then translate the algorithm into programming statements. This is the hardest part in programming, which is also hard to teach because the it involves intuition, knowledge and experience.
An algorithm is a step-by-step instruction to accomplice a task, which may involve decision and iteration. It is often expressed in English-like pseudocode, before translating into programming statement of a particular programming language. There is no standard on how to write pseudocode - simply write something that you, as well as other people, can understand the steps involved, and able to translate into a working program.
Algorithm for Prime Testing
Ancient Greek mathematicians like Euclid and Eratosthenes [around 300-200 BC] had developed many algorithms [or step-by-step instructions] to work on prime numbers. By definition, a prime is a positive integer that is divisible by one and itself only.
To test whether a number
x
is a prime number, we could apply the definition by dividingx
by 2, 3, 4, ..., up tox-1
. If no divisor is found, thenx
is a prime number. Since divisors come in pair, there is no need to try all the factors until x-1, but up to√x
.int maxFactor = [int]Math.sqrt[x]; assume x is a prime; for [int factor = 2; factor = b, the Euclidean algorithm is based on these two properties:1. GCD[a, 0] = a 2. GCD[a, b] = GCD[b, a mod b], where "a mod b" denotes the remainder of a divides by b.For example,
GCD[15, 5] = GCD[5, 0] = 5 GCD[99,88] = GCD[88,11] = GCD[11,0] = 11 GCD[3456,1233] = GCD[1233,990] = GCD[990,243] = GCD[243,18] = GCD[18,9] = GCD[9,0] = 9The Euclidean algorithm is as follows:
GCD[a, b] while [b != 0] { temp ← b b ← a mod b a ← temp } GCD is aBefore explaining the algorithm, suppose we want to exchange [or swap] the values of two variables
x
andy
. Explain why the following code does not work.int x = 55, y=66; x = y; y = x;To swap the values of two variables, we need to define a temporary variable as follows:
int x = 55, y=66; int temp; temp = y; y = x; x = temp;Let us look into the Euclidean algorithm,
GCD[a, b] = a
, ifb
is0
. Otherwise, we replacea
byb
;b
by[a mod b]
, and computeGCD[b, a mod b]
. Repeat the process until the second term is0
. Try this out on pencil-and-paper to convince yourself that it works.TRY: Write a program called
GCD
, based on the above algorithm.Exercises on Algorithm
LINK
Summary
This chapter covers the Java programming basics:
- Comments, Statements and Blocks.
- Variables, Literals, Expressions.
- The concept of type and Java's eight primitive types:
byte
,short
,int
,long
,float
,double
,char
, andboolean
; andString
.- Implicit and explicit type-casting.
- Operators: assignment [
=
], arithmetic operators [+
,-
,*
,/
,%
], increment/decrement [++
,--
] relational operators [==
,!=
,>
,>=
,>
].- Developing algorithm for solving problems.
Link to Java References and Resources
More References and Resources
- [MUST READ] "Code Conventions for the Java Programming Language" @ //www.oracle.com/technetwork/java/codeconvtoc-136057.html, or google the title, Sun Microsystems [now Oracle], 1999.
Chủ Đề