Appendix E Solutions to Programming Exercises

1 Basics of Java Programming

1.1 The printStackElements() method of the PrintableCharStack class does not pop the elements.

//Filename: PrintableCharStack.java
public class PrintableCharStack extends CharStack {                 // (1)

  // Instance method
  public void printStackElements() {                                // (2)
    for (int i = 0; i <= topOfStack; i++)
      System.out.print(stackArray[i]); // print each char on terminal
    System.out.println();
  }

  // Constructor calls the constructor of the superclass explicitly.
  PrintableCharStack(int capacity) { super(capacity); }             // (3)
}

//Filename: Client.java
public class Client {

  public static void main(String[] args) {

    // Create a printable character stack.
    PrintableCharStack stack = new PrintableCharStack(40);

    // Create a string to push on the stack:
    String str = "!no tis ot nuf era skcatS";
    int length = str.length();

    // Push the string char by char onto the stack:
    for (int i = 0; i < length; i++) {
      stack.push(str.charAt(i));
    }

    System.out.print("Stack contents: ");

    stack.printStackElements();

    // Pop and print each char from the stack:
    while (!stack.isEmpty()) {
      System.out.print(stack.pop());
    }
    System.out.println();

    System.out.print("Stack contents: ");
    stack.printStackElements();
  }
}


2 Language Fundamentals

2.1 The following program compiles and runs without errors:

//Filename: Temperature.java
/* Identifiers and keywords in Java are case-sensitive. Therefore, the
   case of the file name must match the class name, the keywords must
   all be written in lowercase. The name of the String class has a
   capital S. The main method must be static and take an array of
   String objects as an argument. */
public class Temperature {
  public static void main(String[] args) {  // Correct method signature
    double fahrenheit = 62.5;
    // /* identifies the start of a "starred" comment.
    // */ identifies the end.
    /* Convert */
    double celsius = f2c(fahrenheit);
    // '' delimits character literals, "" delimits string literals.
    // Only first character literal is quoted as string to avoid addition.
    // The second char literal is implicitly converted to its string
    // representation, as string concatenation is performed by
    // the last + operator.
    // Java is case-sensitive. The name Celsius should be changed to
    // the variable name celsius.
    System.out.println(fahrenheit + "F" + " = " + celsius + 'C'),
  }
  /* Method should be declared static. */
  static double f2c(double fahr) {  // Note parameter type should be double.
    return (fahr - 32) * 5 / 9;
  }
}


3 Declarations

3.1

/** A JavaBean for an editing context */
public class EditContext {             // Non-generic version
  private Object selected;
  public void setSelected(Object newSelected) {
    selected = newSelected;
  }
  public Object getSelected() {
    return selected;
  }
}


3.2

public class QuizGrader {

  /** Enum type to represent the result of answering a question. */
  enum Result { CORRECT, WRONG, UNANSWERED }

  public static final int PASS_MARK = 5;

  public static void main(String[] args) {

    String[] correctAnswers = { "C", "A", "B", "D", "B", "C", "C", "A" };

    System.out.println("Question  Submitted Ans. Correct Ans.  Result");

    // Counters for misc. statistics:
    int numOfCorrectAnswers = 0;
    int numOfWrongAnswers = 0;
    int numOfUnanswered = 0;

    // Loop through submitted answers and correct answers:
    for (int i = 0; i < args.length; i++) {
      String submittedAnswer = args[i];
      String correctAnswer = correctAnswers[i];
      Result result = determineResult(submittedAnswer, correctAnswer);

      // Print report for current question.
      System.out.printf("%5d%10s%15s%15s%n",
                         i+1, submittedAnswer, correctAnswer, result);
      // Accumulate statistics.
      switch(result) {
        case CORRECT: numOfCorrectAnswers++; break;
        case WRONG: numOfWrongAnswers++; break;
        case UNANSWERED: numOfUnanswered++; break;
      }
    }
    // Print summary of statistics.
    System.out.println("No. of correct answers:       " + numOfCorrectAnswers);
    System.out.println("No. of wrong answers:         " + numOfWrongAnswers);

    System.out.println("No. of questions unanswered:  " + numOfUnanswered);
    System.out.println("The candidate " +
                    (numOfCorrectAnswers >= PASS_MARK ? "PASSED." : "FAILED."));
  }

