The purpose of this lab is to review the following basic Java concepts that should have been covered in your previous courses:
int
and
double
values and variablesjava.lang.Math
boolean
expressionsif
statementsString
sfor
loopsThis lab also introduces code testing using JUnit. This lab will be graded for style and correctness.
The API for the class that you need to implement can be found here.
A local copy of the Java API can be found here.
The style rules are not overly restrictive in EECS2030 but it is important that you
follow them;
we use a style checker for all of your submitted lab work. Most
jobs that involve programming will require their employees to follow
a rigid set of style rules.
1. Your programs should use the normal Java conventions (class names begin with an
uppercase letter, variable names begin with a lowercase letter,
public static final
constants should be in all caps, etc.).
2. In general, use short but descriptive variable names. There are exceptions to this rule; for example, traditional loop variables are often called i, j, k, etc.
Avoid very long names; they are hard to read, take up too much screen space, and are easy to mistype.
3. Use a consistent indentation size. Beware of the TAB vs SPACE problem: Tabs have
no fixed size; one editor might interpret a tab to be 4 spaces and
another might use 8 spaces. If you mix tabs and spaces, you will
have indenting errors when your code is viewed in different editors.
4. Use a consistent brace style:
// left aligned braces class X { public void someMethod() { // ... } public void anotherMethod() { for (int i = 0; i < 1; i++) { // ... } } }
or
// ragged braces class X { public void someMethod() { // ... } public void anotherMethod() { for (int i = 0; i < 1; i++) { // ... } } }
5. Insert a space around operators (except the period ".").
The following
// some code somewhere boolean isBetween = (x > MIN_VALUE) && (x > MAX_VALUE); int someValue = x + y * z;
is much easier to read than this
// AVOID DOING THIS // some code somewhere boolean isBetween=(x>MIN_VALUE)&&(x>MAX_VALUE); int someValue=x+y*z;
6. Avoid using "magic numbers". A magic number is a number that appears in a program in place of a named constant. For example, consider the following code:
int n = 7 * 24;
What do the numbers
7
and
24
mean? Compare the code above to the following:
final int DAYS_PER_WEEK = 7; final int HOURS_PER_DAY = 24; int n = DAYS_PER_WEEK * HOURS_PER_DAY;
In the second example, the meaning of
7
and
24
is now clear (better yet would be to also rename
n
).
Not all numbers are magic numbers. You can usually use the values
0
,
1
, and
2
without creating a named constant. If you ever find yourself doing
something like:
final int TEN = 10;
then you are probably better off using
10
and explaining its meaning in a comment.
7. A good IDE (integrated development environment) such as eclipse will correct many style errors for you. In eclipse, you can select the code that you want to format, right click to bring up a context menu, and choose Source -> Format to automatically format your code.
These instructions assume that you have completed the previous step (Hello, world), and you are working in the Prism lab.
Start eclipse by typing
eclipse &
into a terminal, or by using the menu located in the bottom left corner of the screen.
In this lab, you will import an existing project rather than starting everything from scratch. In the eclipse
File menu, choose the
Import... menu item.
In the
Import dialog box that appears, choose the
Existing Projects into Workspace item and click
Next:
If you are working on a Prism lab computer:
Click on the
Select archive file radio button.
Click on the
Browse... button and select the file
/eecs/dept/www/course/2030/labs/lab0/EECS2030_LAB0W20_student.zip
. Click the
Finish button to import the project:
If you are NOT working on a Prism lab computer:
Download the
following zip file. Click on the
Select archive file radio button. Click on the
Browse... button and select the file that you just downloaded. Click the
Finish button to import the project.
On the left-hand side of the eclipse window, you will see a tab labeled
Package Explorer. Use the small triangles to expand the
EECS2030_LAB0W20_student contents, then the
src contents, and finally the
eecs2030.lab0 contents. Double-click on
lab0.java
and
lab0test.java
to open these files in the editor:
lab0test.java
is a test class that contains unit tests for all of the methods that you will implement in this lab. You will learn
more about unit tests in your next lecture. For now, all you need to know is that you can use the test class to check
for errors in the methods in
lab0.java
.
Click on the
lab0test.java
tab in the editor window to view the contents of
lab0test.java
. Run the test class by pressing the green run button indicated by the red arrow in the figure below:
The results of running the tests are shown to you in the
JUnit
tab located on the left-hand side of the eclipse window (see figure above). Notice that all of the tests have a blue or red x beside
them; the blue x indicates that the test has failed and the red x
indicates that the test does not compile. In the
Failure Trace
panel, some diagnostic information is shown to you. For the
test00_one
test, the diagnostic information is indicating that the test expected a value of
1
but received a value of
0
. It seems like there is something wrong with our implementation of the
one
method.
Click on the
lab0.java
tab in the editor window to view the contents of
lab0.java
. Scroll down to the
one
method (the first method in the class). If you read the API for the method, you will see that the method postcondition
promises to return the value
1
. However, when you examine the body of the method, you will see that the method returns
0
, which is obviously incorrect.
Edit the return value of the method so that it returns the correct value.
Click on the
lab0test.java
tab in the editor window to view the contents of
lab0test.java
. Re-run the test class; you should see the following:
Notice that the test
test00_one
now has a green check mark beside it indicating that the test has passed. In some cases, you
will have some tests as failing test.
In the remainder of this lab, you will use the test class to help you fix the remaining methods in the
lab0
class. Follow the remainder of the lab to review some fundamentals of the Java language and complete the exercises
in the pink sections.
In Java, all values have a type. A type defines a set of values and the operations that can be performed using those values.
Java's primitive types are those types that are predefined by the Java language and are named by a reserved keyword. The primitive types are all numeric types and one type representing true/false values.
int
The
int
type represents integer values in the range -2
31 to (2
31 - 1). Java will interpret any number not having a decimal
as being an
int
value.
The following is an example of a (not very useful) method that always returns the
value of
1
. The method creates an
int
variable named
result
, assigns the variable a value of
1
, and returns the value of the variable:
public static int one() { int result = 1; return result; }
Constant values important to the
int
type can be found in the class
java.lang.Integer
.
double
The
double
type represents real values in the approximate range of -1.7 ×
10
308 to 1.7 × 10
308. Java will interpret any number having a decimal as being
a
double
value.
The following is an example of a (not very useful) method that always returns the
value of
0.5
. The method creates a
double
variable named
result
, assigns the variable a value of
0.5
, and returns the value of the variable:
public static double oneHalf() { double result = 0.5; return result; }
Constant values important to the
double
type can be found in the class
java.lang.Double
.
Java provides several operators for performing arithmetic operations using
int
and
double
values:
Assume that you have the following declarations for each example in the table below:
int x = 14; int y = -7; double u = 2.5; double v = -0.9;
Operator | Name | Example | Value |
+ | unary plus operator |
+x +y +u +v |
14 -7 2.5 -0.9 |
- | unary minus operator |
-x -y -u -v |
-14 7 -2.5 0.9 |
* | multiplication operator |
x * y u * v |
-98 -2.25 |
/ | division operator |
x / y u / v |
-2 -2.7777777777777777 |
% | remainder (after division) operator |
x % y u % v |
0 0.7 |
+ | addition operator |
x + y u + v |
7 1.6 |
- | subtraction operator |
x - y u - v |
21 3.4 |
Note that there is no exponentiation operator.
Java arithmetic obeys the same order of operations as regular arithmetic. Parentheses can be used in the same way as regular arithmetic to control the order of operations. For example, the following method computes the value of $\frac{1}{1 + x}$
public static double f_of_x(double x) { double result = 1.0 / (1.0 + x); return result; }
int
division
Any arithmetic operation involving two
int
values always produces another
int
value. Dividing two
int
values in Java produces the same result as dividing the two values
as real numbers and discarding the fractional part of the result;
an exception is thrown when dividing by
0
:
Expression | True Division | Java Division |
6 / 2 | 3 | 3 |
7 / 3 | 2.33... | 2 |
1 / 2 | 0.5 | 0 |
-9 / 5 | -1.8 | -1 |
3 / 0 | ∞ | ArithmeticException |
A common usage of
int
division is when you want to evenly distribute a number of whole
items between a number of groups.
/** * Returns the number of whole items each person receives * after distributing nItems evenly between nPeople. */ public static int perPerson(int nItems, int nPeople) { int result = nItems / nPeople; return result; }
int
remainder
Java provides the remainder after division operator
%
. For two
int
values
x
and
y
, the value of
x % y
is the
int
value equal to the remainder after dividing
x
by
y
:
Expression | Java result |
6 % 2 | 0 |
7 % 3 | 1 |
1 % 2 | 1 |
-9 % 5 | -4 |
9 % -5 | 4 |
3 % 0 | ArithmeticException |
The sign of the result is defined to be equal to the sign of the first operand (the
value to the left of the
%
operator).
A common usage of
int
remainder is when you want to evenly distribute a number of whole
items between a number of groups.
/** * Returns the number of whole items remaining * after distributing nItems evenly between nPeople. */ public static int remainder(int nItems, int nPeople) { int result = nItems % nPeople; return result; }
Complete the methods
isDivisiable(int n).
Note that you can consult the API to read the documentation for all of the methods.
Run the JUnit tester after you complete each method to check your work.
Complete the methods
isPrime(int n)
.
Consult the API to read the documentation for this method.
Run the JUnit tester after you complete each method to check your work.
Complete the methods
gaussian(double x, int sigma)
.
Run the JUnit tester after you complete each method to check your work.
Complete the methods
contains(int[] arr, int a)
.
Run the JUnit tester after you complete each method to check your work.
int
and
double
Be careful when using
int
values to compute a
double
value. For example, suppose that you compute the fractional value
one-third like so:
double oneThird = 1 / 3; // results in 0.0
Java uses the types of the operands to determine what version of an operator to use.
In this case, the
1
and the
3
are both
int
literals; therefore, Java uses
int
division to compute the value of
1 / 3
before converting the computed value to
double
and assigning it to
oneThird
.
The solution is convert one or both of the operands to
double
to force Java to use floating-point division (the type of division
performed when at least one of the operands has type
double
or
float
); any of the following will work:
double oneThird = 1.0 / 3;
double oneThird = 1 / 3.0;
double oneThird = 1.0 / 3.0;
double oneThird = (0.0 + 1) / 3;
double oneThird = (double) 1 / 3;
java.lang.Math
Mathematical functions such as exponentiation, trigonometric functions, roots, and
others are provided by methods in the
java.lang.Math
class. This class also provides mathematical constants such as $e$
and $\pi$ and many other useful methods relating to basic mathematics
operations.
Humidex is an index to indicate how hot the weather feels to the average person when there is some humidity. For example, if the temperature on a humid day is 30 degrees and the humidex is 40 then it means that it feels similar to a dry day where the temperature is 40 degrees. The Humidex formula used by Environment Canada when the air temperature in degrees Celcius is $T_a$ and the dewpoint temperature in degrees Celcius is $T_d$ is:
$T_a + 0.5555(6.11 e^{5417.7530(\frac{1}{273.16} - \frac{1}{T_d + 273.16})} - 10)$
Observe that the implementation uses named constants instead of plain magic numbers to maintain good readability. If we knew what the various constants represented then we would have chosen more descriptive names for the constants.
public static double humidex(double airTemp, double dewPoint) { final double A = 0.5555; final double B = 6.11; final double C = 5417.7530; final double D = 273.16; final double E = 10.0; double power = C * (1 / D - 1 / (dewPoint + D)); return airTemp + A * (B * Math.exp(power) - E); }
Java's primitive type for representing values that can be
true
or
false
is named
boolean
. One way to generate a
boolean
value is to compare two numeric values. Java provides the following
equality and comparison operators for numeric values:
Expression | Meaning |
x == y | is the value of
x equal to the value of
y
|
x != y | is the value of
x not equal to the value of
y
|
x < y | is the value of
x less than the value of
y
|
x > y | is the value of
x greater than the value of
y
|
x <= y | is the value of
x less than or equal to the value of
y
|
x >= y | is the value of
x greater than or equal to the value of
y
|
An integer is even if the remainder after dividing by
2
is equal to
0
. A method that determines if an integer is even could be implemented
like so:
public static boolean isEven(int x) { int remainder = x % 2; boolean result = (remainder == 0); // is remainder equal to zero? return result; }
Complete the method
maximum (int[] arr)
.
Run the JUnit tester after you complete each method to check your work.
boolean
values can be combined to produce a new
boolean
value using boolean algebra. In boolean algebra, the basic operations
are AND, OR, and NOT, and the corresponding Java operators are:
boolean operation | Java operator |
AND | && |
OR | || |
NOT | ! |
Use the AND operator
&&
to determine if two
boolean
values are both true. For example, if you want to determine if a
number
x
is greater than both
y
and
z
you could write:
boolean result = (x > y) && (x > z); // is x greater than y and is x greater than z
The parentheses are not necessary because
&&
has lower precendence than the comparison operators, but are included
in the example to help readability.
Use the OR operator
||
to determine if at least one of two
boolean
values are both true. For example, if you want to determine if a
number
x
is greater than either
y
or
z
you could write:
boolean result = (x > y) || (x > z); // is x greater than y or is x greater than z
Again, the parentheses are not necessary.
The NOT operator
!
negates a
boolean
value. Consider the following:
boolean isEqual = (x == y); boolean isNotEqual = !isEqual;
In the example,
isEqual
is
true
if
x
and
y
have the same value, and
false
otherwise. The value of
isNotEqual
is
true
if
x
and
y
have the different values, and
false
otherwise.
Complete the method
reverseOf (int[] inputarray)
.
Run the JUnit tester after you complete each method to check your work.
if
statement
Java's
if
statement lets you choose to execute a block of code depending on
a
boolean
value. For example, the following method uses an
if
statement to validate an input to the method:
public static double circleCircumference(double radius) {
if (radius < 0.0) {
radius = -radius; // make the radius positive
}
return 2.0 * Math.PI * radius;
}
The method in the above example computes the circumference of a circle given a radius.
The method first checks if the value of
radius
is negative; if
radius
is negative, the code inside the block of the
if
statement is run (shown in red). The code inside the block simply
converts the value of
radius
to the correct positive value. If
radius
is not negative, then the block in red does not run. Whether
or not the block in red runs, the value of the circumference
is computed and returned.
Instead of correcting the negative radius value, we might have chosen to indicate that an error has occurred by throwing an exception:
public static double circleArea(double radius) {
if (radius < 0.0) {
throw new IllegalArgumentException("negative radius");
// method stops running here because an exception was thrown
}
return Math.PI * radius * radius;
}
The method in the above example computes the area of a circle given a radius. The
method first checks if the value of
radius
is negative; if
radius
is negative, the code inside the block of the
if
statement is run (shown in red). The code inside the block creates
an
IllegalArgumentException
object and throws the exception. Throwing the exception causes
the method to stop running immediately. If
radius
is not negative, then the block in red does not run, and the
area is computed and returned.
if-else
statement
An
if-else
statement causes exactly one of two separate blocks of code to run
depending on a
boolean
value. For example, the following method computes the minimum of
two values using an
if-else
statement:
public static int min2(int x, int y) { int min; if (y < x) { min = y; } else { min = x; } return min; }
In the above example, the red block is run if the value of
y
is less than the value of
x
; otherwise, the block in blue is run. After the red or blue block
runs, the value of
min
is returned.
Complete the methods
contains1(double x, Range range)
and compareTo(Range r1, Range r2)
.
Remember to consult the API for Range to see how to use a Range object.
Run the JUnit tester after you complete each method to check your work.
if-else
statement
In situations where exactly one of several blocks of code must run, you can chain
multiple
if-else
statements together:
public static int contains2(double x, Range range) { int result; if (x <= range.getMinimum()) { result = -1; } else if (x >= range.getMaximum()) { result = 1; } else { result = 0; } return result; }
The example code above determines if a value
x
lies to the left of a
Range
, the right of a
Range
, or is strictly inside the
Range
. The red block is run if
x
is less than or equal to the minimum value of the range, otherwise
the blue block is run if
x
is greater than or equal to the maximum value of the range, otherwise
the purple block is run. After the red, blue, or purple block runs,
the value of
result
is returned.
Complete the method
hasValidLengthAndSeparator(String s)
.
Run the JUnit tester after you complete each method to check your work.
A
String
is a sequence of zero or more characters. A
String
can be written as a sequence of zero or more characters enclosed
by quotation marks:
String s = ""; // the empty string String t = "Hello";
The following method returns the title of this course as a
String
:
public static String getCourse() { return "EECS2030"; }
An important feature of Java strings is that once you create a
String
instance it is impossible to change its sequence of characters.
This is because the
String
class provides no
mutator methods (methods that mutate, or modify, the state of
a
String
instance). If you need to change the sequence of characters of a
String
, you must create a new
String
instance.
Complete the methods
sort2(List
and toRadians(List
.
Run the JUnit tester after you complete each method to check your work.
Two
String
instances can be joined, or
concatenated, using the
+
operator; this results in a new
String
instance. For example, the string
"Hello, world"
could be created by concatenating three strings like so:
String u = "Hello" + ", " + "world";
The following method returns the title of this course and the course name separated by a space:
public static String getCourseWithName() { return "EECS2030" + " " + Lab0.getCourseName(); }
The following method returns the title of this course and the course name separated
by a user-defined separator
String
:
public static String getCourseWithName(String separator) { return "EECS2030" + separator + Lab0.getCourseName(); }
Complete the method
toString(Range r)
. The API for the method defines what the string returned by the
method should be equal to.
Run the JUnit tester after you complete each method to check your work.
Individual characters can be retrieved from a
String
using an integer index. The first character has an index of
0
, the second character has an index of
1
, and so on. The last character of a
String
having
n
characters is
(n - 1)
. For example, the characters of the string
"abcd"
have the following indices:
Index | Character |
0 | 'a' |
1 | 'b' |
2 | 'c' |
3 | 'd' |
The
String
method
charAt(int index)
returns the character at the given
index
. The following method returns the first character of a non-empty
string:
public static char firstChar(String s) { if (s.isEmpty()) { throw new IllegalArgumentException("string has length 0"); } return s.charAt(0); }
The
String
method
length()
returns the length (number of characters) of a string. The following
method returns the last character of a non-empty string:
public static char lastChar(String s) { if (s.isEmpty()) { throw new IllegalArgumentException("string has length 0"); } return s.charAt(s.length() - 1); }
Complete the method
shuffle(List
. Check out the API for details.
Run the JUnit tester after you complete each method to check your work.
for
loops
A
for
loop is used when you want to repeat a block of code a known number
of times. For example, the following method returns the string formed
by concatenating a specified string
n
times:
/** * Returns the string formed by concatenating the string s n times. * For illustration purposes only; you should use a StringBuilder * instead of repeated concatenation. */ public static String repeat(String s, int n) { String result = ""; for (int i = 0; i < n; i++) { result = result + s; } return result; }
The
for
statement has three parts:
boolean
expression that is evaluated at the beginning of each iteration.
If the logical expression evaluates to
true
the loop body runs, otherwise the loop stops. The logical expression
usually, but not always, involves the loop variable.
In the above example, the:
int
loop variable named
i
that represents a counter that counts how many times the loop
has run
i
to
n
the number of times that the string should be concatenated.
If
i
is less than
n
, then the loop runs.
If you trace through the above loop using a list of $n$ elements, you'll see that
the value of the loop variable
i
follows the sequence
0, 1, 2, ..., (n - 1)
.
In a terminal, navigate to the directory containing your
lab0.java
file. If you have been following all of the steps in this lab in
sequence then you should be able to type the following into a terminal:
cd cd eecs2030 cd EECS2030_LAB0W20_student/src/lab0package
Recall that:
cd
on its own changes the current directory to your
home directory
cd eecs2030
changes the current directory to the workspace directory you
created for
HelloWorld.java
cd EECS2030_LAB0W20_student/src/lab0package
changes the current directory to the
lab0package
package for the project
EECS2030_LAB0W20_student
Assuming that the above works, you can submit your work by typing:
submit 2030 lab0 lab0.java
which submits your
lab0.java
file. If your file is successfully submitted, then you will first see
the message
All files successfully submitted. If something
is wrong with your submission (e.g., the file name is not existing), you will see a detailed error message
explaining what is wrong with your submission.
If you want to check which files you have submitted you can use the command:
submit -l 2030 lab0
where
-l
is the hyphen followed by a lowercase ell (not the digit one). Lab
0 is complete once you have submitted
lab0.java
It is possible to submit work from outside the Prism lab, but the process is not trivial; do not attempt to do so at the last minute if the process is new to you. The process for submitting from outside of the Prism lab involves the following steps:
cd
) the directory where the newly transferred files are located, submit using the instructions for submitting from within the lab
Windows users will likely need to install additional software first. Mac users have all of the required software as part of MacOS.