CSCI A201/A597

Lecture Notes 9

Spring 2000


Syntax and semantics revisited. Values, operators, expressions, variables, primitive types, objects, strings of characters. A word on the upcoming exams.

The practical exam will be on February 24-25. It will be closed-book, and you will have to write a working program during the interval of time that is allotted to the lab.

The program will be based on your assignment 3: Crossed.java. You will be asked to produce a scalable pattern such us the letters L, Z, X, E, F, I, T, M (all uppercase). The steps that you need to take to produce a working solution is to map your pattern on a two-dimensional grid of lines and rows, and use print and println as necessary to print it out.

The exam will be closed book, but an exhaustive range of patterns that you could see on the exam will be announced ahead of time with hints on how to map each pattern on the grid (if a pattern is complicated).

The midterm exam will be on March 2, in class. It will be a multiple-choice test, and to prepare you for it your next assignment (due February 18) wil be a battery of quizzes that you need to work with in QuizSite. The items on the midterm will be very similar to the items in this battery of on-line tests.

I will have another announcement next week, regarding the possibility of offering a special (more advanced) term project in exchange for the final exam. That is, we will make available a term project for those of you that are interested, such that if you complete that project you don't need to come and take the final exam, and the grade for the project will count as the grade for the final. Details forthcoming in a week.

Now we want to review some of the material that we have already covered and in the process add some more.

Primitive Types in Java

1. Whole Numbers (see page 12 in the book)

These are represented by the keywords:

We will work mostly with ints, unless otherwise specified. The difference between the four integral types is in the range of numbers that they can support. The int is able to represent integers between 231 - 1 (which is 2,147,483,647) and -231 (which is -2,147,483,648). This range is given by the size of the internal representation of numbers (in base two), a thing that won't be of great concern to us here.

So where can we make use of the int keyword in a Java program?

We use it to declare the type of a variable such as:

int n;
n is called an identifier (see page 10 in the book), since it is a name for a storage location that can store ints (that is whole numbers in the range that was mentioned before).

You can declare more than one variable at a time, for example:

int i, j;
You can't use a variable before it is declared. A variable is known to the program and can be used only after its declaration, but not before. and the first use of a variable in a program must be as the target of an assignment statement.

Let's look at some examples:

i = 0; 
int i, j;
j = 3;
won't work because i is used before it is declared.

A variable can only be declared once in a block.

int i; 
i = 3;
int i; 
won't work because i is declared twice. The first use of a declared variable must be as a target in an assignment. But the following won't work
int i; 
i = i + 1; 
because the first use of i will be as a term on the right hand side.

The bottom line of all this is that you need to initialize your variables as soon as you declare them. You can declare them in one line, as part of the declaration, like this:

int i = 0, j = 3;
Note that the Java compiler will identify situations when some variables may remain unitialized and thus signal an error. For example:
int i;
int j = Integer.parseInt(args[0]);

if (j % 2 == 0) { 
  i = 4; 
} 

i = i + 1; 
will signal an error. That is because when j is odd no initial value is stored in i and in those cases i couldn't be possibly incremented with 1.

Even if your user will be careful not to type an odd number it still is possible to call your program with such a number as the first argument on the command line, so the compiler will point this out and signal it as an error.

2. Operations on Whole Numbers

Here's a small table of operators:

