Learn Programming in Java

<<Previous | ToC | Next >>

Lesson #2: Variables & Expressions

Now we can learn how to tell a computer to do arithmetic, and how it remembers things while a program is running. After your program stops, everything it knows is gone, except for whatever is saved in a disk file -- but we called that "output". As we shall see (but not today), input and output hide under a mask of many colors.

In programming-speak, a "variable" is a place in the computer memory that holds a number that can change value during the course of running. Everything is numbers, but it helps us to think clearly about what we are doing if we pretend that some things are not numbers, and Java helps us carry out the pretense. So the first kind of variable you will learn about doesn't look like a number at all.

Remember your "Hello world" message, which we enclosed inside quotes? As in English, the quotation marks surround a sequence of text characters that should be understood literally, that is, that exact sequence of characters -- letters, numerals, spaces, most anything you can type on the keyboard, if you can see it on the screen it counts as a valid character inside quotes. It's called a "string" like a string of beads or pearls in a necklace, which are constrained to be in a particular order by the thread running through them. Try a few different character strings and see what happens. Obviously, if you try to include a (double) quote mark, the computer (or rather the Java compiler) will mistake it for the end of the text string, and refuse to compile the program. Try it.

So what are we to do, if we want a quote inside the string? Programmers are an anarchistic lot, we don't want to be told "You can't do that," so the people who invented the C programming language -- and this is the same as Java, which mostly copied everything that C does, except for some of the mistakes -- chose one of the characters on your keyboard that almost never gets used in real life, the backwards slant "\" and made it magic, different from the other characters. It's called an "escape" character, because lets you briefly escape from the usual rules for text strings when you use it. Everything else (obviously except the quote), when you use it inside a text string means just that letter or character and nothing more, but if you put a back-slant next to it on the left, then it takes on new meaning. A back-slant followed by a quote means the quote is not the end of the string, but is used as a real character in the text. Try this variation on your HelloWorld program:

System.out.println("Hello \"World\"!");

Notice the two back-slants, each immediately followed by a quote. That means that those quotes will be printed as part of the text.. The third quote has no back-slant next to it, so it's the normal end of the string. Try it. What happens if you put a back-slant next to another back-slant? Try it:

System.out.println("Hello \\ World!");

The first back-slant is an escape, which tells the compiler that the next character should be taken literally as a character in the text (so it prints), just like it did with the quote. Except for certain letters, back-slant does that for almost everything, although obviously most characters don't need it.

I told you about programmers who don't want to be told "You can't do that," not even when it comes to using non-printing characters in their text strings. Take for example the tab key. As far as the keyboard is concerned, it's just another number: every key on the keyboard sends a number to the computer, and the operating system understands those numbers as letters and other characters. For example, "a" is the number 97, space is 32, and the tab key is 9. What if I want a tab in my text string? Tab usually means to move to the next field, or to inserts (possibly multiple) spaces, or something non-text like that. Enter the back-slant as an escape again, but this time it tells the compiler that the letter "t" after the back-slant is  to be understood as a tab character, not a letter. Other escaped letters are "\b" for backspace, "\n" for newline, and "\r" for the return key (but most modern keyboards print the label "Enter" on that key). Mostly you don't need these control characters in your text strings, but that's how they are spelled, in case you do.

Different operating systems treat return (13) and newline (10) differently, so it's best not to try to embed them in strings for printing. Instead Java gives us a programmatic way to put a new line into the output text. We have been using println to output a single line; you could also use "print" (without the "ln") and it does not start a new line. Try it. You won't see an obvious difference unless you put two print statements in your program, then you can see them print their output on the same line. Try it.


All that to explain text strings, which can be much more powerful than just immediately printing. Back to our one-line program, let's modify it to print out "John sees Mary."
System.out.println("John sees Mary.");

