2018年3月17日 星期六

Searching Arrays and Collections

The Collections class and the Arrays class both provide methods that allow you to search for a specific element. When searching through collections or arrays, the following rules apply:
  • Searches are performed using the binarySearch() method.
  • Successful searches return the int index of the element being searched.
  • Unsuccessful searches return an int index that represents the insertion point. The insertion point is the place in the collection/array where the clement would be inserted to keep the collection/array properly sorted. Because positive return values and 0 indicate successful searches, the binarysearch() method uses negative numbers to indicate insertion points. Since 0 is a valid result for a successful search, the first available insertion point is -1. Therefore, the actual insertion point is represented as (-(insertion point) -1). For instance, if the insertion point of a search is at element 2, the actual insertion point returned will be -3.
  • The collection/array being searched must be sorted before you can search it.
  • If you attempt to search an array or collection that has not already been sorted, the results of the search will not be predictable.
  • If the collection/array you want to search was sorted in natural order, it must be searched in natural order. (This is accomplished by NOT sending a Comparator as an argument to the binarysearch() method.)
  • If the collection/array you want to search was sorted using a Comparator, it must be searched using the same Comparator, which is passed as the second argument to the binarysearch() method. Remember that Comparators cannot be used when searching arrays of primitives.

Let's take a look at a code sample that exercises the binarysearch() method:

import java.util.*;
class SearchObjArray {
    public static void main(String [] args) {
        String [] sa = {"one", "two", "three", "four"};
        Arrays.sort(sa);                                // #1
        for(String s : sa)
            System.out.print(s + " "};
        System.out.println("\none = "
                + Arrays.binarysearch(sa,"one"));            // #2
        System.out.println("now reverse sort");
        ReSortComparator rs = new ReSortComparator();    // #3
        Arrays.sort(sa,rs);
        for(String s : sa)
            System.out.print(s + " ");
        System.out.println("\none = "
                + Arrays.binarysearch(sa,"one"));            // #4
        System.out.println("one = "
                + Arrays.binarysearch(sa,"one",rs));        // #5
    }
    static class ReSortComparator
            implements Comparator {                // #6
        public int compare(String a, String b) {
            return b.compareTo(a);                        // #7
        }
    }
}

which produces something like this:

four one three two
one = 1
now reverse sort
two three one four
one = -1
one = 2

Here's what happened:

Line 1: Sort the sa array, alphabetically (the natural order).
Line 2: Search for the location of element "one", which is 1.
Line 3: Make a Comparator instance. On the next line we re-sort the array using the Comparator.
Line 4: Attempt to search the array. We didn't pass the binarySearch () method the Comparator we used to sort the array, so we got an incorrect (undefined) answer.
Line 5: Search again, passing the Comparator to binarysearch(). This time we get the correct answer, 2
Line 6: We define the Comparator; it's okay for this to be an inner class.
Line 7: By switching the use of the arguments in the invocation of compareTo(), we get an inverted sort.

Given:

1. import java.util.*;
2. public class Quest{
3.     public static void main(String[] args){
4.         String[] colors = 
5.                 {"blue","red","green","yellow","orange"};
6.         Arrays.sort(colors);
7.         int s2 = Arrays.binarySearch(colors, "orange");
8.         int s3 = Arrays.binarySearch(colors, "violet");
9.         System.out.print(s2 + "" + s3);
10.     }
11. }

What is the result?

A. 2-1
B. 2-4
C. 2-5
D. 3-1
E. 3-4
F. 3-5
G. Compilation fails.
H. An exception is thrown at runtime.

Conditional Operator

The conditional operator is a ternary operator (it has three operands) and is used to evaluate boolean expressions, much like an if statement except instead of executing a block of code if the test is true, a conditional operator will assign a value to a variable. In other words, the goal of the conditional operator is to decide which of two values to assign to a variable. This operator is constructed using a ? (question mark) and a : (colon). The parentheses are optional. Its structure is:

x = (boolean expression) ? value to assign if true : value to assign if false

Let's take a look at a conditional operator in code:

class Salary  {
    public static void main(String [] args) {
        int numofPets = 3;
        String status = (numofPets<4) ? "Pet limit not exceeded"
                : "too many pets";
        System.out.println("This pet status is " + status);
    }
}

You can read the preceding code as