Operator(s) Precedence Associativity
* / % 6 left to right
+ - 5 left to right
< <= >= > 4 left to right
== != 3 left to right
In an expression without parentheses the operators that have a higher precedence will be performed first. If all operators have the same precedence then the operations will be performed from left to right (that's what the left to right associativity means).

So, for example, the following expression

 n < n + 4 
evaluates to true since the addition will be performed first.

The expression:

7 % 3 * 2 
evaluates to 4 since the modulus operator has the same precedence (6) as the one for multiplication. Parentheses can be used to control the order of evaluation: expressions with parentheses are always fully computed before they are used in any larger expression (page 14). Thus
7 % (3 * 2)
evaluates to 1.

3. Numbers with decimals

These are represented by the keywords:

The difference is again in the size of the numbers that could be stored in a location (or variable) that is declared of type float as compared to one that is declared of type double (see page 19).

Our choice of numbers with decimals will be as doubles.

How do you use this keyword?

Same as we use int: we use it to declare variables of this type.

For example:

double x, y;
You can also initialize when you declare, as before:
double pi = 3.141592;
You can store a whole number in a double variable:
double a, b = 3; 
int n = 6;
a = n + 1; 
but you can't store a double in an int without loss of information (the decimal part will be lost).

To make sure you don't forget that Java wants you to make it explicit that you want to do the conversion. Here's how it looks:

double r = 6.3; 
int n; 
n = (int)r; 
The operation is called casting and is described on page 19 of your text.

4. Declarations Again

Remember that declarations can appear anywhere in the program, but that variables can be used only after they are declared. Given this it is better to declare all the variables that you plan to use at the top of your program.

Here's however an example in which we do not follow the rule simply to illustrate that from a testing point of view it is OK to declare a variable next to where you want to use it, if you use it in only one place (see the example in the next section).

Declaring variables inside blocks of statements grouped together by curly braces makes them invisible from outside the block. In the block however the variable will be known as soon as it is declared. We have encountered blocks of statements in if statements, while and for loops.

5. Operations on doubles

The operations that we have listed in section 2 above also apply for numbers represented as doubles (that have decimals). Even % is available to compute the portion of the value that is unaccounted for by the whole division (page 19).

Here's the example:

public class T {
    public static void main(String[] args) {
       double a, b = 3.2; // only b is initialized 
       int n = (int)b;    // n is set to 3 and 0.2 is lost 
       a = n + 1;         // a is set to 4.0 
       double q = b % 2;  // q declared and initialized to 1.2 
       System.out.println(a + " " + b + " " + n + " q = " + q); 
    } 
} 
Will print:
frilled.cs.indiana.edu%javac T.java
frilled.cs.indiana.edu%java T
4.0 3.2 3 q = 1.2000000000000002
frilled.cs.indiana.edu%
The last value shows that not all arithmetic is perfect with a computer.

6. The Math class

Pages 20-22 of your text describe a few functions that are available in the Math class. As I described in class last time classes, without which there can be no Java program, serve two distinct purposes:

The Math class is useful in that it offers methods that Section 2 in appendix D in your book (page 296) contains a description of what Math has to offer. You can also find this online.

7. Truth Values

There are only two truth values in Java: true and false.

These values can be assigned to variables declared as boolean, such as:

boolean done = false;
Truth vales usually come out of conditions, such as:
done = (i > 11);
Here's an example:
public class T {
  public static void main(String[] args) {
    int n = 10; 
    boolean double = false; 
    while (! done) {
      System.out.println(i); 
      i = i + 1; 
      if (i > n) {
        done = true; 
      } 
    } 
  } 
} 
8. Operators on booleans

Table 1.6 in your book contains then results of applying various boolean operators on two boolean values P and Q. The operators listed are:

Operator(s) Precedence Associativity
! 7 left to right
== != 3 left to right
&& 2 left to right
|| 1 left to right
This essentially adds to the table presented in section 2. If we put them together it will start looking more and more like the table on page 14 of your text, number 1.3. Notice also that one line appears in both tables, the one that compares the values for equality.

Regarding the definitions of && (logical and) and || (logical or) we can summarize them as follows:

Negation (!) simply changes the truth value.

As an example, assume the following boolean expression

  n < 10  &&  n > 3   ||   m < 20  &&  m > 16
where n and m are ints.

Given the order of precedence of the operators and their associativity the expression listed above will evaluate in the following way (where the order of evaluation is not changed, only made explicit by the parentheses).

 (n < 10) && (n > 3)  ||  (m < 20) && (m > 16)
that is
((n < 10) && (n > 3)) || ((m < 20) && (m > 16))
In this example the two operators of precedence 4 (< and >) need to be evaluated first. Then the ones that have precedence 2 (&&) will be evaluated first over the one that has precedence 1 (||).

There are additional examples in the book on pages 24-27.

9. Characters

The keyword that describes this primitive type is char.

The characters are listed at the end of the book on page 290 (section 4 of appendix B). They are listed in a certain order and then numbered. This is not just any order, it is the American Standard Code for Information Interchange (ASCII) and so it's used by many people not just us. The ASCII code for uppercase A is going to be 65 everywhere in the world.

To identify character constants we use single quotes:

char grade;
grade = 'A'; 
will assign uppercase A to the char variable with the name of grade.

A few special (unprintable) characters have a special representation in terms of the characters that we normally think as printable. For example the character with ASCII code 10 (newline), that is represented as an escape sequence: '\n' (that is, backslash followed by lowercase n).

A few more are listed in figure 1.5 in your book (page 24) and in appendix B.

Because of this mapping of characters into numbers many things that we can do with (whole) numbers can also be done with characters. Such as:

char grade;
grade = 'A'; 
grade = (char)(grade + 1); 
System.out.println(grade); 
that prints B (uppercase B). The example above shows that used in a numeric context the character is converted into its ASCII numeric code. Internally characters are stored as their ASCII codes.

You can however add two characters and obtain a third one.

char r = (char)(' ' + '!'); 
System.out.println(r);
will print A (uupercase A). If you subtract characters you obtain the difference between their ASCII codes, so by symmetry we could use this as follows:
char rank = '0' + 3;
will place '3' in rank since its ASCII code is 51 (3 bigger than the code for 0).

Thank means that the example above which prints B could be simplified as follows:

public class T2 {
    public static void main(String[] args) {
        char grade = 'A' + 1; 
	System.out.println(grade);
    } 
}
So using a character constant in an addition forces the result to be a character.

Please check this section in the book on pages 22-23.

10. Strings of Characters

Strings are widely used in Java programs ut they are not a primitive type. Strings are objects.

Strings are presented in your book briefly in section 1.4.1 (pages 29-30) and then in one entire chapter 5. The part in chapter 1 covers this:

Regarding this last one operation it is mentioned (page 30, second paragraph) that you should not be comparing Strings for equality with ==.

Instead the equals method of one of the operands should be used with the other operands as an argument. It will return a truth value that will signifiy whether the two strings ofd characters read the same (capitalization and spaces included).

So we could have a code fragment like this:

String a = "George Boole"; 
String b = "George " + "Boole"; 
boolean test1, test2, test3;
test1 = a.equals(b); 
test2 = b.equals(a); 
test3 = a.equals("George" + " Boole");
All three boolean variables will be set to true.

Sections 5.1.1 and 5.1.2 present a few more methods that Strings understand. (Invoking a method on an object is as if we'd be sending a message to that object, with some parameters that qualify our message).

Let's summarize them here briefly:

charAt(i)
returns the (i+1)thcharacter of the string (note that the indexing is again 0-based)

length()
returns the number of characters in the String

substring(i)
returns the portion of the original String that starts with character i (remember that the indexing is 0-based)

substring(i, j)
returns the string of character between positions i and j - 1 inclusively
Examples are presented in the sections mentioned above, but please read knowing that they are given in the context of knowing how to define your own methods so you may need to skip some text to look over only the examples.

11. Syntactic Hazards

We conclude by saying that a sequence of zero or more instructions enclosed by a pair of curly braces ({ and }) is a valid Java construct called a block of statements.

The syntax for an if statement (chapter 3, pp. 72-74) can be described like this:

if (<condition>) 
  <statement>
The parts in angle brackets are syntactic categories.

We need to define them or we can't put such an if into valid Java program.

For <condition> think of any expression that you could build using numbers or int variables compared to each other, as well as boolean combinations of these, as seen in the example that was testing whether both m and n where in some range, a few paragraphs above (meant to illustrate the order of evaluations).

For <statement> we can either use

Notice then that
int i = 3, j = 2; 
if (i < j) 
  System.out.print(i + "is less");
  System.out.println(" than " + j); 
will print
 than 2
because the then branch of the if statement is composed of only the first of two (despite the indentation) print statements.

To add them both to the then branch we need to group them in a block:

int i = 3, j = 2; 
if (i < j) { 
  System.out.print(i + "is less");
  System.out.println(" than " + j); 
} 
There is another frequently seen mistake in which the while loop is memorized with an incorrect syntax, and that is with a semicolon after the condition. You should never use that form, unless you are very experienced and do all the work of the loop in the condition (presumably through one or more function invocations). The resulting construct transforms into a loop with an empty body, followed by a block of statements. Since your condition is fairly simple it will never change and the loop will either never be executed (if the condition starts out being true) or will turn into an infinite loop otherwise.


Last updated on February 8, 2000 by Adrian German