  /** Determines the result of answer to a question. */
  public static Result determineResult(String submittedAnswer,
                                       String correctAnswer) {
    Result result = null;
    if (submittedAnswer.equals(correctAnswer))
      result = Result.CORRECT;
    else if (submittedAnswer.equals("X"))
      result = Result.UNANSWERED;
    else
      result = Result.WRONG;
    return result;
  }
}


4 Access Control

4.1

//Filename: Account.java
package com.megabankcorp.records;

public class Account { }

//Filename: Database.java
// Specify package
package com.megabankcorp.system;

//Refer to the Account class by using the simple name Account.
import com.megabankcorp.records.Account;

// Class must be abstract since it has abstract methods.
public abstract class Database {

  // Abstract and available from anywhere.
  public abstract void deposit(Account acc, double amount);

  // Abstract and available from anywhere.
  public abstract void withdraw(Account acc, double amount);

  // Abstract and only available from package and subclasses.
  protected abstract double amount(Account acc);

  // Unmodifiable and only available from package.
  final void transfer(Account from, Account to, double amount) {
    withdraw(from, amount);
    deposit(to, amount);
  }
}


5 Operators and Expressions

5.1

//Filename: Sunlight.java
public class Sunlight {
  public static void main(String[] args) {
    // Distance from sun (150 million kilometers)
    /* The max value for int is 2147483647, so using int here will
       work. */
    int kmFromSun = 150000000;

    // Again, using int for this value is OK.
    int lightSpeed = 299792458; // Meters per second

    // Convert distance to meters.
    /* The result of this equation will not fit in an int. Let's
       use a long instead. We need to ensure that the values that
       are multiplied really are multiplied using long
       data types, and not multiplied as int data types and later
       converted to long. The L suffix on the 1000L integer
       literal ensures this. The value of kmFromSun will
       implicitly be converted from int to long to match the
       data type of the other factor. The conversion can be done
       implicitly by the compiler since the conversion represents
       a widening of the data type. */
    long mFromSun = kmFromSun * 1000L;

    /* We know that the result value will fit in an int.
       However, the narrowing conversion on assignment from long to int
       in this case requires a cast.*/
    int seconds = (int) (mFromSun / lightSpeed);

    System.out.print("Light will use ");
    printTime(seconds);
    System.out.println(" to travel from the sun to the earth.");
  }

  /* We leave this method alone. */
  public static void printTime(int sec) {
    int min = sec / 60;
    sec = sec - (min * 60);
    System.out.print(min + " minute(s) and " + sec + " second(s)");
  }
}


6 Control Flow

6.1 Finding primes using for-loops.

//Filename: ForPrimes.java
public class ForPrimes {
  final static int MAX = 100;
  public static void main( String[] args ) {
    numbers:
      for (int num = 1; num < MAX; num++) {
        int divLim = (int) Math.sqrt( num );
        for (int div = 2; div <= divLim; div++)
          if ((num % div) == 0) continue numbers;
        System.out.println( num );
      }
  }
}


Finding primes using while-loops.

//Filename: WhilePrimes.java
public class WhilePrimes {
  final static int MAX = 100;
  public static void main( String[] args ) {
    int num = 1;
    numbers:
      while (num < MAX) {
        int number = num++;
        int divLim = (int) Math.sqrt( number );
        int div = 2;
        while (div <= divLim)
          if ((number % div++) == 0) continue numbers;
        System.out.println( number );
      }
  }
}


6.2

package energy;
/** A PowerPlant with a reactor core.
    The solution presented here is provided by Jennie Yip. */
public class PowerPlant {
  /** Each power plant has a reactor core. This has package
      accessibility so that the Control class that is defined in
      the same package can access it. */
  Reactor core;

  /** Initializes the power plant, creates a reactor core. */
  PowerPlant() {
    core = new Reactor();
  }

  /** Sound the alarm to evacuate the power plant. */
  public void soundEvacuateAlarm() {
    // ... implementation unspecified ...
  }

  /** Get the level of reactor output that is most desirable at this time.
      (Units are unspecified.) */
  public int getOptimalThroughput() {
    // ... implementation unspecified ...
    return 0;
  }

  /** The main entry point of the program: sets up a PowerPlant
      object and a Control object and lets the Control object run the
      power plant. */
  public static void main(String[] args) {
    PowerPlant plant = new PowerPlant();
    Control ctrl = new Control(plant);
    ctrl.runSystem();
  }
}