That's so boring. Suppose we want to say Mary also sees John, but we don't want to retype the whole line. This is where variables are useful. I mentioned that a variable is a place in the computer to remember a number. A string does not look like a number, but deep down inside, that's what it is. You don't need to know that, only that if you tell Java that a value is a "String" then it knows that you can put text there. Variables are generally given names, which start with a letter and can have any number of letters and digits (but no spaces, we use the underscore "_" to look like a space); we try to use names that remind us what the variable means to us people, without being so long it a pain to type the whole name. Temporary variables might just be named by a single letter, like x. Java needs to know that the variable is a String (which is spelled with a capital letter, because Java cares about the difference. So I'm going to cut up my English sentence into three words, then print out two lines, in different order. This is more typing (or a single copy/paste ;-) all within the same white panel inside the yellow block:

String j = "John";
String m = "Mary";
System.out.print(" sees ");
System.out.print(" sees ");

Notice that there are no quotes around the "j" in the first print statement. We don't want to print the letter "j" but rather the contents of the variable with that name. The second time around, the variables still have the names of our people, but the English sentence is printed in a different order. But that's a lot of typing. Instead we can do it in two println's, where the value to be printed is made up by "adding" (actually concatenating) the pieces together, like this:

String j = "John";
String m = "Mary";
System.out.println(j + " sees " + m + ".");
System.out.println(m + " sees " + j + ".");

Now comes the fun part. Change only the first line, so it says

String j = "Bill";

What do you think it will do? Try it. We did not change the name of the variable, only the value in it. The rest of the program knows nothing of the value, it just prints whatever is the variable with that name. We can change it as often as we like (in separate statements) throughout the program. After the first println insert a new statement,

j = "William";
The first time the variable "j" is printed (before the line we added), it has the initial value "Bill", but then the value was changed, so the second time it printed the new value.

Notice that when we changed the value, we did not repeat the word "String". The first time you mention a variable in a program, you must tell Java what type it is (in this case "String"). This is called a declaration. After that you can use the variable's current value as often as you like, as we did when printing it. You can also change the value as often as you like with what is called an assignment statement, which is a variable name followed by the equal character followed by some value to put into that variable, and ending with a semicolon, somewhat like you did in Chomp, but spelled differently. Any valid string value can be put into the variable, for example:

String j = "John";
String m = "Mary";
j = j + " sees " + m;
System.out.println(j + ".");

It is important that you do not confuse the assignment operator with the mathematical notion of equality. The third line here should be read as "calculate a new string value by concatenating to the current contents of variable j the given literal string, and then concatenate on the current value of variable m and then put the resulting string value into variable j (discarding its previous value)." You can see how this works if you want to put the second println back in:

String j = "John";
String m = "Mary";
j = j + " sees " + m;
m = m + " sees " + j;
System.out.println(j + ".");
System.out.println(m + ".");

What do you think this will print out? Try it. Remember, by the time the computer gets around to assigning a new value to m, the variable j already has the new value given to it in the previous line. This kind of timing problem happens often, and we solve it with temporary variables, in this case "x":

String j = "John", m = "Mary", x; // one declaration, three variables created, two init
x = j + " sees " + m;             // assign to temporary 'x'
m = m + " sees " + j;
j = x;                            // use tempory value in 'x'
System.out.println(j + ".");
System.out.println(m + ".");

You will notice that I added some comments to some of the lines. Tiny programs like this, it's easy to remember what's going on, but when you are writing an interesting program involving thousands of lines stretched over months of work, it's really easy to forget a particularly clever piece of code. Besides, if you want other people to read and admire your code, you need to explain what you did. We try to put one statement per line, but sometimes a statement is too big and must be split. Your program is easier to read if you divide it up logically and indent subsidiary parts. Look at the examples I show you, or that you see online. If you are good enough to let people look at your code (or bad enough to need help), formatting your code the way other people do encourages them to not think of you as sloppy or worse. Your code is you, so make yourself presentable. It's like wearing clean clothes.

I also combined all the string declarations into one line, where each variable is separated from the next by a comma. The "String" type is specified once at the front of the line and applies to all the variables declared before the final semicolon. In this example I could have given an initial value to "x" instead of making a separate assignment; sometimes it's convenient one way, sometimes the other; both work. You do need to be careful to give a value (either by initializing it in the declaration, or else by subsequent assignment) before you try to use the value. Unlike Chomp, it is an error to try to use the value of a variable before it has a value, and the Java compiler usually will tell you about it, but sometimes the program only behaves strangely or crashes. Java programs "crash" by stopping with an error message, but other programming languages (for example C) can crash your whole computer and require a restart. Modern operating systems usually limit the damage to the running program, but not always. Don't go there. Mostly I will tell you how to avoid it.

Number Types

So far we have been working only with text strings, but computers also (or especially) do numbers. We did numbers in Chomp. There are basically two kinds of numbers a computer can calculate, integers and floating point. Floating point is scientific notation, some fraction times a power of two (instead of ten). It's a lot more complicated than adding or subtracting integers, so I will save that for a later time. Here's a program to illustrate integer data types and operations:
int boyz = 7, gulz = 3;
System.out.println("There are " + boyz + " boys and " + gulz + " girls.");
System.out.println("That's " + boyz+gulz + " kids.");

So if there are seven boys and three girls, how many kids total, ten or 73? Yup, that's a problem. I think it's a mistake in Java to use the "+" operator for two very different (but common) operations, but they didn't ask my opinion. Remember the parentheses in Chomp? Change that last line to:

System.out.println("That's " + (boyz+gulz) + " kids.");

and it works correctly. Why is that? The Java compiler looks at the type of the value to the left of the "+" symbol to decide whether to do this as an integer or as a string, but consecutive operators of the same precedence evaluate left-to-right, so the first "+" sees a string on the left and converts the integer to a string and concatenates them. Then it sees a string on the left and another plus, so it converts the second integer to string and concatenates again. Parentheses override operator sequence by forcing the plus inside the parentheses to be evaluated first, and in that case it's an integer on the left, so it adds them numerically. After that, string concatenation works properly. You will probably see wrong results on many printouts before you get in the habit of adding a lot of extra parentheses. That's OK, you learn by doing. Like a bicycle, you fall off a lot before you get the hang of it.

In addition to the four mathematical operations you learned in grade school, Java supports numerous strange operations on binary numbers, which we will look at later.

Operator precedence refers to which operators get evaluated first when they are mixed without parentheses. Parentheses always take precedence, but other than multiply/divide taking precedence over add and subtract, the rest of the precedence rules are illogical, so you should always use parentheses rather than trying to remember.

Java has a character type "char" which (again like C) is really just another integer. Finally, there is a "boolean" type which has values "false" and "true". You get a boolean result when you compare two values of the same type, like this:

boolean rez = false;
int i = 3, j = 5, k = 0;
k = i+j;
res = k>7;
System.out.println("The value of k = " + k + " and the result rez = " + rez);

You should experiment with different integer operators (+ - * /), and also with different comparisons (<  >  ==  >=  <=  !=). Can you figure out what each one is? Notice that to compare for equality we must use the equal-compare operator ('==') and not the assignment operator ('='). It's easy to use the wrong operator, and Java will not always help you.

Simple Bitwise Operators

In the next lesson we would like to do an interesting program, something like a game, where the computer plays one side and you play the other. One of the requirements for building larger programs is the ability to access values indirectly. This is really one of the topics for next week, but I don't want to wait that long before you get to work with a fun program, so this is a little bit of esoterica that you won't see in your average beginning programming class.

We start by understanding binary numbers. Pretty much everybody understands binary numbers, right? They started teaching that stuff in grade school about the time I got out of college. Here is counting from zero to twenty in decimal (base ten), binary (base two), and hexadecimal (base 16):

Dec  Bin   Hex Pow
 0   0000   0
 1   0001   1   20
 2   0010   2   21
 3   0011   3
 4   0100   4   22
 5   0101   5
 6   0110   6
 7   0111   7
 8   1000   8   23
 9   1001   9
10   1010   A
11   1011   B
12   1100   C
13   1101   D
14   1110   E
15   1111   F
16  10000  10   24
17  10001  11
18  10010  12
19  10011  13
20  10100  14

I listed the hexadecimal next to the binary because each four binary digits (called bits) corresponds to exactly one hex digit. When the binary spills over into a fifth digit, the hex spills over into a second digit. This is important because if you want to spell a binary number in your program, you normally use hex, so that (for example)

(binary) 1101 1110 1010 1101 1011 1110 1110 1111 = 0xDEADBEEF (hexadecimal)
where the "0x" at the front of the number tells Java that it's a number (because only numbers start with a digit like 0) but hexadecimal not decimal (that's what the "x" is for). After a while you will have the important bit patterns memorized, and maybe even be able to convert from common hex numbers to decimal and back in your head.

