Session 2: Expressions and loops

Operators (Section 2.7)
    Binary operators
    Type issues
    Unary operators
    Assignment operators
Comparisons (Section 4.1)
    Inequality operators
    Equality operators
The while statement (Section 4.6)
    Loops
    Counting loops
Using methods (Section 2.9)

Operators

Textbook: Section 2.7

Binary operators

You can build up expressions in Java using operators. For now, we'll look at just five operators:

+addition
-subtraction
/division
*multiplication
%remainder / modulus

You can use these in your assignment statements. Consider, for example, the following segment of code.

int i = 5;
int j = 2 * i + 1;
IO.println(j);
When the computer runs the second line, it computes 2*i+1. Since i holds 5 at this point, this computation yields the number 2*5+1=11. Thus 5 goes into the memory that j refers to. And then the next line prints the value of j, so it displays 11.

Java observes the order of operations. Thus, 1+2*i means to multiply 2 by i first, and then add 1 to it. Of course you can override this using parentheses.

Type issues

When an operator has an integer expression on either side of it, it computes an integer. This means that when you divide two integers, you get an integer back!

So what's 1/2? The computer will perform the division and ignore any remainder. In this case, the division yields 0 with a remainder of 1, so 1/2 evaluates to the integer 0! You're bound to run into problems with this if you're not careful.

If either side of the operator is a double, the computer will compute a double result. So 1.0/2 gives the double value 0.5.

Unary operators

Java supports two unary operators.

+positive
-negative
By unary operator, I mean that they only take one number after them.
j = -(i - 1);
In this example, we've used the binary `-' operator to subtract 1 from i, and we've used the unary `-' operator to negate the result. Java distinguishes between the two based on context. (If i held the number 5, then this statement would put the number -4 into j.)

The unary + operator is useless. Java includes it for completeness only.

Assignment operators

Java provides some additional combination operators for convenience.

+=add and assign
-=subtract and assign
/=divide and assign
*=multiply and assign
%=modulo and assign
For example, consider the line
j *= i + 1;
Say i held 5 and j held 11. The computer would add i and 1, giving 6; it would multiply 11 by this, giving 66; and it would put this 66 back into j.

All the assignment operators rank below the arithmetic operators we already saw in the precedence hierarchy. So it's multiplication/division/modulus, followed by addition/subtraction, followed by the various assignment operators.

Comparisons

Textbook: Section 4.1

Thus far, we've seen operators grouped into four levels of precedence.

unary +, unary -highest precedence
*, /, %
binary +, binary -
=, +=, -=, *=, /=, %=lowest precedence
These operators all work with numeric values and produce numeric values. Today we'll see some boolean operators and see how they can be used to produce our first nontrivial programs.

The operators we'll examine in this section are the comparison operators, which exist for comparing two values together.

Inequality operators

Below the precedence level for addition and subtraction, and above the precedence level for assignment operators, are the inequality operators: <, >, <=, and >=. An inequality operator needs a numeric value on both sides of it, and it computes a boolean value.

For example, you might have the following in a Java program.

double x = 1.3;
double y = 2.1;
boolean is_lessthan = (x < y);
After this is executed, is_lessthan holds the boolean value true, since indeed 1.3 is less than 2.1. (The parentheses in this fragment are optional - the < operator has higher precedence than the assignment operator anyway. But I would include them just to make the program easier to read.)

Equality operators

Java also has operators for comparing two values: == for equality and != for inequality. (Oddly, Java uses the exclamation point to indicate NOT.) They actually fall below the inequality operators in the hierarchy.

unary +, unary -highest precedence
*, /, %
binary +, binary -
<, >, <=, >=
==, !=
=, +=, -=, *=, /=, %=lowest precedence

Notice that Java uses == (two equal signs!) for seeing if two numbers are equal. This operator takes two values and computes whether they are currently equal. This is very different from the assignment operator (one equal sign =), which actually alters the value of the variable named on its left.

Note: You should basically never use the equality operators in conjunction with doubles. The problem is that doubles will have some slight error. For example, if you subtract 1.1 from 1.2, the computer would compute the approximation 0.09999999999999987. So the expression

1.2 - 1.1 == 0.1
would be false! The proper way to do these tests is to see if the absolute value of the difference of the two numbers is small. You'll see how to compute the absolute value later...

The while statement

Textbook: Section 4.6