/** A reactor core that has a throughput that can be either decreased or
    increased. */
class Reactor {
  /** Get the current throughput of the reactor. (Units are unspecified.) */
  public int getThroughput() {
    // ... implementation unspecified ...
    return 0;
  }

  /** @returns true if the reactor status is critical, false otherwise. */
  public boolean isCritical() {
    // ... implementation unspecified ...
    return false;
  }

  /** Ask the reactor to increase throughput. */
  void increaseThroughput() throws ReactorCritical {
    // ... implementation unspecified ...
  }

  /** Ask the reactor to decrease throughput. */
  void decreaseThroughput() {
    // ... implementation unspecified ...
  }
}

/** This exception class should be used to report that the reactor status is
    critical. */
class ReactorCritical extends Exception {}

/** A controller that will manage the power plant to make sure that the
    reactor runs with optimal throughput.  */
class Control {
  PowerPlant thePlant;

  final static int TOLERANCE = 10;

  public Control(PowerPlant p) {
    thePlant = p;
  }

  /** Run the power plant by continuously monitoring the
      optimalThroughput and the actual throughput of the reactor. If
      the throughputs differ by more than 10 units, i.e. tolerance,
      adjust the reactor throughput.
      If the reactor goes critical, the evacuate alarm is
      sounded and the reactor is shut down.
      <p>The runSystem() method does handle the reactor core directly
      but calls methods needAdjustment(), adjustThroughput(), and shutdown
      instead.  */
  public void runSystem() {
    try {
      while (true) { // infinite loop
        int optimalThroughput = thePlant.getOptimalThroughput();
        if (needAdjustment(optimalThroughput))
          adjustThroughput(optimalThroughput);
      }
    } catch (ReactorCritical rc) {
      thePlant.soundEvacuateAlarm();
    } finally {
      shutdown();
    }
  }

  /** Reports whether the throughput of the reactor needs
      adjusting. This method should also monitor and report if the
      reactor goes critical.
      @returns true if the optimal and actual throughput values
      differ by more than 10 units.  */
  public boolean needAdjustment(int target) throws ReactorCritical {
    /* We added the throws clause to the method declaration so that
       the method can throw a ReactorCritical exception if the reactor
       goes critical.  */
    if (thePlant.core.isCritical())
      throw new ReactorCritical();
    return Math.abs(thePlant.core.getThroughput() - target) > TOLERANCE;
  }

  /** Adjust the throughput of the reactor by calling increaseThroughput()
      and decreaseThroughput() until the actual throughput is within 10
      units of the target throughput.  */
  public void adjustThroughput(int target) throws ReactorCritical {
    /* We added the throws clause to the method declaration so that
       the method can pass on ReactorCritical exceptions thrown by
       increaseThroughput(). We do this because the adjustThroughput
       does not want to handle the exception.  */
    while (needAdjustment(target)) {
      if ((thePlant.core.getThroughput() - target) > TOLERANCE)
        thePlant.core.increaseThroughput();
      else

        thePlant.core.decreaseThroughput();
    }
  }

  /** Shut down the reactor by lowering the throughput to 0. */
  public void shutdown() {
    while (thePlant.core.getThroughput() > 0) {
      thePlant.core.decreaseThroughput();
    }
  }
}


7 Object-Oriented Programming

7.1

//Filename: Exercise1.java
package chap07_PE1;

interface Function {
  public int evaluate(int arg);
}

class Half implements Function {
  public int evaluate(int arg) {
    return arg/2;
  }
}

public class Exercise1 {

  public static int[] applyFunctionToArray(int[] arrIn) {
    int length = arrIn.length;
    int[] arrOut = new int[length];
    Function func = new Half();
    for (int i = 0; i < length; i++)
      arrOut[i] = func.evaluate(arrIn[i]);
    return arrOut;
  }

  public static void main(String[] args) {
    // Create array with values 1..10
    int length = 10;
    int[] myArr = new int[length];
    for (int i = 0; i < length;) myArr[i] = ++i;
    // Print array
    for (int value : myArr) System.out.println(value);
    // Half values
    myArr = applyFunctionToArray(myArr);
    // Print array again
    for (int value : myArr) System.out.println(value);
  }
}


7.2

package chap07_PE2;

//Filename: Exercise2.java
interface Function {
  public int evaluate(int arg);
}

class Half implements Function {
  public int evaluate(int arg) {
    return arg/2;
  }
}

