Parameters (Section 7.4)
     Parameters and arguments
     Parameter passing
     Passing objects (and arrays)
     Namespaces
Conditional operator (Section 7.3)
The switch statement (Section 8.1)
     Cases
     The necessity of break
     The default case
     When switch doesn't apply
Textbook: Section 7.4
We've pretty much finished up everything, but there are some issues that we haven't really covered completely. Today I want to pick up three different issues, which I feel we should cover to finish with Java completely, but which I have put off because there was never time to do it. The first of these has to do with parameters.
A parameter is a named value defined at the time a method is called. An argument is the particular value given into the method. This distinction is somewhat weird, but you'll find that people use it quite often.
For example, consider the following very simple program.
import csbsju.cs160.*;
public class Example {
    public static double square(double x) {
        return x * x;
    }
    public static void main(String[] args) {
        IO.println(square(10));
    }
}
In this program, the parameter of square() is
x, and the argument passed into square within
main() is 10 (which x represents for the duration of
the function.
Java uses a technique for passing parameters called call by value. That is, an argument's value is copied into the parameter variable, so that changes to the parameter variable do not affect anything except for the method itself. Consider the following program.
import csbsju.cs160.*;
public class Example {
    public static double square(double x) {
        x = x * x;
        return x;
    }
    public static void main(String[] args) {
        int y = 10;
        IO.println(square(y));
        IO.println(square(y));
    }
}
In this program, the variable y within main() holds
10. We pass that in as the value for the parameter x in
square(), and that method immediately changes x to be
its square, 100. But that change of x does not affect the value
of y within main()! This is because the value
10 is copied into the local parameter variable x, and
subsequent changes to x only affects that single local
variable.
(Some languages pass parameters differently, and some give you a choice. Java isn't among them.)
Objects and arrays work similarly - but it's important to remember that the value of an object variable is actually a pointer to the actual object. So this memory address is what actually gets copied, not the entire object.
Consider the following program using the Account class we defined earlier.
import csbsju.cs160.*;
public class Example {
    public static void doubleAccount(Account acct) {
        acct.deposit(acct.getBalance());
    }
    public static void main(String[] args) {
        Account mine = new Account();
        mine.deposit(100.0);
        doubleAccount(mine);
        IO.println(mine.getBalance());
    }
}
Here, the mine variable's value is the argument to
doubleAccount(), and so acct holds the same memory
address as mine does. So, actually, acct and
mine point to the same object. Thus, the deposit()
method is actually also depositing into the object pointed to by
mine.
Naturally, this doesn't extend to changes to the actual parameter value. Say we instead wrote doubleAccount() as follows.
    public static void doubleAccount(Account acct) {
        Account new_acct = new Account();
        new_acct.deposit(acct.getBalance());
        new_acct.deposit(acct.getBalance());
        acct = new_acct;
    }
This wouldn't work the same, because the final line here is changing
acct to point to a different object. It doesn't actually affect
the object pointed to by mine. The net effect of this method is
simply to waste time - it creates a new account, but other methods have
no way of accessing it as written.
Arrays work the same - which isn't too surprising, since arrays in Java are objects too. For example, you might write the following method to zero out an array.
    public static void zeroArray(int[] array) {
        for(int i = 0; i < array.length; i++) array[i] = 0;
    }
You've probably already figured this out, but it's important to know that each method's variables lives in its own space of names. You can't refer to a method's variables within another method.
In my earlier examples, I was careful to give different variables different names, even if they're in different methods. But that was just for clarity's sake. In the last example program, we could have used acct in place of mine, and it would work the same, since the acct within main() has no relationship to the acct within doubleAccount() - they're completely different variables.
Textbook: Section 7.3
I wanted to quickly tell you about this new operator, since the textbook has covered it by this point. It's called the conditional operator. (Sometimes it's called the ternary operator, because it is peculiar in that it actually works with three arguments. The other operators are all either binary (like *) or unary (like ++).)
The conditional operator gives you a way of putting an if-then-else into an expression.
Both the question mark and the colon are parts of the conditional operator. The part before the question mark is the condition. The computer will evaluate this to see whether the condition is true or false. If it is true, the computer evaluates the expression between the question mark and the colon, and the result is the value of the overall conditional expression. If the condition is false, then the computer evaluates the expression after the colon, and the result is the value of the overall conditional expression.IO.println(m > n ? m : n);
So in the above line, the conditional expression is m if m exceeds n and n otherwise. In other words, this line will display the larger of m and n.
In the order of operations, the conditional operator ranks just above the assignment operator. Usually this is what you want, but it's good practice to use parentheses here even when you don't need them, to make things more readable.
int max = m > n ? m : n; // UGLY: don't do this. int max = (m > n ? m : n); // much better
The conditional operator is never necessary when you program, but it's occassionally convenient. But you should be aware that it's extremely controversial. Many people say it should be banned. But many others use it. So it's worth knowing about.
Textbook: Section 8.1
We've seen else if popping up in programs with some frequency.
if(letter == 'A') {
    mingrade = 90;
} else if(letter == 'B') {
    mingrade = 80;
} else if(letter == 'C') {
    mingrade = 70;
} else if(letter == 'D') {
    mingrade = 60;
} else if(letter == 'F') {
    mingrade = 0;
}
The switch statement is an alternative to this.
A switch statement looks like the following.
switch(letter) {
case 'A':
    mingrade = 90;
    break;
case 'B':
    mingrade = 80;
    break;
case 'C':
    mingrade = 70;
    break;
case 'D':
    mingrade = 60;
    break;
case 'F':
    mingrade = 0;
    break;
}
You put an expression in the parentheses after switch
(in this case, we want to switch based on the value of letter).
Then, between the braces, we list what we want to do for different
possible values of that expression.
For each possible value, we write case, followed by the value,
followed by a colon.
Then we list what to do, followed by a break statement, telling
the compiler that we've reached the end of our case. The break
statement sends the computer to the next statement following the closing
brace.
It's important to remember break statement! If you leave it out, the computer will proceed into the next case. (This is called `falling through' - which is occasionally useful. Most often, however, it's an error.) Suppose, for example, we wrote the earlier switch statement as follows.
switch(letter) {
case 'A':
    mingrade = 90;
case 'B':
    mingrade = 80;
case 'C':
    mingrade = 70;
case 'D':
    mingrade = 60;
case 'F':
    mingrade = 0;
}
Then what would happen is that mingrade would become 0,
regardless of what letter holds. If, for example,
letter held 'A', the computer would set
mingrade to be 90, then 80, then 70, then 60, and then finally
0.
This aspect of switch statements is usually irritating. But there is one particularly important case where this is useful: When you want multiple cases to do the same thing. For example, the following code converts a character into the value it represents as a hexadecimal value.
switch(letter) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
    value = letter - '0';
    break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
    value = letter - 'A';
    break;
}
You can also use the default label as a sort of ``else'' condition.
switch(letter) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
    value = letter - '0';
    break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
    value = letter - 'A';
    break;
default:
    throw new Exception("not a hexadecimal digit");
}
Here, if letter is anything other than the accepted
characters, an exception is thrown.
Though switch is good to know about, its usefulness is severely hampered by the following two facts.