As you know, each binary digit, each 0 or 1, represents exactly one minimal piece of information, yes or no, hot or cold, true or false. Because we have 32-bit numbers in Java, that gives us 32 different pieces of information we can store in each number. For example, a checker board has 64 squares, but for the game of checkers we only use half of them, so we could make a single number represent all the squares that have a piece on them, or better, we can use two variables, one to hold all the squares that have black pieces, and another with all the squares that have red pieces. We do this by numbering the squares that can have a piece of any color, from 0 to 31 (in computers we always count from zero) from left to right, bottom to top, so the black initial position would be binary 0000 0000 0000 0000 0000 1111 1111 1111 (hex 0x00000FFF, decimal 4095), and the red initial position (using the same numbering scheme) would be 1111 1111 1111 0000 0000 0000 0000 0000 or 0xFFF00000 (decimal -1048576).

Notice how each bit in the binary number represents a particular power of two, 2 times itself that many times (where 20 is 2*2 zero times, which is 1, not 0, and 21 is a single 2, as in the table above). This suggests that we can use a power function to get at those bits. But this is binary,and the hardware thinks in binary, so there's an easier way to get a bit into a particular position, which we call shift. Shifting a bit (or group of bits) left effectively doubles its value; shifting it right halves the value. The Java operator to do this is "<<" to shift left, and ">>" to shift right.

Now, as long as there isn't something already in that bit position, you can turn it on by adding a number with just that bit on, and every other bit off. However, if it's already set, that starts to scramble other bits in the number, so we have a couple of operators that operate only on their corresponding bits, with no carries out into adjacent bits. To turn a bit on, we use the logical OR ("|") and to turn it off we use logical AND ("&"). It's also useful to flip one or more bits from one to zero or zero to one, which is called exclusive OR ("^"). All of these (including the shifts) are called bitwise operators. You could write a little program to try these out and see what they do, but that will be easier after the next couple of lessons.

Before we leave arithmetic and assignments, I should mention two useful shortcuts that show up everywhere, the increment (++) and decrement (--) operators. In a program where variable i is an integer, "i++;" is syntactic sugar for (means exactly the same as) "i = i+1;" and "i--;" means the same as "i = i-1;". You may also see the operator before the variable "++i;" which is the same, except when used inside an expression value. Java allows any assignment statement to be used as a value, but I do not recommend it. My college-level students sometimes got that wrong, and you don't need that kind of problem in your programs.

Next: Conditionals & Input

<<Previous | ToC | Next >>

Revised: 2019 December 24