class Print implements Function {
  public int evaluate(int arg) {
    System.out.println(arg);
    return arg;
  }
}

public class Exercise2 {

  public static int[] applyFunctionToArray(int[] arrIn, Function func) {
    int length = arrIn.length;
    int[] arrOut = new int[length];
    for (int i = 0; i < length; i++)
      arrOut[i] = func.evaluate(arrIn[i]);
    return arrOut;
  }

  public static void main(String[] args) {
    // Create array with values 1..10
    int length = 10;
    int[] myArr = new int[length];
    for (int i = 0; i < length;) myArr[i] = ++i;
    // Create a print function
    Function print = new Print();
    // Print array
    applyFunctionToArray(myArr, print);
    // Half values
    myArr = applyFunctionToArray(myArr, new Half());
    // Print array again
    applyFunctionToArray(myArr, print);
  }
}


8 Nested Type Declarations

8.1

//Filename: Exercise3.java
interface Function {
  public int evaluate(int arg);
}

class Half implements Function {
  public int evaluate(int arg) {
    return arg/2;
  }
}

class Print implements Function {
  public int evaluate(int arg) {
    System.out.println(arg);
    return arg;
  }
}

public class Exercise3 {
  /* Inner class that applies the function, prints the value, and
       returns the result. */
  static class PrintFunc extends Print {
    PrintFunc(Function f) {
      func = f;
    }
    Function func;
    public int evaluate(int arg) {
      return super.evaluate(func.evaluate(arg));
    }
  }

  // Inner class that just returns the argument unchanged.
  /* Use this when you want a PrintFunc object to print
       the argument as-is. */
  static class NoOpFunc implements Function {
    public int evaluate(int arg) {
      return arg;
    }
  }

  public static void main(String[] args) {
    // Create array with values 1 .. 10
    int[] myArr = new int[10];
    for (int i=0; i<10;) myArr[i] = ++i;
    // Print array without modification
    applyFunctionToArray(myArr, new PrintFunc(new NoOpFunc()));
    // Print halved values
    applyFunctionToArray(myArr, new PrintFunc(new Half()));
  }

  public static int[] applyFunctionToArray(int[] arrIn, Function func) {
    int length = arrIn.length;
    int[] arrOut = new int[length];
    for (int i=0; i< length; i++)
      arrOut[i] = func.evaluate(arrIn[i]);
    return arrOut;
  }
}


9 Object Lifetime

No programming exercises.

10 Fundamental Classes

10.1

/**
 * Aggregate (non-generic) pairs of arbitrary objects.
 */
public final class Pair {
  private Object first, second;

  /** Construct a Pair object. */
  public Pair(Object one, Object two) {
    first = one;
    second = two;
  }

  /** Provides access to the first aggregated object. */
  public Object getFirst() { return first; }

  /** Provides access to the second aggregated object. */
  public Object getSecond() { return second; }

  /** @return true if the pair of objects are identical. */
  public boolean equals(Object other) {
    if (! (other instanceof Pair)) return false;
    Pair otherPair = (Pair) other;
    return first.equals(otherPair.getFirst()) &&
           second.equals(otherPair.getSecond());
  }

  /** @return a hash code for the aggregate pair. */
  public int hashCode() {
    // XORing the hash codes to create a hash code for the pair.
    return first.hashCode() ^ second.hashCode();
  }

  /** @return the textual representation of the aggregated objects. */
  public String toString() {
    return "[" + first + "," + second + "]";
  }
}


10.2

/** Determine if a string is a palindrome. */
public class Palindrome {
  public static void main(String[] args) {
    if (args.length != 1) {
      System.out.println("Usage: java Palindrome <word>");
      return;
    }
    String word = args[0];
    StringBuilder reverseWord = new StringBuilder(word);
    reverseWord.reverse();
    boolean isPalindrome = word.equals(reverseWord.toString());
    System.out.println("The word " + word + " is " +
                       (isPalindrome ? "" : "not ") + "a palindrome");
  }
}


11 Files and Streams

11.1

