This is the second part of a self-paced short course designed to
get eager, self-motivated people started in the skill of programming.
The first part discusses program structure in a language-neutral way, using
a subset of English. Nobody learns programming in one or two weeks or even
a whole semester, it takes time and practice -- "motivation and miles"
-- but we can give you a roadmap. Once you more or less understand the
basic structure of things, you can look at existing programs and figure
out how they work -- and by extension and a lot of copying, you can write
your own code to do similar things.
Most of this page explains how to translate a program written in what we call "Kitchen English" into an equivalent program in Java, which runs pretty much exactly the same. Here are the topics we cover, which you may want to come back and review if you get stuck later on:
Top-Down Design
Design in English
Six Ideas in Java
Sequence
Iteration
Conditionals
Boolean Operators
Variables
Scope
Input/Output
Simple Input
Subroutines
Strong Types
Computer programming -- at least what they call "programming"
(a lot of computers are programmed in other ways, but nobody wants to admit
that's what is happening) -- is mostly text-based, so I had a lot of text
to explain that, but nobody wanted to read it. I still rather like what
I said, and you can
read it here (it won't cost
you much, but it does help you know if this is what you want to do for
the rest of your life).
This story is how to play Tic-Tac-Toe.or perhaps better:
This story is how two people (or one person against the computer) play Tic-Tac-Toe.
Then, indented under that line, you break that one sentence description
into two or three (not more) short (one line) descriptions of the biggest
chunks of that whole program, so that the three sentences add up to the
same thing that the top line says.
This story is how two people (or one person against the computer) play Tic-Tac-Toe.
You start with a 3x3 square of nine cells
Each player (in their turn) puts their "X" (first player) or "O" (second player) in a cell.
The game is over when there are three Xs or three Os in a row, column, or diagonal.
Then you do the same thing again for each of those new lines.
This story is how two people (or one person against the computer) play Tic-Tac-Toe.Eventually you get to the level of detail where each line is one of the Six Ideas. That is your program (in English, see below).
You start with a 3x3 square of nine cells
You draw two vertical lines across two horizontal lines.
You can number them 1..9 across the top and down to the bottom.Each (in turn) puts their "X" (first player) or "O" (second player) in a cell.
The human player types in a number to play that cell.
The computer scores each possible cell, then plays the highest score.The game ends when there are 3 Xs or 3 Os in a row, column, or diagonal.
...
In the following descriptions, "statement" is a single command, either a subroutine call or variable assignment, or else a complete iteration or conditional. In the code examples it is written in italics "statement" to show that any statement can be there. Italics also are used as place-holders for arbitrary expressions or names supplied by programmer. Reserved words (not allowed as variable or subroutine names) are shown in bold. Other actual code is shown in typewriter font. Colors are used to show relationships
Comments are not part of the program that the computer runs, they are only there to help people (you and your colleagues) read and understand the code. A comment either starts with two slant characters "//" and ends at the end of that line, or else (called "block comment" because it can extend over several lines) starts with "/*" and ends with "*/". I often use comments here to explain the example code.
You will see examples of these Java statement types as we go along,
and they will be explained again when they are first needed in the code
you write, so don't worry if the explanation here is obscure:
Sequence in Java is spelled with a semicolon ";" which terminates each subroutine call or variable assignment or declaration (statement), or else with a pair of braces "{...}" that combines into one statement a whole sequence of statements.{;;; {}} // four null statements (they do nothing) combined into one statementIn English, each line is one statement, but in Java whatever ends with a semicolon is one statement. It is customary in Java to put one statement on each line (if it fits) and indent any spillover into the next line, because that makes it easier to read. Some C programmers consider it great sport to put their whole program on one line (some compilers have line length limits, which makes packing it in interesting), but of course that takes a lot of time (and time is money), so you should not try to do that with real programs.
Iteration in Java comes in several forms, but only two are really useful:
while (expression)statement // the expression should evaluate to true or falseThe expression is tested before the loop statement executes each time through, and any time it is false the loop terminates (and proceeds with the next statement after the loop) without doing statement at allThe statement is whatever you want repeated. Most programmers always wrap braces {...} around the statement so they don't need to think about adding them if they later decide to add another statement inside the loop.
for (name=expression;expression;statement)statementname is a variable, declared either here or previouslyThe for-loop parentheses and the semicolons are required, but the expressions and statements between them are optional (I do not recommend leaving them out, it makes your program hard to read). The assignment, if omitted, could be replaced by some other initialization in a prior line. The second expression, if omitted, is assumed to be true (it would be a never-ending infinite loop unless you have an explicit break inside)The first expression is an initial value given to that variable
The second expression is a boolean value, usually testing name against some end value, and works like the expression in while
The first statement is typically an increment or decrement on the variable, which executes after the end of the second statement
The second statement is whatever you want repeated.
For example, this is exactly equivalent to the corresponding while-loop above:Two other commands inside the statement give more precise control of the loop operation:for (;expression;)statementbreak; // immediately exits the loopcontinue; /* immediately skips to the loop's next iteration, including any incrementation statement and the test expression*/
Examples: In English there was only one form of iteration, the Repeat, for example:Repeat 3which prints "Hello" on three successive lines. In Java that would look like this:
Print "Hello"
Nextfor (int n=0; n<3; n++) System.out.println("Hello");In English, if we wanted to do something that counted the iterations and numbered the steps, we would need to declare a separate variable, but that variable is built into the Java for-loop (n in our example above). Here we want to show our count, first in English:Variable n = 0Here's the same thing in Java:
Repeat
Add 1 to n
If n>9 then Exit
Print n # ".."
Nextfor (int n=1; n<=9; n++) System.out.println("" + n + "..");
or alternatively:int n = 0;
while (true) {
n++;
if (n>9) break;
System.out.println("" + n + "..");}
Notice that the concatenation operator in Java is the same as the addition operator (that's called "operator overloading" in C where the programmers are encouraged to do stupid things like that) so if you don't make sure the value on its left is a String (of characters, in this case the empty string ""), it will attempt to do arithmetic and get wrong results, and the compiler won't help you. I think that was a mistake but they didn't ask my opinion, so you are stuck with the result. It is what it is.
Conditionals come in two flavors in Java, but we will mostly only use the familiar if..else:
if (expression)statementelsestatementThe expression is a boolean value, which if it evaluated true, the first statement is executed, otherwise the second statement is executedThe else-part (with its stmt) is optional. Most programmers always wrap braces {...} around the statements, so they don't need to think about adding them if they decide to add another statement under the control of the condition.
After you are more comfortable writing Java code, you can read about the other kind of conditional in the Switch section of the "Things You Need to Know in Java" page.Examples: The English conditional only let you control one statement. Technically that's true also in Java, but everybody uses braces without even thinking about it. You could do that in the Kitchen English programming language too (using an iteration) but it was unobvious:
Input YourGuess
If YourGuess = MyNumber then Repeat 1
Print "You got it!"
Add 1 to wins
Next
In Java that might look like this (using my "safe" input):int YourGuess = Zystem.ReadInt();
if (YourGuess == MyNumber) {
System.out.println("You got it!");
wins++;}
The Kitchen English programming language only lets you compare for equal, less, or greater; Java also lets you compare for their negations:
Op True Negation Equal == != Less < >= Greater > <=
Notice also that to test if a value is equal in Java uses a different symbol '==' than making it equal in an assignment '='. They really are different things, but because they use separate symbols, the Java compiler can (and does!) also let you do assignments in places where they don't belong -- and the Java compiler will not always warn you! For example,boolean A = true, B = false;
if (A=B) System.out.println("Equal!");If both are true, then you get the top left quadrant ("AND" which is '&&' in Java). If neither is true, you get the bottom right quadrant. You might want the condition where either the truck is blue OR the car is red (or both), which is every possibility except the bottom right. You cannot say that in Kitchen English directly, you must make up a combination like this:
This will actually compile and run in Java (and print "Equal!"). Java repaired a lot of C's mistakes, but this wasn't one of them. If A and B are numbers, then the compiler will complain, not that you set them equal (which is the real bug) but that it's expecting a boolean value inside the parentheses. It is what it is. You can't always trust the error message, only that there's some kind of programming error on (or before) the line where it complains. If you can't find it, get help from somebody who has more experience. Or if you compile often (which is a good idea) you can look for your error among your most recent changes.
The Kitchen English programming language has no way to combine boolean values in a single expression. Sometimes programmers need to do that, but usually in large complicated programs, which you have not seen so far. In spoken English you might say "if the truck is blue AND the car is red then..." but you can also say "if the truck is blue then if the car is red then..." to get the same effect, and it works in Kitchen English. There are several ways to combine these two conditions, as shown in this diagram, where the top half represents the blue truck and the bottom half is some other color of truck, andthe left half represents the red car and the right half is some other color of car:Let either = falseIn Java you can do that, but usually you use the boolean OR operator '||':
If the truck is blue then Let either = true
If the car is red then Let either = true
If either is true then ...if ((truck == blue)||(car == red)) {...Note that the extra parentheses are required, Java got the operator hierarchy wrong for what everybody needs these operators for. Other combinations you can make up with the NOT operator ('!' in Java), for example any of these three are the same bottom right quadrant:if ((truck != blue)&&(car != red)) {...Again, you need the extra parentheses. Extra parentheses never hurt (except too many of them make it hard for people to read).
if (!((truck == blue)||(car == red))) {...
if ((!(truck == blue))&&(!(car == red))) {...
Variables (sometimes also called "fields") must always be declared to be a particular type in Java before they are used, and may optionally be given an initial value in the declaration. Multiple variables may be declared of the same type in one statement (ending in a semicolon), but you cannot declare the same variable name multiple times (in the same scope, see below). The type must be a previously defined class name (see "Object-Oriented Programming" when we get there, and "Objects and Classes" in the "Need to Know" page because we mostly won't get there), or else a defined scalar type like boolean, char, int, float or double. The last three are numbers, and if you mix different sizes of any number type, Java will promote the operation to the highest precision (typically double). That's reasonable. What is unreasonable (and it will bite you because the compiler should complain, but it doesn't) is that Java considers characters to be compatible with numbers, and gives you no warning if (for example) you try to compare a character to an integer, like this:
int num = 3;The numeric value Java sees in variable ach as 51, not 3, so of course comparing them is never equal. This is a blunder, but they didn't ask my opinion. You need to be careful when working with characters.
char ach = '3';
if (ach == num) ThisSubroutineNotCalled();Notice that Java allows only one type for each variable, and every value you want to put into a variable must be the same type as the variable. The types must match (or at least be compatible, that is, Java knows how to convert them). The English computer automatically did whatever conversion was necessary.
Here is an example of two variable declarations, the second being the system-defined String type:
int abc, xyz = 0, aHugeVeryBigName = xyz+8;If the idea of "string" is new to you, you might find it helpful review the topic in English where we discussed it in connection with Variables.
String aWord = "Mary";Variables can be given values when they are declared, and/or elsewhere in the program like this:
abc = aHugeVeryBigName-xyz+33;Notice that only one line tells Java the type (in this case int); if you try to use the type name on multiple lines that set a new value to abc, Java will be confused and refuse to run it. You can give the same value to multiple variables in a single command, but I don't encourage it (look it up online if you want to do that). Start simple, you can get tricky later (tricky is not a good idea, but some programmers consider it fun; the manager paying you to write a program usually has a different opinion).The familiar arithmetic operators (+ - * /) work on the number types in Java, along with various bit operators you mostly don't need in the programs we are doing here, and you can group operations using parentheses, where the subexpressions inside parentheses are evaluated before being combined with any operations outside. Everything else is done by subroutine ("function" or "method") calls.
You also have easy ways to add (or subtract) 1 to a variable:
n++; // is the same as (English) 'Add 1 to n'There are update forms for most of the operators, but you can learn them later (if you so choose; me, I don't use them at all because they are only more things to know and be concerned about, but offer no advantage).
n--; // is the same as (English) 'Subtract 1 from n'Scope: In English all variables are global, that is, you can declare a variable anywhere in your program and use it anywhere else, and it's the same variable everywhere. In Java a variable is only visible inside the most nearly enclosing braces, called its scope (that's Greek for "visible"). I recommend that variables used only inside a single subroutine be declared at the beginning of that subroutine, just inside the left brace (see examples below), but if you want the same variable to be used in several subroutines, or if you want to preserve its value between subroutine calls, you must declare it inside the outer braces of your compiled class (see examples below). Until we start using the "Object-Oriented" (OOPS) features of Java, all the variables you declare at the class level (only) need the magic word "static" in front of the type name.
The first four programs you write in Java, you will use the simple rules described on this page to convert (translate) your English code to Java, line by line (except you should move all variable declarations out to the class level), and it will work. Then you should go back and decide which of these variable should be parameters, and which should be local, so the Java code looks better and is easier to understand.
Java allows variables to be declared anywhere in your program, but the variables declared inside a subroutine can only be used inside the nearest brace pair, and only after they are declared. I do not recommend it, but many Java programmers declare for-loop control variables inside the parentheses of the for-loop (see the first for-loop example above). Java could and should prevent you from accidentally re-using a control variable, but this habit at least prevents one of the possible bugs that people might make.
Examples:If you have the same variable name declared at different scopes (levels), only the nearest (by counting braces) declaration will be used. So you could (this would be A Very Bad Idea) do something foolish like this:
class MyClass {
static String x = "Hello"; // visible everywhere inside MyClassstatic void fust() {
char x = '?'; // hides outer String x
for (int x=1; x<=9; x++) { // hides outer char x
System.out.print(x);} // prints digits from 1 to 9 on a line
System.out.print(x);} // adds a question mark to the linestatic void main() {
fust(); // prints '123456789?'
System.out.print(x);} // prints ' Hello' on the same line
}
So here you have three identical print statements in the same program printing the same variable name x but printing very different things from three separate variables, with no confusion -- except in the mind of the programmer trying to understand what is going on. Don't be that person.But you certainly need to declare some variables at the class level (they are called class variables or fields) so you can preserve their values across multiple subroutine calls, and other variables inside their respective subroutines (they are called local variables) so you don't need to worry about accidentally using the same name in another subroutine the next week. When you have values used in a single subroutine but prepared outside where it is called, you should use parameters (see examples in "Subroutines" below); when a subroutine calculates a single value for the use of its caller, you should return it as a function result.
Input/Output in Java is always by predefined subroutine calls.
Examples: In English we had Print and Input commands for text I/O. The Java subroutines to do these simple things are more complicated than they need to be, but you can think of them as "silly long names with dots in them" for now. The dots have to do with classes and objects, which we will get to much later (you can read about them in the "Objects and Classes" section of the "Need to Know" page). So, the English
Print "Hello"is spelled in Java:System.out.println("Hello");
You also can print multiple things on the same line:System.out.print("Hello,"); System.out.print("World!");which prints 'Hello,World!' on the one line. In English you could do it this way:Let Hello = "Hello,"
Print Hello # "World!"
In English you can specify what kind of input you want using a number after the variable name on the Input command line:Input word {gets whatever the user types, up to but not including Enter}
Input number,-1 {gets only a number, all else ignored}
Input letter,1 {gets a single (capitalized) character}
Java has very complicated ways to do the same kinds of input (which we will get to when we do the Calculator in Java) but I wrote some simplified input routines in a special "Zystem" class (see "Input Routines in my class Zystem" in the "Things You Need to Know in Java" page), which you can use for now:String word = Zystem.ReadWord(); // same as EnglishNotice that Java allows only one type for each variable (in these three lines, String, then integer, then character). If you open up the Zystem file you can see that those three input routines are declared to return those three types. The types must match (or at least be compatible, that is, Java knows how to convert them). The English computer always did whatever conversion was necessary.
int number = Zystem.ReadInt(); // ignores spaces but stops at non-digit
char letter = Zystem.ReadLetter(); // one (including Enter) uncap'd
Subroutines in Java are called "methods" for no particular reason, and can be declared only inside class definitions. They have an optional return type, a name, and a parameter list of zero or more typed parameters that look more or less like variable declarations separated by commas rather than semicolons and enclosed in a pair of parentheses. The parentheses are required, both in the declaration (sometimes called the "header"), and also every place the subroutine is called, even if there are no parameters. The body of the method is enclosed in a pair of required braces. If the subroutine ("function") returns a value, it must end in a return statement giving the value to be returned, which must be the declared type and ending in a semicolon; otherwise the declared type is void. Here is the general form:
static typename(parameter list) {The gray "static" you should always use until you get into OOPS (after you complete Seaman in Java). It means this subroutine is not "Object-oriented." The gray "return value;" is required when the type is an ordinary type name (not void), and the value must be that type. All Java subroutines or functions must be declared inside a class declaration and not inside another subroutine or function.
// subroutine body here
return value;} // end of nameHere are two specific examples (there are others below). Note that the first example has a single integer parameter, and the second example here is a function with no parameters and requires a boolean result (in this case the constant value true):
static void mySubroutine(int z) {
System.out.println("z = " + z);
} // end of mySubroutine
static boolean myFunction() { // no parameters
System.out.println("in myFunction");
return true;} // end of myFunction
When you call a subroutine from somewhere else in your program, it looks maybe like this:if (myFunction()) // using the boolean result to control the conditional
mySubroutine(7); // no result to use
else mySubroutine(0);
You need to be careful that your argument values in the call statement line up properly with the parameters (same number, same order) in the subroutine header. Any subroutine or function may return early with a return statement giving the value, or if void, the return statement alone, in either case always ending in a semicolon.Here is an example of a trivial method (function) returning the sum of its two parameters:
static int sum(int a, int b) {return a+b;}
...
int five = sum(2,3); // arguments: 2,3 match params a=2, b=3
Classes in Java are a way to group related data and methods into a separate compilation, where the class name becomes a new data type with its own copies of the data declared in the class. Most of the programs you will write in this curriculum are not object-oriented, so we will introduce those distinctives when we get there, (see "Object-Oriented Programming" when we get there, and "Objects and Classes" in the "Need to Know" page because we mostly won't get there).Examples: The Real World is not "object oriented" so of course the English language isn't either, and we knew nothing of classes and objects when we wrote programs in the "Kitchen English" programming language. But we did have subroutines, which were declared with a name in quotation marks, and were called by the same name without the quotes. For example, if we have in English:
Variable x = 23
Do times6
Do my Subroutine
Add 3 to x
Do my Subroutine"my Subroutine"
Print "x = " x
Done"times6"
Let x = x*6
Done
The same thing in Java looks like this:class Example {
static void mySubroutine(int z) {
System.out.println("x = " + z);
} // end of mySubroutinestatic int times6(int y) {
int rez = y*6;
return rez;
} // end of times6static void main() {
int x = 23;
x = times6(x);
mySubroutine(x);
x = x+3;
mySubroutine(x);
} // end of main
} // end of Example
Notice first that English allows spaces in the subroutine name, but Java does not. You can just delete the spaces and change the next letter to a capital for readability, or you can use the underscore character (shift-hyphen "_") which is considered to be a letter in Java but not allowed in English.Notice that x declared inside main is copied to parameters y and z when calling those respective subroutines. All English variables (including subroutine parameters and results) are global, so you just set the values then called your subroutine, then got the results when it got back. In Java you can declare variables inside any pair of braces (the for-loop parentheses are presumed to be inside its braces, even though they really aren't) and those variables are visible only inside those braces -- sometimes, but not always, only after the declaration, so it's a good policy to declare variables always before they are used. See the nested variable example above for how that works.
Every Java program is expected to have one subroutine named "main" which is also static -- which means it exists outside the class; static subroutines can only refer to static class variables and subroutines; for now everything is static at the class level, but later, when you do real objects, that won't be necessary. From the Bad Olde Unix dayes, the main subroutine is often expected to take an array of String values (you will always see an example of what this looks like when you come to a new IDE), but modern point-and-click implementations don't pass any command-line parameters. You should be prepared for either kind. Your program is always started by the operating system calling its main() subroutine, which then does whatever your program needs to do.
The essence of strong data types is that you must declare the type (tell the compiler your intentions) of anything that can have a type before you ever try to use it, and then the compiler will refuse to accept it if you accidentally try to do something inappropriate. Very large programs -- think: thousands or millions of lines of code -- nobody can keep all that logic in mind at once, so we need all the help we can get from the compiler. The strong type system is your friend, be nice to it.
In the following projects you will be converting the four programs you wrote in English into Java. English is untyped (OK as a learning tool, but rotten for heavy lifting), so an important part of converting them to Java is choosing an appropriate data type for each variable. This will be covered in the discussion.
Subroutines (in Java they are called methods or functions) have several places where the strong type system is exercised. Let's review them here. Here is a subroutine like many you will see (and write!) in Java:
static void main() {The first line is called the "method header" and it declares everything we need to know about this subroutine. It also happens to be the correct form for the main program in any Java program (except in Unix environments like Replit you need a parameter that nobody ever uses: just copy the example when you get there).
int x = 23;
/// ... (more code here)
} // end of main
The first word "static" means this subroutine is not "object-oriented" (OOPS, see "Object-Oriented Programming" later in this tutorial and "Objects and Classes" in the page on "Things You Need to Know in Java"). Java is intended to be OOPS, so everything else -- including the required "main" routine -- must be specially marked as not. What can I say? They didn't get everything right, but they tried, and they are way ahead of whatever is in second place. You need to put "static" in front of every method header you write in this course, until you get to the OOPS part. The compiler will complain if you don't, but copy-and-paste is easy.
The second word "void" is a magic word that means "not a data type". Subroutines can return a single value -- we call them "functions" when they do -- but if not, we need to tell the compiler that we don't want a return value. The word void goes in the place on that line that the return data type would go if a value is returned. We'll get to that shortly (below).
The third word "main" is the name of the routine, and the empty parentheses "()" tells the compiler that this is a subroutine and there are no parameters. Always we need to tell the compiler what our intentions are.
The next line is the beginning of the subroutine body, and it declares a local variable "x" and gives it an initial value 23. The variable x is visible only between the opening brace in the header and the closing brace at the routine end. That way you can have thousands of subroutines in your program, and many of them can declare local variables named "x" and there is no confusion. Also this variable must have a type (in this case integer) spelled "int" which means this variable can only have integer values. The compiler will complain if you deviate from this stated intention. See also "Variables" above.
Here is another subroutine (called a "function" because it returns a value), which you also already saw above:
int sum(int a, int b) {If you decided to test this subroutine in the Hello class in the next section, you would need to add a "static" in front because you have no way to call it in an object-oriented way yet.
return a+b;
} // end of sum
We know this subroutine is a function because it is declared with a type name "int" and not "void". That also means that a "return" command is required for every possible path through the function, and it must be an integer value in each case. For example, if you changed the return line to be conditional:
if (a>0) return "a+b";the compiler would complain for two reasons, first because you are trying to return a string (which is not an integer), and then again because if the parameter value a is zero or less, it would be possible for execution to get to the end brace (on the third line) without executing any return at all.
Continuing with our analysis of the header line, we see two parameters, both integers. Parameters are essentially local variable declarations, which are initialized with values provided by the calling code, so they must always be given a data type. When the subroutine is called, the compiler verifies that that the values supplied are compatible with (can be automatically converted to) the declared types. Integers are pretty restrictive, you can automatically convert a character (type "char") to it -- I think that is a mistake, but they didn't ask my opinion -- but not much else. Anything else, you need to do the conversion yourself (that would be a good thing, you don't want stuff like that happening by accident). As noted above, integers can be automatically promoted to float or double, but (surprisingly, because it is allowed other places) not to String. Whatever. Best you do explicit conversion every place you want it.
That should be enough to get you started. We'll try to remind you as we go along. See also "Variables" above for other ways that strong types are different from untyped languages like English.
If you came here from some other part of the tutorial to review data types, you can use your browser's GoBack button to return. Otherwise...
OK, let's get started. Turn the page.
Next: Programming Environment
2022 May 10