Set numofPets equal to 3. Next we're going to assign a String to the status variable. If numofPets is less than 4, assign "Pet limit not exceeded" to the status variable; otherwise, assign "too many pets" to the status variable.

A conditional operator starts with a boolean operation, followed by two possible values for the variable to the left of the assignment ( = ) operator. The first value (the one to the left of the colon) is assigned if the conditional (boolean) test is true, and the second value is assigned if the conditional test is false. You can even nest conditional operators into one statement:

class AssignmentOps {
    public static void main(String [] args) {
        int sizeOfYard = 10;
        int numOfPets = 3;
        String status = (numOfPets<4)?"Pet count OK"
                :(sizeOfYard > 8)? "Pet limit on the edge"
                :"too many pets";
        System.out.println("Pet status is " + status);
    }
}

Don't expect many questions using conditional operators, but remember that conditional operators are sometimes confused with assertion statements, so be certain you can tell the difference.

Given:

11. String[] elements = {"for", "tea", "too"};
12. String first = (elements.length>0) ? elements[0] : null;

What is the result?

A. Compilation fails.
B. An exception is thrown at runtime.
C. The variable first is set to null.
D. The variable first is set to elements[0].

Logical Operators exclusive-OR (^) and Boolean invert (!)

The last two logical operators on the exam are
  • ^ exclusive-OR (XOR)
  • ! Boolean invert

The ^ (exclusive-OR) operator evaluates only boolean values. The ^ operator is related to the non-short-circuit operators we just reviewed, in that it always evaluates both the left and right operands in an expression. For an exclusive-OR (^) expression to be true, EXACTLY one operand must be true—for example,

System.out.printIn ("xor " + ((2<3) ^ (4>3)));

produces the output: xor false

The preceding expression evaluates to false because BOTH operand one (2 < 3) and operand two (4 > 3) evaluate to true.

The ! (boolean invert) operator returns the opposite of a boolean's current value:

if (!(7 == 5)) { system.out.println ("not equal"); }

can be read "if it's not true that 7 == 5," and the statement produces this output: not equal

Here's another example using booleans:

boolean t = true;
boolean f = false;
System.out.println ("! " + (t & !f) + " " + f);

produces the output: ! true false

In the preceding example, notice that the & test succeeded (printing true), and that the value of the boolean variable f did not change, so it printed false.

Given:

1. public class Spock{
2.     public static void main(String[] args){
3.         Long tail = 2000L;
4.         Long distance = 1999L;
5.         Long story = 1000L;
6.         if((tail>distance) ^ ((story*2)==tail))
7.             System.out.print("1");
8.         if((distance+1 != tail) ^ ((story*2)==distance))
9.             System.out.print("2");
10.     }
11. }

What is the result?

A. 1
B. 2
C. 12
D. Compilation fails.
E. No output is produced.
F. An exception is thrown at runtime.

Using Break and Continue

The break and continue keywords are used to stop either the entire loop (break) or just the current iteration (continue). Typically if you're using break or continue, you'll do an if test within the loop, and if some condition becomes true (or false depending on the program), you want to get out immediately. The difference between them is whether or not you continue with a new iteration or jump to the first statement below the loop and continue from there.

The break statement causes the program to stop execution of the innermost loop and start processing the next line of code after the block.

The continue statement causes only the current iteration of the innermost loop to cease and the next iteration of the same loop to start if the condition of the loop is met. When using a continue statement with a for loop, you need to consider the effects that continue has on the loop iteration. Examine the following code:

for (int i = 0; i < 10; i++) {
    System.out.println("Inside loop");
    continue;
}

The question is, is this an endless loop? The answer is no. When the continue statement is hit, the iteration expression still runs! It runs just as though the current iteration ended "in the natural way." So in the preceding example, i will still increment before the condition (i < 10) is checked again. Most of the time, a continue is used within an if test as follows:

for (int i = 0; i < 10; i++) {
    System.out.println("Inside loop");
    if (foo. doStuff() == 5) {
        continue;
    }
    // more loop code, that won't be reached when the above if
    // test is true
}


Given:

1. public class Breaker2{
2.     static String o = "";
3.     public static void main(String[] args){
4.         z:
5.         for(int x=2; x<7; x++){
6.             if(x == 3) continue;
7.             if(x == 5) break z;
8.             o = o + x;
9.         }
10.         System.out.println(o);
11.     }
12. }