//Filename: Convert.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class Convert {
  public static void main(String args[]) {

    String inEncoding  = "8859_1";
    String outEncoding = "UTF8";
    InputStream  inStream  = System.in;
    OutputStream outStream = System.out;

    try {
      try {
        inEncoding  = args[0];
        outEncoding = args[1];
        inStream  = new FileInputStream (args[2]);
        outStream = new FileOutputStream(args[3]);

      } catch (ArrayIndexOutOfBoundsException aioobe) {
        // Missing parameters are allowed.
      }
      BufferedReader reader = new BufferedReader(
          new InputStreamReader(inStream, inEncoding)
      );
      BufferedWriter writer = new BufferedWriter(
          new OutputStreamWriter(outStream, outEncoding)
      );
      // Transfer 512 chars at a time.
      char[] cbuf = new char[512];
      while (true) {
        int bytesLastRead = reader.read(cbuf);
        if (bytesLastRead == -1) break;
        writer.write(cbuf, 0, bytesLastRead);
        // Last two args was offset (none) and length.
      }
      reader.close();
      writer.close();
    } catch (FileNotFoundException fnfe) {
      System.err.println("File not found: " + fnfe.getLocalizedMessage());
    } catch (IOException ioe) {
      System.err.println("I/O error: " + ioe.getLocalizedMessage());
    } catch (SecurityException se) {
      System.err.println("Security Error: " + se.getLocalizedMessage());
    }
  }
}


12 Localization, Pattern Matching, and Formatting

12.1

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class VerySimpleGrep {
  public static void main(String[] args) throws IOException {
    // Test file
    FileWriter fw = new FileWriter("test.txt");
    fw.write("To be or not to be. ");
    fw.write("Only As, no Bs. ");
    fw.write("A bee movie is not funny. ");
    fw.write("Bessy was a beautiful beatnik from Bern. ");
    fw.close();
    String fileName = "test.txt";
    String regexStr = "[bB]e";
    grepFile(fileName, regexStr);

    // Test on this file:
    fileName = "VerySimpleGrep.java";
    regexStr = "[a-zA-Z_$][a-zA-Z0-9_$]*";
    grepFile(fileName, regexStr);

    // Read file name and regex as program arguments:
    fileName = args[0];
    regexStr = args[1];
    grepFile(fileName, regexStr);
  }

  /**
   * Finds and prints matches for the regex in the text file.
   * @param fileName
   * @param regex
   * @throws IOException
   */
  public static void grepFile(String fileName, String regex)
                              throws IOException {
    Pattern pattern = Pattern.compile(regex);
    BufferedReader source = new BufferedReader(new FileReader(fileName));
    int lineNum = 1;
    String line = source.readLine();
    while (line != null ) {
      if (!line.equals("")) {
        List<String> matchList = grepLine(pattern, line);
        if (matchList.size() != 0)
          System.out.println(lineNum + ": " + matchList);
      }
      lineNum++;
      line = source.readLine();
    }
    source.close();
  }

  /**
   * Finds the matches for the pattern in the target.
   * @param pattern
   * @param target
   * @return List<String> with the matches found in the target
   */
  public static List<String> grepLine(Pattern pattern, String target) {
    Matcher matcher = pattern.matcher(target);
    List<String> matchList = new ArrayList<String>();
    while(matcher.find()) {
      int startCharIndex = matcher.start();
      int lastPlus1Index = matcher.end();
      int lastCharIndex = startCharIndex == lastPlus1Index ?
          lastPlus1Index : lastPlus1Index-1;
      String matchedStr = matcher.group();
      matchList.add("(" + startCharIndex + "," + lastCharIndex + ":" +
          matchedStr + ")");
    }
    return matchList;
  }
}


12.2

import static java.lang.System.out;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Pattern;

public class CSVReader {
  public static void main(String[] args) throws IOException {
    FileWriter fw = new FileWriter("csv.txt");
    fw.write("2.5,25,250 ");
    fw.write("Hi,Hello,Howdy ");
    fw.write("2008,2009,2010 ");
    fw.write("one,two,three ");
    fw.close();
    BufferedReader source = new BufferedReader(new FileReader("csv.txt"));
    readCSV(source, 3);
    source.close();
  }
  /**
   * Reads values in CSV format.
   * @param source
   * @param numOfFields
   * @throws IOException
   */
  public static void readCSV(Readable source,
                             int numOfFields)throws IOException {
    Scanner lexer = new Scanner(source);
    Pattern csvPattern = compileCSVPattern(numOfFields);
    out.println("Pattern: " + csvPattern.pattern());
    Pattern splitPattern = Pattern.compile(",");
    while (lexer.hasNextLine()) {
      // Match fields on the line
      String record = lexer.findInLine(csvPattern);
      if (record != null) {
        // Split the record on the split pattern:
        String[] fields = splitPattern.split(record, numOfFields);
        out.println(Arrays.toString(fields));
      }
      lexer.nextLine();          // Clear line separator to continue.
    }
    IOException ioe = lexer.ioException();
    if (ioe != null)
      throw ioe;
  }