A computer needs to be able to do something repeatedly if it's going to be useful. We can do this in Java using the while statement.

Loops

A while statement looks like the following.

while(expression) statement
For example:
while(i * 2 < n) i *= 2;
Say i holds 1 and n holds 23 before the computer reaches this while statement. The computer then does the following steps.
  1. The computer checks whether i*2<n. Yes, it's true that 2<23, so the computer executes ``i *= 2;.'' The value of i is now 2.
  2. The computer checks whether 2*2<23. It's true, so the computer executes ``i *= 2;'' again. The value of i is now 4.
  3. The computer checks whether 4*2<23. It's true; the value of i becomes 8.
  4. The computer checks whether 8*2<23. It's true; the value of i becomes 16.
  5. The computer checks whether 16*2<23. That's false. So the computer is done with the while statement, and it continues to whatever follows.

If we want to repeat a sequence of several statements, you can use braces to combine them. The computer repeatedly checks whether the condition is true and then executes all the statements listed in the braces.

import csbsju.cs160.*;

public class WhileExample {
    public static void run() {
        int i = 1;
        int n = 23;
        while(i * 2 < n) {
            i *= 2;
            IO.println(i);
        }
    }
}
Notice how we indented the body of the while loop! This isn't necessary from the Java compiler's point of view, but it's good form, to keep the program less confusing. We will deduct points if you don't adhere to good form.

In this example, the computer would print the following.

2
4
8
16
Notice that, just before it prints 16, i*2<n is no longer true. But the computer prints the number anyway, since it checks the condition until all the statements (including the call to IO.println()) are done.

Counting loops

One particularly popular loop arrangement is to count. You'll see this sort of thing quite a bit.

int i = 1;
while(i <= 100) {
    System.out.print("Now I'm at ");
    System.out.println(i);
    i += 1;
}
This program counts from 1 to 100.

In fact, counting is so popular that Java provides some convenient abbreviations. One abbreviation is the ++ and -- operators to increment or decrement a variable.

int i = 1;
while(i <= 100) {
    System.out.print("Now I'm at ");
    System.out.println(i);
    i++;   // <-- Note the change to i++ in place of i += 1
}
This is slightly more convenient for those times when you want to do it.

Using methods

Textbook: Section 2.9

A method defines some actions to accomplish for a given set of inputs. These inputs are called arguments.

We've been using one method named IO.println quite a bit already.

IO.println(42);
IO.println takes a single argument - some piece of data which is to be displayed into the I/O window. In this case, the argument is the integer 42.

Java includes a variety of methods, split between many classes. For example, the Math class includes a method called Math.pow, which takes two double arguments and computes the first argument raised to the power of the second. This method has a return value - in this case, the result of the computation, which is itself a double.

double x = Math.pow(16.0, 0.5);
In this example, the computer computes 16.00.5 - that is, the square root of 16.0, which is 4.0. So 4.0 is what goes into the x variable.

You can call methods within expressions however you want.

IO.println(Math.pow(y + 1.0, 2.0) + Math.pow(y - 1.0, 2.0));
If y held the value 3, this would compute (3+1)2 + (3-1)2, and it would print that value (20.0) to the I/O window.

The Math class holds a variety of useful methods. You can read about them in the Java library documentation. You'll be using the library documentation quite a bit throughout this course, so it's good to get used to it now. There's a link on the CS160 Web page directly to it.

The IO class also holds many useful methods. We've been using the IO.print and IO.println methods already. But there are also methods for reading numbers from the user. For example, IO.readInt() will wait until the user types a number, followed by the Enter key, and then it will return the int value the user typed. The IO.readDouble() method works similarly.

Here's a program that converts Celsius temperatures typed by the user into Fahrenheit.

import csbsju.cs160.*;

public class Example {
    public static void run() {
        while(true) {
            IO.print("Celsius: ");
            double celsius = IO.readDouble();
            IO.print("Fahrenheit: ");
            IO.println(1.8 * celsius + 32);
        }
    }
}
If I ran this, then it would work as follows. (Boldface indicates characters the user typed.)
Celsius: 0
Fahrenheit: 32.0
Celsius: -40
Fahrenheit: -40.0
Celsius: 37.0
Fahrenheit: 98.6
Celsius: and so on
Since the while condition is always true, this program actually never quits; it will keep asking for more temperatures to convert until the window is closed (or somebody pulls the plug).