What is the result?

A. 2
B. 24
C. 234
D. 246
E. 2346
F. Compilation fails.

2018年3月16日 星期五

Labeled Statements

Although many statements in a Java program can be labeled, it's most common to use labels with loop statements like for or while, in conjunction with break and continue statements. A label statement must be placed just before the statement being labeled, and it consists of a valid identifier that ends with a colon (:).

You need to understand the difference between labeled and unlabeled break and continue. The labeled varieties are needed only in situations where you have a nested loop, and need to indicate which of the nested loops you want to break from, or from which of the nested loops you want to continue with the next iteration. A break statement will exit out of the labeled loop, as opposed to the innermost loop, if the break keyword is combined with a label. An example of what a label looks like is in the following code:

foo:
    for (int x = 3; x < 20; x++) {
        while(y > 7)    {
            y--;
        }
    }

The label must adhere to the rules for a valid variable name and should adhere to the Java naming convention. The syntax for the use of a label name in conjunction with a break statement is the break keyword, then the label name, followed by a semicolon. A more complete example of the use of a labeled break statement is as follows:

boolean is True = true;
outer:
    for(int i=0; i<5; i++) {
        while (isTrue) {
            System.out.println("Hello");
            break outer;
        } // end of inner while loop
        System.out.println("Outer loop."); // Won't print
    } // end of outer for loop
System.out.println("Good-Bye");

Running this code produces

Hello
Good-Bye

In this example the word Hello will be printed one time. Then, the labeled break statement will be executed, and the flow will exit out of the loop labeled outer. The next line of code will then print out Good-Bye. Let's see what will happen if the continue statement is used instead of the break statement. The following code example is similar to the preceding one, with the exception of substituting continue for break:

outer:
    for (int i=0; i<5; 1++) {
        for (int j=0; j<5; j++) {
            System.out.println("Hello");
            continue outer;
        } // end of inner loop
        System.out.println("outer"); // Never prints
    }
System.out.println("Good-Bye");

Running this code produces

Hello
Hello
Hello
Hello
Hello
Good-Bye

In this example, Hello will be printed five times. After the continue statement is executed, the flow continues with the next iteration of the loop identified with the label. Finally, when the condition in the outer loop evaluates to false, this loop will finish and Good-Bye will be printed.

Given:

1. public class Breaker{
2.     static String o = "";
3.     public static void main(String[] args){
4.         z:
5.         o = o + 2;
6.         for(int x=3; x<8; x++){
7.             if(x == 4) break;
8.             if(x == 6) break z;
9.             o = o + x;
10.         }
11.         System.out.println(o);
12.     }
13. }

What is the result?

A. 23
B. 234
C. 235
D. 2345
E. 2357
F. 23457
G. Compilation fails.

Increment and Decrement Operators

Java has two operators that will increment or decrement a variable by exactly one. These operators are composed of either two plus signs (++) or two minus signs (--):
  • ++ increment (prefix and postfix)
  • -- decrement (prefix and postfix)

The operator is placed either before (prefix) or after (postfix) a variable to change its value. Whether the operator comes before or after the operand can change the outcome of an expression. Examine the following:

1. class MathTest {
2.     static int players = 0;
3.     public static void main (String [] args) {
4.         System.out.println("players online: " + players++);
5.         System.out.println("The value of players is " + players);
6.         System.out.println("The value of players is now " + ++players);
7.     }
8. }

Notice that in the fourth line of the program the increment operator is after the variable players. That means we're using the postfix increment operator, which causes players to be incremented by one but only after the value of players is used in the expression. When we run this program, it outputs the following:

%java MathTest
players online: 0
The value of players is 1
The value of players is now 2

Notice that when the variable is written to the screen, at first it says the value is 0. Because we used the postfix increment operator, the increment doesn't happen until after the players variable is used in the print statement. Get it? The "post" in postfix means after. Line 5 doesn't increment players; it just outputs its value to the screen, so the newly incremented value displayed is 1. Line 6 applies the prefix increment operator to players, which means the increment happens before the value of the variable is used, so the output is 2.

Expect to see questions mixing the increment and decrement operators with other operators, as in the following example:

int x = 2;  int y = 3;
if ((y == x++) | (x < ++y)) {
    System.out.println("x = " + x + " y = " + y) ;
}

The preceding code prints: x = 3 y = 4

You can read the code as follows: "If 3 is equal to 2 OR 3 < 4"

The first expression compares x and y, and the result is false, because the increment on x doesn't happen until after the == test is made. Next, we increment x, so now x is 3. Then we check to see if x is less than y, but we increment y before comparing it with x! So the second logical test is (3 < 4). The result is true, so the print statement runs.

As with String concatenation, the increment and decrement operators are used throughout the exam, even on questions that aren't trying to test your knowledge of how those operators work. You might see them in questions on for loops, exceptions, even threads. Be ready.

Given:

10. int x = 0;
11. int y = 10;
12. do{
13.     y--;
14.     ++x;
15. }while(x < 5);
16. System.out.print(x + "," + y);

What is the result?

A. 5,6
B. 5,5
C. 6,5
D. 6,6

2018年3月2日 星期五

if-else Branching

The basic format of an if statement is as follows:

if (booleanExpression) {
    System.out.println("Inside if statement");
}

The expression in parentheses must evaluate to (a boolean) true or false. Typically you're testing something to see if it's true, and then running a code block (one or more statements) if it is true, and (optionally) another block of code if it isn't. The following code demonstrates a legal if-else statement:

if (x > 3) {
    System.out.println("x is greater than 3");
} else {
    System.out.println("x is not greater than 3");
}

The else block is optional, so you can also use the following:

if (x > 3) {
    y = 2;
}
z += 8;
a = y + x;

The preceding code will assign 2 to y if the test succeeds (meaning x really is greater than 3), but the other two lines will execute regardless. Even the curly braces are optional if you have only one statement to execute within the body of the conditional block. The following code example is legal (although not recommended for readability):

if (x > 3) // bad practice, but seen on the exam
    y = 2;
z += 8;
a = y + x;

Sun considers it good practice to enclose blocks within curly braces, even if there's only one statement in the block. Be careful with code like the above, because you might think it should read as,

"If x is greater than 3, then set y to 2, z to z + 8, and a to y + x."

But the last two lines are going to execute no matter what! They aren't part of the conditional flow. You might find it even more misleading if the code were indented as follows:

if (x > 3)
y = 2;
z += 8;
a = y + x;

You might have a need to nest if-else statements (although, again, it's not recommended for readability, so nested if tests should be kept to a minimum). You can set up an if-else statement to test for multiple conditions. The following example uses two conditions so that if the first test fails, we want to perform a second test before deciding what to do:

if (price < 300) {
    buyProduct();
} else {
    if (price < 400) {
        getApproval();
    }
    else {
        dontBuyProduct();
    }
}

This brings up the other if-else construct, the if, else if, else. The preceding code could (and should) be rewritten:

if (price < 300) {
    buyProduct();
} else if (price < 400) {
    getApproval () ;
} else {
    dontBuyProduct();
}

There are a couple of rules for using else and else if:
  • You can have zero or one else for a given if, and it must come after any else ifs.
  • You can have zero to many else ifs for a given if and they must come before the (optional) else.
  • Once an else if succeeds, none of the remaining else ifs or elses will be tested.

The following example shows code that is horribly formatted for the real world. As you've probably guessed, it's fairly likely that you'll encounter formatting like this on the exam. In any case, the code demonstrates the use of multiple else ifs:

int x = 1;
if ( x == 3 ) { }
else if (x < 4) {System.out.println("<4"); }
else if (x < 2) {System.out.println("<2"); }
else { System.out.println("else"); }

It produces the output:

<4

(Notice that even though the second else if is true, it is never reached.) Sometimes you can have a problem figuring out which if your else should pair with, as follows:

if (exam. done())
    if (exam.getScore() < 0.61)
        System.out.println("Try again.");
    // Which if does this belong to?
    else
        System.out.println("Java master!");

We intentionally left out the indenting in this piece of code so it doesn't give clues as to which if statement the else belongs to. Did you figure it out? Java law decrees that an else clause belongs to the innermost if statement to which it might possibly belong (in other words, the closest preceding if that doesn't have an else). In the case of the preceding example, the else belongs to the second if statement in the listing. With proper indenting, it would look like this:

if (exam. done())
    if (exam.getScore() < 0.61)
    System.out.println("Try again.");
    // Which if does this belong to?
    else
        System.out.println("Java master!");

Following our coding conventions by using curly braces, it would be even easier to read:

if (exam.done()) {
    if (exam.getScore() < 0.61) {
        System.out.println("Try again.");
    // Which if does this belong to?
    } else {
        System.out.println("Java master!");
    }
}

Don't get your hopes up about the exam questions being all nice and indented properly. Some exam takers even have a slogan for the way questions are presented on the exam: anything that can be made more confusing, will be.

Be prepared for questions that not only fail to indent nicely, but intentionally indent in a misleading way: Pay close attention for misdirection like the following:

if (exam. done())
    if (exam.getScore() < 0.61)
        System.out.println("Try again.");
else
    System.out.println("Java master!");    // Hmmmmm ... now where does
                        // it belong?

Of course, the preceding code is exactly the same as the previous two examples, except for the way it looks.

Given:

1. public class Test{
2.     public static void main(String[] args){
3.         int x = 5;
4.         boolean b1 = true;
5.         boolean b2 = false;
6.
7.         if((x==4) && !b2)
8.             System.out.print("1 ");
9.             System.out.print("2 ");
10.         if((b2=true) && b1)
11.             System.out.print("3 ");
12.     }
13. }

What is the result?

A. 2
B. 3
C. 1 2
D. 2 3
E. 1 2 3
F. Compilation fails.
G. An exception is thrown at runtime.


Given:

22. public void go(){
23.     String o = "";
24.     z:
25.     for(int x=0; x<3; x++){
26.         for(int y=0; y<2; y++){
27.             if(x == 1) break;
28.             if(x==2 && y==1) break z;
29.             o = o + x + y;
30.         }
31.     }
32.     System.out.println(o);
33. }

What is the result when the go() method is invoked?

A. 00
B. 0001
C. 000120
D. 00012021
E. Compilation fails.
F. An exception is thrown at runtime.

Compound Assignment Operators

There are actually 11 or so compound assignment operators, but only the four most commonly used (+=, -=, *=, and /=),are on the exam (despite what the objectives say).
The compound assignment operators let lazy typists shave a few keystrokes off their workload. Here are several example assignments, first without using a compound operator,

y =  y - 6;
x = x + 2 * 5;

Now, with compound operators:

y -= 6;
x += 2 * 5;

The last two assignments give the same result as the first two.

Given:

1. public class TestString1{
2.     public static void main(String[] args){
3.         String str = "420";
4.         str += 42;
5.         System.out.print(str);
6.     }
7. }

What is the output?

A. 42
B. 420
C. 462
D. 42042
E. Compilation fails.
F. An exception is thrown at runtime.

Java Keywords

List of Java Keywords (assert  added in 1.4, enum added in 1.5)

abstract
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
extends
final
finally
float
for
goto
if
implements
import
instanceof
int
interface
long
native
new
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
throw
throws
transient
try
void
volatile
while
assert
enum

Legal Identifiers

Technically, legal identifiers must be composed of only Unicode characters, numbers, currency symbols, and connecting characters (like underscores). The exam doesn't dive into the details of which ranges of the Unicode character set are considered to qualify as letters and digits. So, for example, you won't need to know that Tibetan digits range from \u0420 to \uOf29. Here are the rules you do need to know:
  • Identifiers must start with a letter, a currency character ($), or a connecting character such as the underscore ( _ ). Identifiers cannot start with a number!
  • After the first character, identifiers can contain any combination of letters, currency characters, connecting characters, or numbers.
  • In practice, there is no limit to the number of characters an identifier can contain.
  • You can't use a Java keyword as an identifier.
  • Identifiers in Java are case-sensitive; foo and Foo are two different identifiers.

Examples of legal and illegal identifiers follow, first some legal identifiers:

int _a;
int $c;
int ______2_w;
int _$;
int this_is_a_very_detailed_name_for_an_identifier;

The following are illegal (it's your job to recognize why):

int :b;
int -d;
int e#;
int .f;
int 7g;

Given:

35. String #name = "Jane Doe"; 
36. int $age = 24; 
37. Double _height = 123.5; 
38. double ~temp = 37.5; 

Which two statements are true? (Choose two.)

A. Line 35 will not compile.
B. Line 36 will not compile.
C. Line 37 will not compile.
D. Line 38 will not compile.