  /**
   * Creates a multiline-mode pattern that corresponds to the number of fields
   * specified in CSV format on each line/record:
   * ([^,]+),...,([^,]+)
   * Alternative regular expressions for CSV:

   * ^([^,]+),...,([^,]+)
   * ([^,]+),...,([^,]+)$
   * ^([^,]+),...,([^,]+)$
   * (.+),...,(.+)
   *
   * @param numOfFields
   * @return Pattern to match all the field values.
   */
  public static Pattern compileCSVPattern(int numOfFields) {
    assert numOfFields >= 1;
    String fieldPattern = "([^,]+)";
    String patternStr = fieldPattern;
    for (int i = 2; i <= numOfFields; i++) {
      patternStr += "," + fieldPattern;
    }
    return Pattern.compile(patternStr, Pattern.MULTILINE);
  }
}


13 Threads

13.1

//Filename: Counter.java
/*
    Notice that the result of running this program
    may not be what you expect. Since both threads are
    working full throttle it is possible that only one
    of the threads is granted CPU time.
 */

public class Counter implements Runnable {
  public static void main(String[] args) {
    Storage store = new Storage();
    new Counter(store);
    new Printer(store);
  }
  Storage storage;
  Counter(Storage target) {
    storage = target;
    new Thread(this).start();
  }
  public void run() {
    int i=0;
    while (true) {
      storage.setValue(i);
      i++;
    }
  }
}

class Printer implements Runnable {
  Storage storage;

  Printer(Storage source) {
    storage = source;
    new Thread(this).start();
  }
  public void run() {
    while (true) {
      System.out.println(storage.getValue());
    }
  }
}

class Storage {
  int value;
  void setValue(int i) { value = i; }
  int getValue() { return value; }
}


13.2

//Filename: Counter.java
package pe13_2;
/* Only the Storage class has been altered. */

/* No change to this class */
public class Counter implements Runnable {
  public static void main(String[] args) {
    Storage store = new Storage();
    new Counter(store);
    new Printer(store);
  }
  Storage storage;
  Counter(Storage s) {
    storage = s;
    new Thread(this).start();
  }
  public void run() {
    int i=0;
    while (true) {
      storage.setValue(i);
      i++;
    }
  }
}

/* No changes to this class. */
class Printer implements Runnable {
  Storage storage;
  Printer(Storage s) {
    storage = s;
    new Thread(this).start();
  }
  public void run() {
    while (true) {
      System.out.println(storage.getValue());
    }
  }
}

/* This class now ensures that getting and setting are done
   in an alternating fashion.
 */
class Storage {
  int value;
  boolean isUnread = false;
  synchronized void setValue(int i) {
    ensureUnread(false);
    value = i;
    setUnread(true);
  }
  synchronized int getValue() {
    ensureUnread(true);
    setUnread(false);
    return value;
  }
  private void ensureUnread(boolean shouldHaveUnread) {
    while (shouldHaveUnread != isUnread)
      try { wait(); }
      catch (InterruptedException ie) {}
  }
  private void setUnread(boolean b) {
    isUnread = b;
    notify();
  }
}


14 Generics

14.1

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Utilities {

  /** Convert Map to MultiMap */
  public static <K,V> Map<V,List<K>> toMultiMap(Map<K,V> origMap) {
    Map<V, List<K>> multiMap = new HashMap<V,List<K>>();
    Collection<K> keys = origMap.keySet();
    for (K key : keys) {
      V value = origMap.get(key);
      List<K> valueList = multiMap.get(value);
      if (valueList == null) {
        valueList = new ArrayList<K>();
        multiMap.put(value, valueList);
      }
      valueList.add(key);
    }
    return multiMap;
  }
}


14.2

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class GraphTraversal {

  public static void main(String[] args) {
    // (1) Given a directed graph with five vertices:
    Integer[][] neighbors = {
        {1, 3},  // Vertex 0
        {2},     // Vertex 1
        {4},     // Vertex 2
        {1, 2},  // Vertex 3
        {}       // Vertex 4
    };
    Map<Integer, Collection<Integer>> graph
                 = new HashMap<Integer, Collection<Integer>>();
    for (int i = 0; i < neighbors.length; i++) {
      graph.put(i, Arrays.asList(neighbors[i]));
    }

    // (2) Get the start vertex.
    int startVertex;
    try {
      startVertex = Integer.parseInt(args[0]);
    } catch (ArrayIndexOutOfBoundsException ive) {
      System.out.println("Usage: java GraphTraversal [0-4]");
      return;
    } catch (NumberFormatException nfe) {
      System.out.println("Usage: java GraphTraversal [0-4]");
      return;
    }

    Set<Integer> visitedSet = GraphTraversal.findVerticesOnPath(graph,
                                                                startVertex);
    System.out.print("Vertex " + startVertex + " is connected to " + visitedSet);
  }

  /**
   * Finds the vertices on a path from a given vertex in a directed graph.
   * In the map, the key is a vertex, and the value is the collection
   * containing its neighbours.
   */
  public static <N> Set<N> findVerticesOnPath(
                Map<N,Collection<N>> graph, N startVertex) {
    // (3) Create a stack for traversing the graph:
    MyStack<N> traversalStack = new MyStack<N>();

    // (4) Create a set for visited vertices:
    Set<N> visitedSet = new HashSet<N>();

    // (5) Push start vertex on the stack:
    traversalStack.push(startVertex);
    // (6) Handle each vertex found on the stack:
    while (!traversalStack.isEmpty()) {
      N currentVertex = traversalStack.pop();
      // (7) Check if current vertex has been visited.
      if (!visitedSet.contains(currentVertex)) {
        // (8) Add the current vertex to the visited set.
        visitedSet.add(currentVertex);
         // (9) Push neighbors of current vertex on to the stack.
        Collection<N> neighbors = graph.get(currentVertex);
        for (N neighbor : neighbors)
            traversalStack.push(neighbor);
      }
    }
    visitedSet.remove(startVertex);
    return visitedSet;
  }
}


15 Collections and Maps

15.1

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class UniqueCharacterCounter {
  /**
   * A cache, mapping strings to number of unique characters in them.
   */
  static Map<String, Integer> globalCache = new HashMap<String, Integer>();

  public static int countUniqueCharacters(String aString) {
    Integer cachedResult = globalCache.get(aString);
    if (cachedResult != null)
      return cachedResult;
    // Result was not in the cache, calculate it.
    int length = aString.length();
    Set<Character> distinct = new TreeSet<Character>();
    Set<Character> duplicates = new TreeSet<Character>();
    // Determine whether each distinct character in the string is duplicated:
    for (int i = 0; i < length; i++) {
      Character character = aString.charAt(i);
      if (duplicates.contains(character))
        continue;
      boolean isDistinct = distinct.add(character);
      if (!isDistinct)
        duplicates.add(character);
    }

    // Remove duplicates from the distinct set to obtain unique characters:
    distinct.removeAll(duplicates);
    int result = distinct.size();
    // Put result in cache before returning:
    globalCache.put(aString, result);
    return result;
  }

  /**
   * Demonstrate the cache for mapping strings to number of unique characters
   * in them.
   * Prints the result of applying the operation to each command line argument.
   */
  public static void main(String[] args) {
    int nArgs = args.length;
    for (int i = 0; i < nArgs; i++) {
      String argument = args[i];
      int result = countUniqueCharacters(argument);
      System.out.println(argument + ": " + result);
    }
  }
}


15.2

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Concordance {

  /** Map for the concordance. */
  public Map<Character, List<Integer>> indexMap =
      new HashMap<Character, List<Integer>>();

  /** Add each character and its index to the concordance */
  public Concordance(StringBuilder input) {
    for (int i = 0; i < input.length(); ++i) {
      addEntry(input.charAt(i), i);
    }
  }

  /** Update the list of indices for a given character */
  void addEntry(char key, int pos) {
    List<Integer> hits = indexMap.get(key);
    if (hits == null) {
      hits = new ArrayList<Integer>();
      indexMap.put(key, hits);
    }
    hits.add(pos);
  }

  public static void main(String[] args) {
    StringBuilder input = new StringBuilder();
    for (int i = 0; i < args.length; ++i)
      input.append(args[i]);
    Concordance conc = new Concordance(input);
    System.out.println(conc.indexMap);
  }
}


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset