-
[Thinking in Java练习题](十四)多线程
2006年08月29日
/****************** Exercise 1 ******************
* Inherit a class from Thread and override the
* run() method. Inside run(), print a message,
* and then call sleep(). Repeat this three
* times, then return from run(). Put a start-up
* message in the constructor and override
* finalize() to print a shut-down message. Make
* a separate thread class that calls System.gc()
* and System.runFinalization() inside run(),
* printing a message as it does so. Make several
* thread objects of both types and run them to
* see what happens.
***********************************************/class Gc extends Thread{
static int count = 0;
int index;
Gc(){
count++;
index = count;
}
public String toString(){
return "Gc #" + index;
}
public void run(){
System.out.println(this + " gc");
System.gc();
System.out.println(this + " runFinalization");
System.runFinalization();
}
}public class Ex01 extends Thread {
static int count = 0;
int index;
Ex01(){
count++;
index = count;
}
public String toString(){
return "Ex01 #" + index;
}
public void run(){
System.out.println(this + " running");
try{
sleep(500);
}catch(Exception e){
e.printStackTrace();
}
}
public void finalize (){
System.out.println(this + " Complete, finalize");
}
public static void main(String args[]){
for (int i=10;i>0;i--){
Ex01 ex = new Ex01();
Gc gc = new Gc();
ex.run();
gc.run();
}
}
}/****************** Exercise 2 ******************
* Modify Sharing2.java to add a synchronized
* block inside the run() method of TwoCounter
* instead of synchronizing the entire run()
* method.
***********************************************/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;public class
Ex02 extends JApplet {
TwoCounter[] s;
private static int accessCount = 0;
private static JTextField aCount =
new JTextField("0", 7);
public static void incrementAccess() {
accessCount++;
aCount.setText(Integer.toString(accessCount));
}
private JButton
start = new JButton("Start"),
watcher = new JButton("Watch");
private boolean isApplet = true;
private int numCounters = 12;
private int numWatchers = 15;class TwoCounter extends Thread {
private boolean started = false;
private JTextField
t1 = new JTextField(5),
t2 = new JTextField(5);
private JLabel l =
new JLabel("count1 == count2");
private int count1 = 0, count2 = 0;
public TwoCounter() {
JPanel p = new JPanel();
p.add(t1);
p.add(t2);
p.add(l);
getContentPane().add(p);
}
public void start() {
if(!started) {
started = true;
super.start();
}
}
public void /* synchronized */ run() {
while (true) {
// New:
synchronized(this) {
t1.setText(Integer.toString(count1++));
t2.setText(Integer.toString(count2++));
}
try {
sleep(500);
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
}
}
public synchronized void synchTest() {
incrementAccess();
if(count1 != count2)
l.setText("Unsynched");
}
}class Watcher extends Thread {
public Watcher() { super.start(); }
public void run() {
while(true) {
for(int i = 0; i < s.length; i++)
s[i].synchTest();
try {
sleep(500);
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
}
}
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < s.length; i++)
s[i].start();
}
}
class WatcherL implements ActionListener {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < numWatchers; i++)
new Watcher();
}
}
public void init() {
if(isApplet) {
String counters = getParameter("size");
if(counters != null)
numCounters = Integer.parseInt(counters);
String watchers = getParameter("watchers");
if(watchers != null)
numWatchers = Integer.parseInt(watchers);
}
s = new TwoCounter[numCounters];
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
for(int i = 0; i < s.length; i++)
s[i] = new TwoCounter();
JPanel p = new JPanel();
start.addActionListener(new StartL());
p.add(start);
watcher.addActionListener(new WatcherL());
p.add(watcher);
p.add(new Label("Access Count"));
p.add(aCount);
cp.add(p);
}
public static void main(String args[]) {
Ex02 applet = new Ex02();
// This isn't an applet, so set the flag and
// produce the parameter values from args:
applet.isApplet = false;
applet.numCounters =
(args.length == 0 ? 12 :
Integer.parseInt(args[0]));
applet.numWatchers =
(args.length < 2 ? 15 :
Integer.parseInt(args[1]));
Console.run(applet, 350,
applet.numCounters * 50);
}
}/****************** Exercise 3 ******************
* Create two Thread subclasses, one with a run()
* that starts up and then calls wait(). The
* other class should capture the reference of
* the first Thread object. Its run()should call
* notifyAll() for the first thread after some
* number of seconds have passed, so the first
* thread can print a message.
***********************************************/
class Coop1 extends Thread {
public Coop1() {
System.out.println("Constructed Coop1");
start();
}
public void run() {
System.out.println("Coop1 going into wait");
synchronized(this) {
try {
wait();
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
}
System.out.println("Coop1 exited wait");
}
}class Coop2 extends Thread {
Coop1 otherThread;
public Coop2(Coop1 otherThread) {
this.otherThread = otherThread;
System.out.println("Constructed Coop2");
start();
}
public void run() {
System.out.println("Coop2 pausing 5 secs");
try {
sleep(5000);
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
System.out.println("Coop2 calling notifyAll");
synchronized(otherThread) {
otherThread.notifyAll();
}
}
}public class Ex03 {
public static void main(String args[]) {
new Coop2(new Coop1());
}
}/****************** Exercise 4 ******************
* In Counter5.java inside Ticker2, remove the
* yield() and explain the results. Replace the
* yield() with a sleep() and explain the
* results.
***********************************************/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;class Ticker2 extends Thread {
private JButton
b = new JButton("Toggle"),
incPriority = new JButton("up"),
decPriority = new JButton("down");
private JTextField
t = new JTextField(10),
pr = new JTextField(3); // Display priority
private int count = 0;
private boolean runFlag = true;
public Ticker2(Container c) {
b.addActionListener(new ToggleL());
incPriority.addActionListener(new UpL());
decPriority.addActionListener(new DownL());
JPanel p = new JPanel();
p.add(t);
p.add(pr);
p.add(b);
p.add(incPriority);
p.add(decPriority);
c.add(p);
}
class ToggleL implements ActionListener {
public void actionPerformed(ActionEvent e) {
runFlag = !runFlag;
}
}
class UpL implements ActionListener {
public void actionPerformed(ActionEvent e) {
int newPriority = getPriority() + 1;
if(newPriority > Thread.MAX_PRIORITY)
newPriority = Thread.MAX_PRIORITY;
setPriority(newPriority);
}
}
class DownL implements ActionListener {
public void actionPerformed(ActionEvent e) {
int newPriority = getPriority() - 1;
if(newPriority < Thread.MIN_PRIORITY)
newPriority = Thread.MIN_PRIORITY;
setPriority(newPriority);
}
}
public void run() {
while (true) {
if(runFlag) {
t.setText(Integer.toString(count++));
pr.setText(
Integer.toString(getPriority()));
}
// yield();
try {
sleep(1);
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
}
}
}class Counter5 extends JApplet {
private JButton
start = new JButton("Start"),
upMax = new JButton("Inc Max Priority"),
downMax = new JButton("Dec Max Priority");
private boolean started = false;
private static final int SIZE = 10;
private Ticker2[] s = new Ticker2[SIZE];
private JTextField mp = new JTextField(3);
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
for(int i = 0; i < s.length; i++)
s[i] = new Ticker2(cp);
cp.add(new JLabel(
"MAX_PRIORITY = " + Thread.MAX_PRIORITY));
cp.add(new JLabel("MIN_PRIORITY = "
+ Thread.MIN_PRIORITY));
cp.add(new JLabel("Group Max Priority = "));
cp.add(mp);
cp.add(start);
cp.add(upMax);
cp.add(downMax);
start.addActionListener(new StartL());
upMax.addActionListener(new UpMaxL());
downMax.addActionListener(new DownMaxL());
showMaxPriority();
// Recursively display parent thread groups:
ThreadGroup parent =
s[0].getThreadGroup().getParent();
while(parent != null) {
cp.add(new Label(
"Parent threadgroup max priority = "
+ parent.getMaxPriority()));
parent = parent.getParent();
}
}
public void showMaxPriority() {
mp.setText(Integer.toString(
s[0].getThreadGroup().getMaxPriority()));
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(!started) {
started = true;
for(int i = 0; i < s.length; i++)
s[i].start();
}
}
}
class UpMaxL implements ActionListener {
public void actionPerformed(ActionEvent e) {
int maxp =
s[0].getThreadGroup().getMaxPriority();
if(++maxp > Thread.MAX_PRIORITY)
maxp = Thread.MAX_PRIORITY;
s[0].getThreadGroup().setMaxPriority(maxp);
showMaxPriority();
}
}
class DownMaxL implements ActionListener {
public void actionPerformed(ActionEvent e) {
int maxp =
s[0].getThreadGroup().getMaxPriority();
if(--maxp < Thread.MIN_PRIORITY)
maxp = Thread.MIN_PRIORITY;
s[0].getThreadGroup().setMaxPriority(maxp);
showMaxPriority();
}
}
}public class Ex04 {
public static void main(String args[]) {
Console.run(new Counter5(), 450, 600);
}
}/****************** Exercise 5 ******************
* In ThreadGroup1.java, replace the call to
* sys.suspend() with a call to wait() for the
* thread group, causing it to wait for two
* seconds. For this to work correctly you must
* acquire the lock for sys inside a synchronized
* block.
***********************************************/
public class Ex05 {
public static void main(String[] args) {
// Get the system thread & print its Info:
ThreadGroup sys =
Thread.currentThread().getThreadGroup();
sys.list(); // (1)
// Reduce the system thread group priority:
sys.setMaxPriority(Thread.MAX_PRIORITY - 1);
// Increase the main thread priority:
Thread curr = Thread.currentThread();
curr.setPriority(curr.getPriority() + 1);
sys.list(); // (2)
// Attempt to set a new group to the max:
ThreadGroup g1 = new ThreadGroup("g1");
g1.setMaxPriority(Thread.MAX_PRIORITY);
// Attempt to set a new thread to the max:
Thread t = new Thread(g1, "A");
t.setPriority(Thread.MAX_PRIORITY);
g1.list(); // (3)
// Reduce g1's max priority, then attempt
// to increase it:
g1.setMaxPriority(Thread.MAX_PRIORITY - 2);
g1.setMaxPriority(Thread.MAX_PRIORITY);
g1.list(); // (4)
// Attempt to set a new thread to the max:
t = new Thread(g1, "B");
t.setPriority(Thread.MAX_PRIORITY);
g1.list(); // (5)
// Lower the max priority below the default
// thread priority:
g1.setMaxPriority(Thread.MIN_PRIORITY + 2);
// Look at a new thread's priority before
// and after changing it:
t = new Thread(g1, "C");
g1.list(); // (6)
t.setPriority(t.getPriority() -1);
g1.list(); // (7)
// Make g2 a child Threadgroup of g1 and
// try to increase its priority:
ThreadGroup g2 = new ThreadGroup(g1, "g2");
g2.list(); // (8)
g2.setMaxPriority(Thread.MAX_PRIORITY);
g2.list(); // (9)
// Add a bunch of new threads to g2:
for (int i = 0; i < 5; i++)
new Thread(g2, Integer.toString(i));
// Show information about all threadgroups
// and threads:
sys.list(); // (10)
System.out.println("Starting all threads:");
Thread[] all = new Thread[sys.activeCount()];
sys.enumerate(all);
for(int i = 0; i < all.length; i++)
if(all[i] != null && !all[i].isAlive())
all[i].start();
System.out.println("All threads started. " +
"Going into wait() for two seconds");
synchronized(sys) {
try {
sys.wait(2000);
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
}
System.out.println("Wait finished");
}
}/****************** Exercise 6 ******************
* Change Daemons.java so that main() has a
* sleep() instead of a readLine(). Experiment
* with different sleep times to see what
* happens.
***********************************************/
import java.io.*;class Daemon extends Thread {
private static final int SIZE = 10;
private Thread[] t = new Thread[SIZE];
public Daemon() {
setDaemon(true);
start();
}
public void run() {
for(int i = 0; i < SIZE; i++)
t[i] = new DaemonSpawn(i);
for(int i = 0; i < SIZE; i++)
System.out.println(
"t[" + i + "].isDaemon() = "
+ t[i].isDaemon());
while(true)
yield();
}
}class DaemonSpawn extends Thread {
public DaemonSpawn(int i) {
System.out.println(
"DaemonSpawn " + i + " started");
start();
}
public void run() {
while(true)
yield();
}
}public class Ex06 {
public static void main(String[] args)
throws IOException {
Thread d = new Daemon();
System.out.println(
"d.isDaemon() = " + d.isDaemon());
// Allow the daemon threads to
// finish their startup processes:
try {
d.sleep(80);
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
}
}/****************** Exercise 7 ******************
* In Chapter 8, locate the
* GreenhouseControls.java example, which
* consists of three files. In Event.java, the
* class Event is based on watching the time.
* Change Event so that it is a Thread, and
* change the rest of the design so that it works
* with this new Thread-based Event.
***********************************************/
import java.util.*;abstract class Event extends Thread {
private long delay;
public Event(long delayTime) {
delay = delayTime;
start();
}
public void run() {
try {
sleep(delay);
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
action();
System.out.println(description());
}
abstract public void action();
abstract public String description();
}class GreenhouseControls {
// List events = new ArrayList();
private boolean light = false;
private boolean water = false;
private String thermostat = "Day";
private class LightOn extends Event {
public LightOn(long delayTime) {
super(delayTime);
}
public void action() {
// Put hardware control code here to
// physically turn on the light.
light = true;
}
public String description() {
return "Light is on";
}
}
private class LightOff extends Event {
public LightOff(long delayTime) {
super(delayTime);
}
public void action() {
// Put hardware control code here to
// physically turn off the light.
light = false;
}
public String description() {
return "Light is off";
}
}
private class WaterOn extends Event {
public WaterOn(long delayTime) {
super(delayTime);
}
public void action() {
// Put hardware control code here
water = true;
}
public String description() {
return "Greenhouse water is on";
}
}
private class WaterOff extends Event {
public WaterOff(long delayTime) {
super(delayTime);
}
public void action() {
// Put hardware control code here
water = false;
}
public String description() {
return "Greenhouse water is off";
}
}
private class ThermostatNight extends Event {
public ThermostatNight(long delayTime) {
super(delayTime);
}
public void action() {
// Put hardware control code here
thermostat = "Night";
}
public String description() {
return "Thermostat on night setting";
}
}
private class ThermostatDay extends Event {
public ThermostatDay(long delayTime) {
super(delayTime);
}
public void action() {
// Put hardware control code here
thermostat = "Day";
}
public String description() {
return "Thermostat on day setting";
}
}
// An example of an action() that inserts a
// new one of itself into the event list:
private int rings;
private class Bell extends Event {
public Bell(long delayTime) {
super(delayTime);
}
public void action() {
// Ring every 2 seconds, 'rings' times:
System.out.println("Bing!");
if(--rings > 0)
new Bell(200);
}
public String description() {
return "Ring bell";
}
}
static int repeats = 3;
class Restart extends Event {
public Restart(long delayTime) {
super(delayTime);
}
public void action() {
if(--repeats < 0) return;
rings = 5;
new ThermostatNight(0);
new LightOn(100);
new LightOff(200);
new WaterOn(300);
new WaterOff(800);
new Bell(900);
new ThermostatDay(1000);
// Can even add a Restart object!
new Restart(2000);
}
public String description() {
return "Restarting system";
}
}
}public class Ex07 {
public static void main(String[] args) {
GreenhouseControls gc =
new GreenhouseControls();
gc.new Restart(1000);
}
}/****************** Exercise 8 ******************
* Modify Exercise 7 so that the java.util.Timer
* class found in JDK 1.3 is used to run the
* system.
***********************************************/
import java.util.*;abstract class Event_T extends TimerTask {
public Event_T(long eventDelay) {
new Timer().schedule(this, eventDelay);
}
// abstract public void action();
// Replace "action" with TimerTask's run()::
public void run() {
System.out.println(description());
}
abstract public String description();
}class GreenhouseControls_T {
private boolean light = false;
private boolean water = false;
private String thermostat = "Day";
private class LightOn extends Event_T {
public LightOn(long eventDelay) {
super(eventDelay);
}
public void run() {
// Put hardware control code here to
// physically turn on the light.
light = true;
super.run();
}
public String description() {
return "Light is on";
}
}
private class LightOff extends Event_T {
public LightOff(long eventDelay) {
super(eventDelay);
}
public void run() {
// Put hardware control code here to
// physically turn off the light.
light = false;
super.run();
}
public String description() {
return "Light is off";
}
}
private class WaterOn extends Event_T {
public WaterOn(long eventDelay) {
super(eventDelay);
}
public void run() {
// Put hardware control code here
water = true;
super.run();
}
public String description() {
return "Greenhouse water is on";
}
}
private class WaterOff extends Event_T {
public WaterOff(long eventDelay) {
super(eventDelay);
}
public void run() {
// Put hardware control code here
water = false;
super.run();
}
public String description() {
return "Greenhouse water is off";
}
}
private class ThermostatNight extends Event_T {
public ThermostatNight(long eventDelay) {
super(eventDelay);
}
public void run() {
// Put hardware control code here
thermostat = "Night";
super.run();
}
public String description() {
return "Thermostat on night setting";
}
}
private class ThermostatDay extends Event_T {
public ThermostatDay(long eventDelay) {
super(eventDelay);
}
public void run() {
// Put hardware control code here
thermostat = "Day";
super.run();
}
public String description() {
return "Thermostat on day setting";
}
}
// An example of an run() that inserts a
// new one of itself into the event list:
private int rings;
private class Bell extends Event_T {
public Bell(long eventDelay) {
super(eventDelay);
}
public void run() {
// Ring every 2 seconds, 'rings' times:
System.out.println("Bing!");
if(--rings > 0)
new Bell(200);
super.run();
}
public String description() {
return "Ring bell";
}
}
static int repeats = 3;
class Restart extends Event_T {
public Restart(long eventDelay) {
super(eventDelay);
}
public void run() {
super.run();
if(--repeats < 0) {
System.out.println("Finished");
// Must call this or threads keep the
// program running:
System.exit(0);
}
rings = 5;
new ThermostatNight(0);
new LightOn(100);
new LightOff(200);
new WaterOn(300);
new WaterOff(800);
new Bell(900);
new ThermostatDay(1000);
// Can even add a Restart object!
new Restart(2000);
}
public String description() {
return "Restarting system";
}
}
}public class Ex08 {
public static void main(String[] args) {
GreenhouseControls_T gc =
new GreenhouseControls_T();
gc.new Restart(0);
}
}/****************** Exercise 9 ******************
* Starting with SineWave.java from Chapter 13,
* create a program (an applet/application using
* the Console class) that draws an animated sine
* wave that appears to scroll past the viewing
* window like an oscilloscope, driving the
* animation with a Thread. The speed of the
* animation should be controlled with a
* java.swing.JSlider control.
***********************************************/
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;class SineDraw extends JPanel implements Runnable {
static final int SCALEFACTOR = 200;
int cycles;
int points;
double[] sines;
int[] pts;
Thread self;
int delay = 50;
JSlider speed = new JSlider(0, 100, 50);
double offset = 0;
SineDraw() {
super(new BorderLayout());
setCycles(5);
self = new Thread(this);
self.start();
speed.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
delay = speed.getValue();
}
});
add(BorderLayout.SOUTH, speed);
// So that left to right is slow to fast:
speed.setInverted(true);
}
public synchronized
void setCycles(int newCycles) {
cycles = newCycles;
points = SCALEFACTOR * cycles * 2;
sines = new double[points];
pts = new int[points];
for(int i = 0; i < points; i++) {
double radians = (Math.PI/SCALEFACTOR) * i;
sines[i] = Math.sin(radians);
}
repaint();
}
public void run() {
while(true) {
offset += 0.25;
synchronized(this) {
for(int i = 0; i < points; i++) {
double radians =
(Math.PI/SCALEFACTOR) * i + offset;
sines[i] = Math.sin(radians);
}
}
repaint();
try {
self.sleep(delay);
} catch(InterruptedException e) {
System.out.println(
"InterruptedException = " + e);
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
int maxWidth = getWidth();
double hstep =(double)maxWidth/(double)points;
int maxHeight = getHeight();
for(int i = 0; i < points; i++)
// Some adjustments here to compensate for
// the added JSlider in the panel:
pts[i] = (int)(sines[i] * maxHeight/2 * .89
+ maxHeight/2 * .91);
for(int i = 1; i < points; i++) {
int x1 = (int)((i - 1) * hstep);
int x2 = (int)(i * hstep);
int y1 = pts[i-1];
int y2 = pts[i];
g.drawLine(x1, y1, x2, y2);
}
}
}class SineWave extends JApplet {
SineDraw sines = new SineDraw();
JSlider cycles = new JSlider(1, 30, 5);
public void init() {
Container cp = getContentPane();
cp.add(sines);
cycles.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
sines.setCycles(
((JSlider)e.getSource()).getValue());
}
});
cp.add(BorderLayout.SOUTH, cycles);
}
}public class Ex09 {
public static void main(String[] args) {
Console.run(new SineWave(), 700, 400);
}
}/****************** Exercise 10 *****************
* Modify Exercise 9 so that multiple sine wave
* panels are created within the application. The
* number of sine wave panels should be
* controlled by HTML tags or command-line
* parameters.
***********************************************/
import com.bruceeckel.swing.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;class MultiSineWave extends JApplet {
boolean isApplet = true;
SineDraw[] sines;
int panels = 1;
JSlider cycles = new JSlider(1, 30, 5);
public void init() {
if (isApplet) {
String sz = getParameter("panels");
if(sz != null)
panels = Integer.parseInt(sz);
}
Container cp = getContentPane();
int side = Math.round(
(float)Math.sqrt((double)panels));
JPanel jp =
new JPanel(new GridLayout(side, side));
sines = new SineDraw[panels];
for(int i = 0; i < sines.length; i++) {
sines[i] = new SineDraw();
jp.add(sines[i]);
}
cp.add(jp);
cp.add(BorderLayout.SOUTH, cycles);
cycles.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
for(int i = 0; i < sines.length; i++)
sines[i].setCycles(
((JSlider)e.getSource()).getValue());
}});
}
}public class Ex10 {
public static void main(String[] args) {
MultiSineWave applet = new MultiSineWave();
applet.isApplet = false;
if(args.length != 0)
applet.panels = Integer.parseInt(args[0]);
else
applet.panels = 4;
Console.run(applet, 700, 400);
}
}/****************** Exercise 11 *****************
* Modify Exercise 9 so that the java.swing.Timer
* class is used to drive the animation. Note the
* difference between this and java.util.Timer.
***********************************************/
import com.bruceeckel.swing.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;class SineDraw_T extends JPanel {
static final int SCALEFACTOR = 200;
int cycles;
int points;
double[] sines;
int[] pts;
JSlider speed = new JSlider(0, 100, 50);
double offset = 0;
int delay = 50;
Timer timer = new Timer(delay,
new ActionListener() {
public void actionPerformed(ActionEvent e) {
offset += 0.25;
for(int i = 0; i < points; i++) {
double radians = (Math.PI/SCALEFACTOR)
* i + offset;
sines[i] = Math.sin(radians);
repaint();
}
}
});
SineDraw_T() {
super(new BorderLayout());
setCycles(5);
speed.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
timer.setDelay(speed.getValue());
}
});
add(BorderLayout.SOUTH, speed);
speed.setInverted(true);
timer.start();
}
public void setCycles(int newCycles) {
cycles = newCycles;
points = SCALEFACTOR * cycles * 2;
sines = new double[points];
pts = new int[points];
for(int i = 0; i < points; i++) {
double radians = (Math.PI/SCALEFACTOR) * i;
sines[i] = Math.sin(radians);
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
int maxWidth = getWidth();
double hstep =(double)maxWidth/(double)points;
int maxHeight = getHeight();
for(int i = 0; i < points; i++)
// Some adjustments here to compensate for
// the added JSlider in the panel:
pts[i] = (int)(sines[i] * maxHeight/2 * .94
+ maxHeight/2 * .96);
for(int i = 1; i < points; i++) {
int x1 = (int)((i - 1) * hstep);
int x2 = (int)(i * hstep);
int y1 = pts[i-1];
int y2 = pts[i];
g.drawLine(x1, y1, x2, y2);
}
}
}class SineWave_T extends JApplet {
SineDraw_T sines = new SineDraw_T();
JSlider cycles = new JSlider(1, 30, 5);
public void init() {
Container cp = getContentPane();
cp.add(sines);
cycles.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
sines.setCycles(
((JSlider)e.getSource()).getValue());
}
});
cp.add(BorderLayout.SOUTH, cycles);
}
}public class Ex11 {
public static void main(String args[]) {
Console.run(new SineWave_T(), 700, 400);}
}/****************** Exercise 11 *****************
* Modify SimpleThread.java so that all the
* threads are daemon threads, and verify that
* the program ends as soon as main( ) is able
* to exit.
***********************************************/
public class Ex12 extends Thread {
private int countDown = 5;
private static int threadCount = 0;
private int threadNumber = ++threadCount;
public Ex12() {
System.out.println("Making " + threadNumber);
setDaemon(true); // Add this line
}
public void run() {
while(true) {
System.out.println("Thread " +
threadNumber + "(" + countDown + ")");
if(--countDown == 0) return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new Ex12().start();
System.out.println("All Threads Started");
}
} -
[Thinking in Java练习题](十二)执行期型别辨识
2006年08月28日
/****************** Exercise 1 ******************
* Add Rhomboid to Shapes.java. Create a
* Rhomboid, upcast it to a Shape, then downcast
* it back to a Rhomboid. Try downcasting to a
* Circle and see what happens.
***********************************************/
import java.util.*;class Shape {
void draw() {
System.out.println(this + ".draw()");
}
}class Circle extends Shape {
public String toString() { return "Circle"; }
}class Square extends Shape {
public String toString() { return "Square"; }
}class Triangle extends Shape {
public String toString() { return "Triangle"; }
}class Rhomboid extends Shape {
public String toString() { return "Rhomboid"; }
}public class Ex01 {
public static void main(String[] args) {
List s = new ArrayList();
s.add(new Circle());
s.add(new Square());
s.add(new Triangle());
s.add(new Rhomboid());
Iterator e = s.iterator();
while(e.hasNext())
((Shape)e.next()).draw();
// Upcast to shape:
Shape shape = new Rhomboid();
// Downcast to Rhomboid:
Rhomboid r = (Rhomboid)shape;
// Downcast to Circle. Succeeds at
// compile-time, fails at runtime with
// a ClassCastException:
//! Circle c = (Circle)shape;
}
}/****************** Exercise 2 ******************
* Modify Exercise 1 so that it uses instanceof
* to check the type before performing the
* downcast.
***********************************************/
public class Ex02 {
public static void main(String[] args) {
// Upcast to shape:
Shape shape = new Rhomboid();
// Downcast to Rhomboid:
Rhomboid r = (Rhomboid)shape;
// Test before Downcasting:
Circle c = null;
if(shape instanceof Circle)
c = (Circle)shape;
else
System.out.println("shape not a Circle");
}
}/****************** Exercise 3 ******************
* Modify Shapes.java so that it can "highlight"
* (set a flag) in all shapes of a particular
* type. The toString() method for each derived
* Shape should indicate whether that Shape is
* "highlighted."
***********************************************/
import java.util.*;class HShape {
boolean highlighted = false;
void highlight() { highlighted = true; }
void clearHighlight() { highlighted = false; }
void draw() {
System.out.println(this + " draw()");
}
public String toString() {
return getClass().getName() +
(highlighted ? " highlighted " : " normal");
}
static ArrayList allShapes = new ArrayList();
public HShape() {
allShapes.add(this);
}
static void highlight(Class type) {
Iterator it = allShapes.iterator();
while(it.hasNext()) {
HShape shape = (HShape)it.next();
if(type.isInstance(shape))
shape.highlight();
}
}
static void clearHighlight(Class type) {
Iterator it = allShapes.iterator();
while(it.hasNext()) {
HShape shape = (HShape)it.next();
if(type.isInstance(shape))
shape.clearHighlight();
}
}
}class HCircle extends HShape {}
class HSquare extends HShape {}
class HTriangle extends HShape {}
public class Ex03 {
public static void main(String[] args) {
List s = new ArrayList(
Arrays.asList(new HShape[]{
new HCircle(), new HSquare(),
new HTriangle(), new HSquare(),
new HTriangle(), new HCircle(),
new HCircle(), new HSquare(), }));
HShape.highlight(HCircle.class);
Iterator e = s.iterator();
while(e.hasNext())
((HShape)e.next()).draw();
System.out.println("*******");
// Highlight them all:
HShape.highlight(HShape.class);
e = s.iterator();
while(e.hasNext())
((HShape)e.next()).draw();
System.out.println("*******");
// Not in the hierarchy:
HShape.clearHighlight(ArrayList.class);
e = s.iterator();
while(e.hasNext())
((HShape)e.next()).draw();
}
}
/****************** Exercise 4 ******************
* Modify SweetShop.java so that each type of
* object creation is controlled by a
* command-line argument. That is, if your
* command line is "java SweetShop Candy," then
* only the Candy object is created. Notice how
* you can control which Class objects are loaded
* via the command-line argument.
***********************************************/
class Candy {
static {
System.out.println("Loading Candy");
}
}class Gum {
static {
System.out.println("Loading Gum");
}
}class Cookie {
static {
System.out.println("Loading Cookie");
}
}public class Ex04 {
public static void main(String[] args)
throws Exception {
for(int i = 0; i < args.length; i++)
Class.forName(args[i]);
}
}/****************** Exercise 5 ******************
* Add a new type of Pet to PetCount3.java.
* Verify that it is created and counted
* correctly in main().
***********************************************/
import java.util.*;class Pet {}
class Dog extends Pet {}
class Pug extends Dog {}
class Cat extends Pet {}
class Rodent extends Pet {}
class Gerbil extends Rodent {}
class Hamster extends Rodent {}// New type of pet:
class Labrador extends Dog {} // Added this lineclass Counter { int i; }
public class Ex05 {
public static void main(String[] args)
throws Exception {
ArrayList pets = new ArrayList();
Class[] petTypes = {
Pet.class,
Dog.class,
Pug.class,
Labrador.class, // Had to add this line too
Cat.class,
Rodent.class,
Gerbil.class,
Hamster.class,
};
try {
for(int i = 0; i < 15; i++) {
// Offset by one to eliminate Pet.class:
int rnd = 1 + (int)(
Math.random() * (petTypes.length - 1));
pets.add(
petTypes[rnd].newInstance());
}
} catch(InstantiationException e) {
System.err.println("Cannot instantiate");
throw e;
} catch(IllegalAccessException e) {
System.err.println("Cannot access");
throw e;
}
HashMap h = new HashMap();
for(int i = 0; i < petTypes.length; i++)
h.put(petTypes[i].toString(),
new Counter());
for(int i = 0; i < pets.size(); i++) {
Object o = pets.get(i);
// Using isInstance to eliminate individual
// instanceof expressions:
for (int j = 0; j < petTypes.length; ++j)
if (petTypes[j].isInstance(o)) {
String key = petTypes[j].toString();
((Counter)h.get(key)).i++;
}
}
for(int i = 0; i < pets.size(); i++)
System.out.println(pets.get(i).getClass());
Iterator keys = h.keySet().iterator();
while(keys.hasNext()) {
String nm = (String)keys.next();
Counter cnt = (Counter)h.get(nm);
System.out.println(
nm.substring(nm.lastIndexOf('.') + 1) +
" quantity: " + cnt.i);
}
}
}/****************** Exercise 6 ******************
* Write a method that takes an object and
* recursively prints all the classes in that
* object's hierarchy.
***********************************************/
public class Ex06 {
static void printClasses(Class c) {
// getSuperclass() returns null on Object:
if(c == null) return;
System.out.println(c.getName());
// Produces the interfaces that this class
// implements:
Class[] interfaces = c.getInterfaces();
for(int i = 0; i < interfaces.length; i++) {
Class k = interfaces[i];
System.out.println(
"Interface: " + k.getName());
printClasses(k.getSuperclass());
}
printClasses(c.getSuperclass());
}
public static void main(String args[])
throws Exception {
for(int i = 0; i < args.length; i++) {
System.out.println("Displaying " + args[i]);
printClasses(Class.forName(args[i]));
if(i < args.length -1)
System.out.println("==================");
}
}
}/****************** Exercise 7 ******************
* Modify Exercise 6 so that it uses
* Class.getDeclaredFields() to also display
* information about the fields in a class.
***********************************************/
import java.lang.reflect.*;
import java.util.*;interface Iface {
int i = 47;
void f();
}class Base implements Iface {
String s;
double d;
public void f() {
System.out.println("Base.f");
}
}class Composed {
Base b;
}class Derived extends Base {
Composed c;
String s;
}public class Ex07 {
static Set alreadyDisplayed = new HashSet();
static void printClasses(Class c) {
// getSuperclass() returns null on Object:
if(c == null) return;
System.out.println(c.getName());
Field[] fields = c.getDeclaredFields();
if(fields.length != 0)
System.out.println("Fields:");
for(int i = 0; i < fields.length; i++) {
System.out.println("\t" + fields[i]);
}
for(int i = 0; i < fields.length; i++) {
Class field = fields[i].getType();
if(!alreadyDisplayed.contains(field)) {
printClasses(field);
alreadyDisplayed.add(field);
}
}
// Produces the interfaces that this class
// implements:
Class[] interfaces = c.getInterfaces();
for(int i = 0; i < interfaces.length; i++) {
Class k = interfaces[i];
System.out.println(
"Interface: " + k.getName());
printClasses(k.getSuperclass());
}
printClasses(c.getSuperclass());
}
public static void main(String args[])
throws Exception {
for(int i = 0; i < args.length; i++) {
System.out.println("Displaying " + args[i]);
printClasses(Class.forName(args[i]));
if(i < args.length -1)
System.out.println("==================");
}
}
}/****************** Exercise 8 ******************
* In ToyTest.java, comment out Toy's default
* constructor and explain what happens.
***********************************************/
interface HasBatteries {}
interface Waterproof {}
interface ShootsThings {}
class Toy {
// Comment out the following default
// constructor to see
// NoSuchMethodError from (*1*)
Toy() {} // Comment this line to get the effect
Toy(int i) {}
}class FancyToy extends Toy
implements HasBatteries,
Waterproof, ShootsThings {
FancyToy() { super(1); }
}public class Ex08 {
public static void main(String[] args)
throws Exception {
Class c = null;
try {
c = Class.forName("FancyToy");
} catch(ClassNotFoundException e) {
System.err.println("Can't find FancyToy");
throw e;
}
printInfo(c);
Class[] faces = c.getInterfaces();
for(int i = 0; i < faces.length; i++)
printInfo(faces[i]);
Class cy = c.getSuperclass();
Object o = null;
try {
// Requires default constructor:
o = cy.newInstance(); // (*1*)
} catch(InstantiationException e) {
System.err.println("Cannot instantiate");
throw e;
} catch(IllegalAccessException e) {
System.err.println("Cannot access");
throw e;
}
printInfo(o.getClass());
}
static void printInfo(Class cc) {
System.out.println(
"Class name: " + cc.getName() +
" is interface? [" +
cc.isInterface() + "]");
}
}/****************** Exercise 9 ******************
* Incorporate a new kind of interface into
* ToyTest.java and verify that it is detected
* and displayed properly.
***********************************************/
interface HasCPU {}
class FancierToy extends Toy
implements HasBatteries, HasCPU,
Waterproof, ShootsThings {
FancierToy() { super(1); }
}public class Ex09 {
public static void main(String[] args)
throws Exception {
Class c = null;
try {
c = Class.forName("FancierToy");
} catch(ClassNotFoundException e) {
System.err.println("Can't find FancierToy");
throw e;
}
printInfo(c);
Class[] faces = c.getInterfaces();
for(int i = 0; i < faces.length; i++)
printInfo(faces[i]);
Class cy = c.getSuperclass();
Object o = null;
try {
// Requires default constructor:
o = cy.newInstance(); // (*1*)
} catch(InstantiationException e) {
System.err.println("Cannot instantiate");
throw e;
} catch(IllegalAccessException e) {
System.err.println("Cannot access");
throw e;
}
printInfo(o.getClass());
}
static void printInfo(Class cc) {
System.out.println(
"Class name: " + cc.getName() +
" is interface? [" +
cc.isInterface() + "]");
}
}/****************** Exercise 10 *****************
* Create a new type of container that uses a
* private ArrayList to hold the objects. Capture
* the type of the first object you put in it,
* and then allow the user to insert objects of
* only that type from then on.
***********************************************/
import java.util.*;class TypedContainer extends AbstractList {
private ArrayList list = new ArrayList();
Class type = null;
public boolean add(Object o) {
if(type == null)
type = o.getClass();
if(o.getClass() == type) {
list.add(o);
return true;
}
return false;
}
public void add(int index, Object o) {
if(type == null)
type = o.getClass();
if(o.getClass() == type)
list.add(index, o);
}
public Object set(int index, Object o) {
if(type == null)
type = o.getClass();
if(o.getClass() == type)
return list.set(index, o);
return list.get(index);
}
public Object get(int index) {
return list.get(index);
}
public int size() { return list.size(); }
public Object remove(int index) {
return list.remove(index);
}
public int indexOf(Object o) {
return list.indexOf(o);
}
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
public void clear() {
list.clear();
}
public boolean addAll(int index, Collection c) {
return list.addAll(index, c);
}
public Iterator iterator() {
return list.iterator();
}
public ListIterator listIterator() {
return list.listIterator();
}
public ListIterator listIterator(int index) {
return list.listIterator(index);
}
public List subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
public boolean equals(Object o) {
return list.equals(o);
}
}class X {
public String toString() {
return "X";
}
}class Y {
public String toString() {
return "Y";
}
}public class Ex10 {
public static void main(String args[]) {
TypedContainer tc = new TypedContainer();
for(int i = 0; i < 10; i++) {
tc.add(new X());
tc.add(new Y());
}
System.out.println("tc = " + tc);
TypedContainer tc2 = new TypedContainer();
for(int i = 0; i < 10; i++) {
tc2.add(new Y());
tc2.add(new X());
}
System.out.println("tc2 = " + tc2);
}
}/****************** Exercise 11 *****************
* Write a program to determine whether an array
* of char is a primitive type or a true object.
***********************************************/
public class Ex11 {
public static void main(String args[]) {
char[] ac = "Hello, World!".toCharArray();
System.out.println(
"ac.getClass() = " + ac.getClass());
System.out.println(
"ac.getClass().getSuperclass() = "
+ ac.getClass().getSuperclass());
char c = 'c';
//! c.getClass(); // Can't do it, primitives
// are not true objects.
int[] ia = new int[3];
System.out.println(
"ia.getClass() = " + ia.getClass());
long[] la = new long[3];
System.out.println(
"la.getClass() = " + la.getClass());
double[] da = new double[3];
System.out.println(
"da.getClass() = " + da.getClass());
String[] sa = new String[3];
System.out.println(
"sa.getClass() = " + sa.getClass());
Ex11[] pot = new Ex11[3];
System.out.println(
"pot.getClass() = " + pot.getClass());
// Multi-dimensional arrays:
int[][][] threed = new int[3][][];
System.out.println(
"threed.getClass() = " + threed.getClass());
}
}/****************** Exercise 12 *****************
* Implement clearSpitValve() as described in the
* summary.
***********************************************/
// The summary reads:
/*
One option is to put a clearSpitValve( ) method
in the base class Instrument, but this is
confusing because it implies that Percussion and
Electronic instruments also have spit valves.
RTTI provides a much more reasonable solution in
this case because you can place the method in the
specific class (Wind in this case), where it's
appropriate. However, a more appropriate solution
is to put a prepareInstrument( ) method in the
base class, but you might not see this when
you're first solving the problem and could
mistakenly assume that you must use RTTI.
*/
// We'll use the last-defined version of the
// instrument hierarchy:
interface Instrument {
int i = 5; // static & final
void play();
String what();
void adjust();
void prepareInstrument();
}class Wind implements Instrument {
public void play() {
System.out.println("Wind.play()");
}
public String what() { return "Wind"; }
public void adjust() {}
public void clearSpitValve() {
System.out.println("Wind.clearSpitValve");
}
public void prepareInstrument() {
clearSpitValve();
}
}class Percussion implements Instrument {
public void play() {
System.out.println("Percussion.play()");
}
public String what() { return "Percussion"; }
public void adjust() {}
public void prepareInstrument() {
System.out.println(
"Percussion.prepareInstrument");
}
}class Stringed implements Instrument {
public void play() {
System.out.println("Stringed.play()");
}
public String what() { return "Stringed"; }
public void adjust() {}
public void prepareInstrument() {
System.out.println(
"Stringed.prepareInstrument");
}
}class Brass extends Wind {
public void play() {
System.out.println("Brass.play()");
}
public void adjust() {
System.out.println("Brass.adjust()");
}
public void clearSpitValve() {
System.out.println("Brass.clearSpitValve");
}
}class Woodwind extends Wind {
public void play() {
System.out.println("Woodwind.play()");
}
public String what() { return "Woodwind"; }
public void clearSpitValve() {
System.out.println("Woodwind.clearSpitValve");
}
}class Music5 {
static void tune(Instrument i) {
// ...
i.play();
}
static void tuneAll(Instrument[] e) {
for(int i = 0; i < e.length; i++)
tune(e[i]);
}
static void prepareAll(Instrument[] e) {
for(int i = 0; i < e.length; i++)
e[i].prepareInstrument();
}
}public class Ex12 {
public static void main(String[] args) {
Instrument[] orchestra = {
new Wind(), new Percussion(),
new Stringed(), new Brass(),
new Woodwind(),
};
Music5.prepareAll(orchestra);
Music5.tuneAll(orchestra);
}
}/****************** Exercise 13 *****************
* Implement the rotate(Shape) method described
* in this chapter, such that it checks to see if
* it is rotating a Circle (and, if so, doesn't
* perform the operation).
***********************************************/
// This exercise contained an error -- the
// rotate() method was not in fact described
// in the chapter.
import java.util.*;class RShape {
void draw() {
System.out.println(this + ".draw()");
}
void rotate(int degrees) {
System.out.println("Rotating " + this +
" by " + degrees + " degrees");
}
public String toString() {
return getClass().getName();
}
}class RCircle extends RShape {}
class RSquare extends RShape {}
class RTriangle extends RShape {}
class RRhomboid extends RShape {}
public class Ex13 {
public static void rotateAll(
Iterator it, int degrees) {
while(it.hasNext()) {
RShape s = (RShape)it.next();
if(!(s instanceof RCircle))
s.rotate(degrees);
}
}
public static void main(String args[]) {
List s = new ArrayList(
Arrays.asList(new RShape[]{
new RCircle(), new RRhomboid(),
new RTriangle(), new RSquare(),
new RRhomboid(), new RSquare(),
new RTriangle(), new RCircle(),
new RCircle(), new RSquare(),
}));
rotateAll(s.iterator(), 45);
}
}/****************** Exercise 16 *****************
* In ToyTest.java, use reflection to create a
* Toy object using the nondefault constructor.
***********************************************/
import java.lang.reflect.*;
import java.io.*;class ExceptionAdapter extends RuntimeException {
public ExceptionAdapter(Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
throw new RuntimeException(sw.toString());
}
}class SuperToy extends FancierToy {
int IQ;
public SuperToy(int intelligence) {
IQ = intelligence;
}
public String toString() {
return "I'm a SuperToy. I'm smarter than you";
}
}public class Ex16 {
public static Toy
makeToy(String toyName, int IQ) {
try {
Class tClass = Class.forName(toyName);
Constructor[] ctors =
tClass.getConstructors();
for(int i = 0; i < ctors.length; i++) {
// Look for the constructor with a
// single parameter:
Class[] params =
ctors[i].getParameterTypes();
if(params.length == 1)
if(params[0] == int.class)
return (Toy)ctors[i].newInstance(
new Object[]{ new Integer(IQ)} );
}
} catch(Exception e) {
new ExceptionAdapter(e);
}
return null;
}
public static void main(String args[]) {
System.out.println(makeToy("SuperToy", 150));
}
}/****************** Exercise 17 *****************
* Look up the interface for java.lang.Class in
* the HTML Java documentation from java.sun.com.
* Write a program that takes the name of a class
* as a command-line argument, then uses the
* Class methods to dump all the information
* available for that class. Test your program
* with a standard library class and a class you
* create.
***********************************************/
// The solution is a much-modified version of
// Showmethods.java.
import java.lang.reflect.*;public class Ex17 {
public static void
display(String msg, Object[] vals) {
System.out.println(msg);
for(int i = 0; i < vals.length; i++)
System.out.println(" " + vals[i]);
}
public static void
classInfo(Class c) throws Exception {
System.out.println(
"c.getName(): " + c.getName());
System.out.println(
"c.getPackage(): " + c.getPackage());
System.out.println(
"c.getSuperclass(): " + c.getSuperclass());
// This produces all the classes
// declared as members:
display("c.getDeclaredClasses()",
c.getDeclaredClasses());
display("c.getClasses()", c.getClasses());
display("c.getInterfaces()",
c.getInterfaces());
// The "Declared" version includes all
// versions, not just public:
display("c.getDeclaredMethods()",
c.getDeclaredMethods());
display("c.getMethods()",
c.getMethods());
display("c.getDeclaredConstructors()",
c.getDeclaredConstructors());
display("c.getConstructors()",
c.getConstructors());
display("c.getDeclaredFields()",
c.getDeclaredFields());
display("c.getFields()", c.getFields());
if(c.getSuperclass() != null) {
System.out.println("Base class: --------");
classInfo(c.getSuperclass());
}
System.out.println("End of " + c.getName());
}
public static
void main(String[] args) throws Exception {
classInfo(Class.forName(args[0]));
}
} -
[Thinking in Java练习题](十一)Java I/O系统
2006年08月27日
/****************** Exercise 1 ******************
* Open a text file so that you can read the file
* one line at a time. Read each line as a String
* and place that String object into a
* LinkedList. Print all of the lines in the
* LinkedList in reverse order.
***********************************************/
import java.io.*;
import java.util.*;public class Ex01 {
// Report all exceptions to console:
public static void main(String args[])
throws Exception {
LinkedList lines = new LinkedList();
BufferedReader in =
new BufferedReader(
new FileReader("Ex01.java"));
String s;
while((s = in.readLine())!= null)
lines.add(s);
in.close();
ListIterator it =
lines.listIterator(lines.size());
while(it.hasPrevious())
System.out.println(it.previous());
}
}/****************** Exercise 2 ******************
* Modify Exercise 1 so that the name of the file
* you read is provided as a command-line
* argument.
***********************************************/
import java.util.*;
import java.io.*;public class Ex02 {
// Report all exceptions to console:
public static void main(String args[])
throws Exception {
LinkedList lines = new LinkedList();
BufferedReader in =
new BufferedReader(
new FileReader(args[0]));
String s;
while((s = in.readLine())!= null)
lines.add(s);
in.close();
ListIterator it =
lines.listIterator(lines.size());
while(it.hasPrevious())
System.out.println(it.previous());
}
}/****************** Exercise 3 ******************
* Modify Exercise 2 to also open a text file so
* you can write text into it. Write the lines in
* the ArrayList, along with line numbers (do not
* attempt to use the "LineNumber" classes), out
* to the file.
***********************************************/
import java.util.*;
import java.io.*;public class Ex03 {
// Report all exceptions to console:
public static void main(String args[])
throws Exception {
LinkedList lines = new LinkedList();
BufferedReader in =
new BufferedReader(
new FileReader(args[0]));
String s;
while((s = in.readLine())!= null)
lines.add(s);
in.close();
PrintWriter out =
new PrintWriter(
new BufferedWriter(
new FileWriter(args[1])));
int line = 1;
Iterator it = lines.iterator();
while(it.hasNext())
out.println(line++ + ": " + it.next());
out.close();
}
}/****************** Exercise 4 ******************
* Modify Exercise 2 to force all the lines in
* the ArrayList to upper case and send the
* results to System.out.
***********************************************/
import java.util.*;
import java.io.*;public class Ex04 {
// Report all exceptions to console:
public static void main(String args[])
throws Exception {
LinkedList lines = new LinkedList();
BufferedReader in =
new BufferedReader(
new FileReader(args[0]));
String s;
while((s = in.readLine())!= null)
lines.add(s);
in.close();
Iterator it = lines.iterator();
while(it.hasNext())
System.out.println(
((String)it.next()).toUpperCase());
}
}
/****************** Exercise 5 ******************
* Modify Exercise 2 to take additional
* command-line arguments of words to find in the
* file. Print all lines in which any of the
* words match.
***********************************************/
import java.util.*;
import java.io.*;public class Ex05 {
// Report all exceptions to console:
public static void main(String args[])
throws Exception {
Set words = new HashSet();
for(int i = 1; i < args.length; i++)
words.add(args[i]);
BufferedReader in =
new BufferedReader(
new FileReader(args[0]));
String s;
while((s = in.readLine())!= null) {
Iterator it = words.iterator();
while(it.hasNext()) {
String candidate = (String)it.next();
if(s.indexOf(candidate) != -1) {
System.out.println(s);
break; // Out of while loop
}
}
}
}
}/****************** Exercise 6 ******************
* Modify DirList.java so that the FilenameFilter
* actually opens each file and accepts the file
* based on whether any of the trailing arguments
* on the command line exist in that file.
***********************************************/
import java.io.*;
import java.util.*;
import com.bruceeckel.util.*;class DirFilter implements FilenameFilter {
String afn;
Set words = new HashSet();
DirFilter(String afn, String[] args) {
this.afn = afn;
for(int i = 1; i < args.length; i++)
words.add(args[i]);
}
public boolean accept(File dir, String name) {
// Strip path information:
String f = new File(name).getName();
// Only investigate files containing afn:
if(f.indexOf(afn) == -1) return false;
System.out.println("** " + f);
// Modified from E05_FindWords.java:
try {
BufferedReader in =
new BufferedReader(
new FileReader(f));
String s;
while((s = in.readLine())!= null) {
Iterator it = words.iterator();
while(it.hasNext()) {
String candidate = (String)it.next();
if(s.indexOf(candidate) != -1) {
// Print the line that first matched:
System.out.println(s);
return true;
}
}
}
} catch(IOException e) {
System.out.println("Caught" + e);
return false;
}
return false;
}
}public class Ex06 {
public static void main(String[] args) {
File path = new File(".");
String[] list;
list = path.list(
new DirFilter(args[0], args));
Arrays.sort(list,
new AlphabeticComparator());
System.out.println(">> Resulting List <<");
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
}
/****************** Exercise 7 ******************
* Create a class called SortedDirList with a
* constructor that takes file path information
* and builds a sorted directory list from the
* files at that path. Create two overloaded
* list() methods that will either produce the
* whole list or a subset of the list based on an
* argument. Add a size() method that takes a
* file name and produces the size of that file.
***********************************************/
import java.io.*;
import java.util.*;
import com.bruceeckel.util.*;class SortedDirList {
File path;
public SortedDirList() {
path = new File(".");
}
public SortedDirList(String filePath) {
path = new File(filePath);
}
public String[] list() {
String[] list =
path.list(new FilenameFilter() {
public boolean
accept(File dir, String n) {
// Accept anything:
return true;
}
});
Arrays.sort(list,
new AlphabeticComparator());
return list;
}
public String[] list(final String afn) {
String[] list =
path.list(new FilenameFilter() {
public boolean
accept(File dir, String n) {
String f = new File(n).getName();
return f.indexOf(afn) != -1;
}
});
Arrays.sort(list,
new AlphabeticComparator());
return list;
}
public long length(final String fileName) {
File[] files =
path.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName()
.indexOf(fileName) != -1;
}
});
if(files.length > 1)
throw new RuntimeException(
"More than one match for " + fileName);
return files[0].length();
}
}
public class Ex07 {
public static void main(String args[]) {
// Default constructor == current directory
SortedDirList dir = new SortedDirList();
Arrays2.print(dir.list());
Arrays2.print(dir.list(".java"));
String f = dir.list(".java")[0];
System.out.println(
"Length of " + f + " is " + dir.length(f));
}
}/****************** Exercise 8 ******************
* Modify WordCount.java so that it produces an
* alphabetic sort instead, using the tool from
* Chapter 9.
***********************************************/
import java.io.*;
import java.util.*;
import com.bruceeckel.util.*;class Counter {
private int i = 1;
int read() { return i; }
void increment() { i++; }
}class WordCount {
private FileReader file;
private StreamTokenizer st;
// The only change -- provide a comparator
// to the TreeMap constructor:
private TreeMap counts =
new TreeMap(new AlphabeticComparator());
// Instead of this:
// new TreeMap();
WordCount(String filename)
throws FileNotFoundException {
try {
file = new FileReader(filename);
st = new StreamTokenizer(
new BufferedReader(file));
st.ordinaryChar('.');
st.ordinaryChar('-');
} catch(FileNotFoundException e) {
System.err.println(
"Could not open " + filename);
throw e;
}
}
void cleanup() {
try {
file.close();
} catch(IOException e) {
System.err.println(
"file.close() unsuccessful");
}
}
void countWords() {
try {
while(st.nextToken() !=
StreamTokenizer.TT_EOF) {
String s;
switch(st.ttype) {
case StreamTokenizer.TT_EOL:
s = new String("EOL");
break;
case StreamTokenizer.TT_NUMBER:
s = Double.toString(st.nval);
break;
case StreamTokenizer.TT_WORD:
s = st.sval; // Already a String
break;
default: // single character in ttype
s = String.valueOf((char)st.ttype);
}
if(counts.containsKey(s))
((Counter)counts.get(s)).increment();
else
counts.put(s, new Counter());
}
} catch(IOException e) {
System.err.println(
"st.nextToken() unsuccessful");
}
}
Collection values() {
return counts.values();
}
Set keySet() { return counts.keySet(); }
Counter getCounter(String s) {
return (Counter)counts.get(s);
}
}public class Ex08 {
public static void main(String[] args)
throws FileNotFoundException {
WordCount wc =
new WordCount(args[0]);
wc.countWords();
Iterator keys = wc.keySet().iterator();
while(keys.hasNext()) {
String key = (String)keys.next();
System.out.println(key + ": "
+ wc.getCounter(key).read());
}
wc.cleanup();
}
}/****************** Exercise 9 ******************
* Modify WordCount.java so that it uses a class
* containing a String and a count value to store
* each different word, and a Set of these
* objects to maintain the list of words.
***********************************************/
import java.io.*;
import java.util.*;class Counter implements Comparable {
private String word;
private int count;
public Counter(String word) {
this.word = word;
count = 1;
}
public void increment() { count++; }
public String toString() {
return "\n" + word + " [" + count + "]";
}
public boolean equals(Object obj) {
return obj instanceof Counter &&
((Counter)obj).word.equals(word);
}
public int hashCode() {
return word.hashCode();
}
public int compareTo(Object o) {
return word.compareTo(((Counter)o).word);
}
}class CounterSet extends AbstractSet {
private Map set = new TreeMap();
public void addOrIncrement(String s) {
Counter c = new Counter(s);
if (set.containsKey(c))
((Counter)set.get(c)).increment();
else
set.put(c, c);
}
public Iterator iterator() {
return set.keySet().iterator();
}
public int size() {
return set.size();
}
public String toString() {
return set.keySet().toString();
}
}class WordCount {
private FileReader file;
private StreamTokenizer st;
private CounterSet counts = new CounterSet();
WordCount(String filename)
throws FileNotFoundException {
try {
file = new FileReader(filename);
st = new StreamTokenizer(
new BufferedReader(file));
st.ordinaryChar('.');
st.ordinaryChar('-');
} catch(FileNotFoundException e) {
System.err.println(
"Could not open " + filename);
throw e;
}
}
void cleanup() {
try {
file.close();
} catch(IOException e) {
System.err.println(
"file.close() unsuccessful");
}
}
void countWords() {
try {
while(st.nextToken() !=
StreamTokenizer.TT_EOF) {
String s;
switch(st.ttype) {
case StreamTokenizer.TT_EOL:
s = new String("EOL");
break;
case StreamTokenizer.TT_NUMBER:
s = Double.toString(st.nval);
break;
case StreamTokenizer.TT_WORD:
s = st.sval; // Already a String
break;
default: // single character in ttype
s = String.valueOf((char)st.ttype);
}
counts.addOrIncrement(s);
}
} catch(IOException e) {
System.err.println(
"st.nextToken() unsuccessful");
}
}
public Iterator iterator() {
return counts.iterator();
}
public String toString() {
return counts.toString();
}
}public class Ex09 {
public static void main(String[] args)
throws FileNotFoundException {
WordCount wc = new WordCount(args[0]);
wc.countWords();
System.out.println("wc = " + wc);
wc.cleanup();
}
}
/****************** Exercise 10 *****************
* Modify IOStreamDemo.java so that it uses
* LineNumberReader to keep track of the
* line count. Note that it's much easier to just
* keep track programmatically.
***********************************************/
import java.io.*;public class Ex10 {
public static void main(String[] args)
throws IOException {
// LineNumberReader is inherited from
// BufferedReader so we don't need to
// explicitly buffer it:
LineNumberReader in =
new LineNumberReader(
new FileReader("Ex10.java"));
String s, s2 = new String();
while((s = in.readLine())!= null)
s2 += in.getLineNumber() + ": " + s + "\n";
in.close();
System.out.println(s2);
}
}/****************** Exercise 11 *****************
* Starting with section 4 of IOStreamDemo.java,
* write a program that compares the performance
* of writing to a file when using buffered and
* unbuffered I/O.
***********************************************/
import java.io.*;public class Ex11 {
// Report exceptions to console:
public static void main(String args[])
throws Exception {
BufferedReader in =
new BufferedReader(
new FileReader(
"Ex11.java"));
String s, s2 = new String();
while((s = in.readLine())!= null)
s2 += s + "\n";
in.close();
PrintWriter out1 =
new PrintWriter(
new BufferedWriter(
new FileWriter(
"BufferPerformance1.out")));
long t1 = System.currentTimeMillis();
for(int i = 0; i < 10000; i++)
out1.println(s2);
long t2 = System.currentTimeMillis();
System.out.println("buffered: " + (t2 - t1));
out1.close();
PrintWriter out2 =
new PrintWriter(
new FileWriter(
"BufferPerformance2.out"));
t1 = System.currentTimeMillis();
for(int i = 0; i < 10000; i++)
out2.println(s2);
t2 = System.currentTimeMillis();
System.out.println(
"unbuffered: " + (t2 - t1));
out2.close();
}
}/****************** Exercise 12 *****************
* Modify section 5 of IOStreamDemo.java to
* eliminate the spaces in the line produced by
* the first call to in5.readUTF().
***********************************************/
import java.io.*;public class Ex12 {
// Report all exceptions to console:
public static void main(String args[])
throws Exception {
DataOutputStream out2 =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("Data.txt")));
out2.writeDouble(3.14159);
out2.writeUTF("That was pi");
out2.writeDouble(1.41413);
out2.writeUTF("Square root of 2");
out2.close();
DataInputStream in5 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("Data.txt")));
System.out.println(in5.readDouble());
// First, eliminate any surrounding space:
String s = in5.readUTF().trim();
String noSpace = "";
char c;
for(int i = 0; i < s.length(); i++) {
c = s.charAt(i);
if(c != ' ')
noSpace += c;
}
System.out.println("noSpace = " + noSpace);
System.out.println(in5.readDouble());
System.out.println(in5.readUTF());
}
}/****************** Exercise 13 *****************
* Repair the program CADState.java as described
* in the text.
***********************************************/
/*
The instructions from the book are:
1. Add a serializeStaticState() and
deserializeStaticState( ) to the shapes.
2. Remove the ArrayList shapeTypes and all code
related to it.
3. Add calls to the new serialize and
deserialize static methods in the shapes.
*/
import java.io.*;
import java.util.*;abstract class Shape implements Serializable {
public static final int
RED = 1, BLUE = 2, GREEN = 3;
private int xPos, yPos, dimension;
private static Random r = new Random();
private static int counter = 0;
abstract public void setColor(int newColor);
abstract public int getColor();
public Shape(int xVal, int yVal, int dim) {
xPos = xVal;
yPos = yVal;
dimension = dim;
}
public String toString() {
return getClass() +
" color[" + getColor() +
"] xPos[" + xPos +
"] yPos[" + yPos +
"] dim[" + dimension + "]\n";
}
public static Shape randomFactory() {
int xVal = r.nextInt() % 100;
int yVal = r.nextInt() % 100;
int dim = r.nextInt() % 100;
switch(counter++ % 3) {
default:
case 0: return new Circle(xVal, yVal, dim);
case 1: return new Square(xVal, yVal, dim);
case 2: return new Line(xVal, yVal, dim);
}
}
}class Circle extends Shape {
private static int color = RED;
public static void
serializeStaticState(ObjectOutputStream os)
throws IOException {
os.writeInt(color);
}
public static void
deserializeStaticState(ObjectInputStream os)
throws IOException {
color = os.readInt();
}
public Circle(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}class Square extends Shape {
private static int color = BLUE;
public static void
serializeStaticState(ObjectOutputStream os)
throws IOException {
os.writeInt(color);
}
public static void
deserializeStaticState(ObjectInputStream os)
throws IOException {
color = os.readInt();
}
public Square(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
color = RED;
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}class Line extends Shape {
private static int color = GREEN;
public static void
serializeStaticState(ObjectOutputStream os)
throws IOException {
os.writeInt(color);
}
public static void
deserializeStaticState(ObjectInputStream os)
throws IOException {
color = os.readInt();
}
public Line(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}public class Ex13 {
public static void main(String[] args)
throws Exception {
ArrayList shapes;
if(args.length == 0) {
shapes = new ArrayList();
// Make some shapes:
for(int i = 0; i < 10; i++)
shapes.add(Shape.randomFactory());
// Save the state vector:
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("CADState.out"));
Line.serializeStaticState(out);
Circle.serializeStaticState(out);
Square.serializeStaticState(out);
out.writeObject(shapes);
} else { // There's a command-line argument
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream(args[0]));
// Read in the same order they were written:
Line.deserializeStaticState(in);
Circle.deserializeStaticState(in);
Square.deserializeStaticState(in);
shapes = (ArrayList)in.readObject();
}
// Display the shapes:
System.out.println(shapes);
}
}/****************** Exercise 14 *****************
* In Blips.java, copy the file and rename it to
* BlipCheck.java and rename the class Blip2 to
* BlipCheck (making it public and removing the
* public scope from the class Blips in the
* process). Remove the //! marks in the file and
* execute the program including the offending
* lines. Next, comment out the default
* constructor for BlipCheck. Run it and explain
* why it works. Note that after compiling, you
* must execute the program with "java Blips"
* because the main() method is still in class
* Blips.
***********************************************/
import java.io.*;
import java.util.*;class Blip1 implements Externalizable {
public Blip1() {
System.out.println("Blip1 Constructor");
}
public void writeExternal(ObjectOutput out)
throws IOException {
System.out.println("Blip1.writeExternal");
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
System.out.println("Blip1.readExternal");
}
}public class Ex14
implements Externalizable {
// E14_BlipCheck() {
// System.out.println("BlipCheck Constructor");
// }
public void writeExternal(ObjectOutput out)
throws IOException {
System.out.println("BlipCheck.writeExternal");
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
System.out.println("BlipCheck.readExternal");
}
}class Blips {
// Throw exceptions to console:
public static void main(String[] args)
throws IOException, ClassNotFoundException {
System.out.println("Constructing objects:");
Blip1 b1 = new Blip1();
Ex14 b2 = new Ex14();
ObjectOutputStream o =
new ObjectOutputStream(
new FileOutputStream("Blips.out"));
System.out.println("Saving objects:");
o.writeObject(b1);
o.writeObject(b2);
o.close();
// Now get them back:
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("Blips.out"));
System.out.println("Recovering b1:");
b1 = (Blip1)in.readObject();
// OOPS! Throws an exception:
System.out.println("Recovering b2:");
b2 = (Ex14)in.readObject();
}
}/****************** Exercise 15 *****************
* In Blip3.java, comment out the two lines after
* the phrases "You must do this:" and run the
* program. Explain the result and why it differs
* from when the two lines are in the program.
***********************************************/
import java.io.*;
import java.util.*;class Blip3 implements Externalizable {
int i;
String s; // No initialization
public Blip3() {
System.out.println("Blip3 Constructor");
// s, i not initialized
}
public Blip3(String x, int a) {
System.out.println("Blip3(String x, int a)");
s = x;
i = a;
// s & i initialized only in nondefault
// constructor.
}
public String toString() { return s + i; }
public void writeExternal(ObjectOutput out)
throws IOException {
System.out.println("Blip3.writeExternal");
// You must do this:
// out.writeObject(s);
// out.writeInt(i);
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
System.out.println("Blip3.readExternal");
// You must do this:
// s = (String)in.readObject();
// i =in.readInt();
}
}public class Ex15 {
public static void main(String[] args)
throws IOException, ClassNotFoundException {
System.out.println("Constructing objects:");
Blip3 b3 = new Blip3("A String ", 47);
System.out.println(b3);
ObjectOutputStream o =
new ObjectOutputStream(
new FileOutputStream("Blip3.out"));
System.out.println("Saving object:");
o.writeObject(b3);
o.close();
// Now get it back:
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("Blip3.out"));
System.out.println("Recovering b3:");
b3 = (Blip3)in.readObject();
System.out.println(b3);
}
} -
[Thinking in Java练习题](十)通过异常处理错误
2006年08月26日
/****************** Exercise 1 ******************
* Create a class with a main() that throws an
* object of class Exception inside a try block.
* Give the constructor for Exception a String
* argument. Catch the exception inside a catch
* clause and print the String argument. Add a
* finally clause and print a message to prove
* you were there.
***********************************************/
public class Ex01 {
public static void main(String args[]) {
try {
throw new Exception("An exception in main");
} catch(Exception e) {
System.out.println(
"e.getMessage() = " + e.getMessage());
} finally {
System.out.println("In finally clause");
}
}
}
/****************** Exercise 2 ******************
* Create your own exception class using the
* extends keyword. Write a constructor for this
* class that takes a String argument and stores
* it inside the object with a String reference.
* Write a method that prints out the stored
* String. Create a try-catch clause to exercise
* your new exception.
***********************************************/
// Following the instructions to the letter:
class MyException extends Exception {
String msg;
public MyException(String msg) {
this.msg = msg;
}
public void printMsg() {
System.out.println("msg = " + msg);
}
}// Or you can take a more clever approach, and
// note that string storage and printing is
// built into Exception:
class MyException2 extends Exception {
public MyException2(String s) {
super(s);
}
}public class Ex02 {
public static void main(String args[]) {
try {
throw new MyException(
"MyException message");
} catch(MyException e) {
e.printMsg();
}
try {
throw new MyException2(
"MyException2 message");
} catch(MyException2 e) {
System.out.println(
"e.getMessage() = " + e.getMessage());
}
}
}
/****************** Exercise 3 ******************
* Write a class with a method that throws an
* exception of the type created in Exercise 2.
* Try compiling it without an exception
* specification to see what the compiler says.
* Add the appropriate exception specification.
* Try out your class and its exception inside a
* try-catch clause.
***********************************************/
class Thrower {
public void f() {
// Compiler gives an error: "unreported
// exception MyException; must be caught or
// declared to be thrown"
//! throw new MyException("Inside f()");
}
public void g() throws MyException {
throw new MyException("Inside g()");
}
}public class Ex03 {
public static void main(String args[]) {
Thrower t = new Thrower();
try {
t.g();
} catch(MyException e) {
e.printMsg();
}
}
}
/****************** Exercise 4 ******************
* Define an object reference and initialize it
* to null. Try to call a method through this
* reference. Now wrap the code in a try-catch
* clause to catch the exception.
***********************************************/
public class Ex04 {
public static void main(String args[]) {
String s = null;
// Causes a NullPointerException:
//! s.toString();
try {
s.toString();
} catch(Exception e) {
System.out.println("Caught exception " + e);
}
}
}/****************** Exercise 5 ******************
* Create a class with two methods, f() and g().
* In g(), throw an exception of a new type that
* you define. In f(), call g(), catch its
* exception and, in the catch clause, throw a
* different exception (of a second type that you
* define). Test your code in main().
***********************************************/
class AnException extends Exception {}class AnotherException extends Exception {}
public class Ex05 {
public void g() throws AnException {
throw new AnException();
}
public void f() throws AnotherException {
try {
g();
} catch(AnException e) {
throw new AnotherException();
}
}
public static void main(String args[]) {
Ex05 ce = new Ex05();
try {
ce.f();
} catch(AnotherException e) {
System.out.println("Caught " + e);
}
}
}
/****************** Exercise 6 ******************
* Create three new types of exceptions. Write a
* class with a method that throws all three. In
* main(), call the method but only use a single
* catch clause that will catch all three types
* of exceptions.
***********************************************/
class ExBase extends Exception {}
class Ex1 extends ExBase {}
class Ex2 extends ExBase {}
class Ex3 extends ExBase {}class Thrower2 {
void f() throws Ex1, Ex2, Ex3 {
throw new Ex1();
// You aren't forced to throw all the
// exceptions in the specification.
}
}public class Ex06 {
public static void main(String args[]) {
Thrower2 t = new Thrower2();
try {
t.f();
} catch(ExBase e) {
System.out.println("caught " + e);
} catch(Exception e) {
// You could also have just caught
// Exception, since it's also a common
// base class to all three.
}
}
}/****************** Exercise 7 ******************
* Write code to generate and catch an
* ArrayIndexOutOfBoundsException.
***********************************************/
public class Ex07 {
public static void main(String args[]) {
char[] array = new char[10];
try {
array[10] = 'x';
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("e = " + e);
}
}
}
/****************** Exercise 8 ******************
* Create your own resumption-like behavior using
* a while loop that repeats until an exception
* is no longer thrown.
***********************************************/
class ResumerException extends Exception {}class Resumer {
static int count = 3;
void f() throws ResumerException {
if(--count > 0)
throw new ResumerException();
}
}public class Ex08 {
public static void main(String args[]) {
Resumer r = new Resumer();
while(true) {
try {
r.f();
} catch(ResumerException e) {
System.out.println("Caught " + e);
continue;
}
System.out.println("Got through...");
break;
}
System.out.println("Successful execution");
}
}
/****************** Exercise 9 ******************
* Create a three-level hierarchy of exceptions.
* Now create a base-class A with a method that
* throws an exception at the base of your
* hierarchy. Inherit B from A and override the
* method so it throws an exception at level two
* of your hierarchy. Repeat by inheriting class
* C from B. In main(), create a C and upcast it
* to A, then call the method.
***********************************************/
class Level1Exception extends Exception {}
class Level2Exception extends Level1Exception {}
class Level3Exception extends Level2Exception {}class A {
public void f() throws Level1Exception {
throw new Level1Exception();
}
}class B extends A {
public void f() throws Level2Exception {
throw new Level2Exception();
}
}class C extends B {
public void f() throws Level3Exception {
throw new Level3Exception();
}
}public class Ex09 {
public static void main(String args[]) {
A a = new C();
try {
a.f();
} catch(Level1Exception e) {
System.out.println("Caught " + e);
}
}
}
/****************** Exercise 10 *****************
* Demonstrate that a derived-class constructor
* cannot catch exceptions thrown by its
* base-class constructor.
***********************************************/
class Except1 extends Exception {
public Except1(String s) {
super(s);
}
}class BaseWithException {
public BaseWithException() throws Except1 {
throw new Except1(
"thrown by BaseWithException");
}
}class DerivedWE extends BaseWithException {
// Gives compile error:
// unreported exception Except1
// ! public DerivedWE() {}
// Gives compile error: call to super must be
// first statement in constructor:
//! public DerivedWE() {
//! try {
//! super();
//! } catch(Except1 ex1) {
//! }
//! }
public DerivedWE() throws Except1 {}
}public class Ex10 {
public static void main(String args[]) {
try {
new DerivedWE();
} catch(Except1 ex1) {
System.out.println("Caught " + ex1);
}
}
}
/****************** Exercise 11 *****************
* Show that OnOffSwitch.java can fail by
* throwing a RuntimeException inside the try
* block.
***********************************************/
class Switch {
boolean state = false;
boolean read() { return state; }
void on() { state = true; }
void off() { state = false; }
public String toString() {
return "Switch = " +
(state ? "on" : "off");
}
}
class OnOffException1 extends Exception {}
class OnOffException2 extends Exception {}public class Ex11 {
static Switch sw = new Switch();
static void f() throws
OnOffException1, OnOffException2 {
throw new RuntimeException("Inside try");
}
public static void main(String[] args) {
try {
try {
sw.on();
// Code that can throw exceptions...
f();
sw.off();
} catch(OnOffException1 e) {
System.err.println("OnOffException1");
sw.off();
} catch(OnOffException2 e) {
System.err.println("OnOffException2");
sw.off();
}
} catch(RuntimeException e) {
System.out.println(sw);
System.out.println("Oops! the exception '"
+ e + "' slipped through without "
+ "turning the switch off!");
}
}
}/****************** Exercise 12 *****************
* Show that WithFinally.java doesn't fail by
* throwing a RuntimeException inside the try
* block.
***********************************************/
public class Ex12 {
static Switch sw = new Switch();
static void f() throws
OnOffException1, OnOffException2 {
throw new RuntimeException("Inside try");
}
public static void main(String[] args) {
try {
try {
sw.on();
// Code that can throw exceptions...
f();
} catch(OnOffException1 e) {
System.err.println("OnOffException1");
} catch(OnOffException2 e) {
System.err.println("OnOffException2");
} finally {
sw.off();
}
} catch(RuntimeException e) {
System.out.println("Exception '" + e +
"'. Did the switch get turned off?");
System.out.println(sw);
}
}
}
/****************** Exercise 13 *****************
* Modify Exercise 6 by adding a finally clause.
* Verify your finally clause is executed, even
* if a NullPointerException is thrown.
***********************************************/
public class Ex13 {
public static void throwNull() {
throw new NullPointerException();
}
public static void main(String args[]) {
Thrower2 t = new Thrower2();
try {
t.f();
} catch(ExBase e) {
System.out.println("caught " + e);
} catch(Exception e) {
// You could also have just caught
// Exception, since it's also a common
// base class to all three.
} finally {
System.out.println("In finally clause");
}
try {
throwNull();
t.f();
} catch(ExBase e) {
System.out.println("caught " + e);
} catch(Exception e) {
// You could also have just caught
// Exception, since it's also a common
// base class to all three.
} finally {
System.out.println("In finally clause");
}
}
}
/****************** Exercise 14 *****************
* Create an example where you use a flag to
* control whether cleanup code is called, as
* described in the second paragraph after the
* heading "Constructors."
***********************************************/
// The paragraph reads:
/*
Since you've just learned about finally, you
might think that it is the correct solution. But
it's not quite that simple, because finally
performs the cleanup code every time, even in
the situations in which you don't want the
cleanup code executed until the cleanup method
runs. Thus, if you do perform cleanup in finally,
you must set some kind of flag when the
constructor finishes normally so that you don't
do anything in the finally block if the flag is
set. Because this isn't particularly elegant (you
are coupling your code from one place to
another), it's best if you try to avoid
performing this kind of cleanup in finally
unless you are forced to.
*/
class AbortedConstruction extends Exception {
public AbortedConstruction() {
super("Construction aborted");
}
}class WithCleanup {
private boolean constructed = false;
public WithCleanup(boolean abort)
throws AbortedConstruction {
// Perform construction that might be
// unsucessful (and throw an exception) here.
if(abort) throw new AbortedConstruction();
System.out.println("After exception");
constructed = true;
}
public void cleanup() {
System.out.println(
"constructed = " + constructed);
if(constructed == true)
System.out.println("Cleaning up");
else
System.out.println(
"Constructor didn't finish,"+
"not cleaning up");
}
}
public class Ex14 {
public static void main(String args[]) {
WithCleanup wc = null;
try {
wc = new WithCleanup(false);
} catch(AbortedConstruction e) {
System.out.println("Caught " + e);
} finally {
System.out.println(
"In finally 1, preparing to clean up");
wc.cleanup();
}
wc = null; // Very important!
try {
try {
wc = new WithCleanup(true);
} catch(AbortedConstruction e) {
System.out.println("Caught " + e);
} finally {
System.out.println(
"In finally 2, preparing to clean up");
wc.cleanup();
}
} catch(Exception e) {
System.out.println("Caught exception "+ e);
}
}
}/****************** Exercise 15 *****************
* Modify StormyInning.java by adding an
* UmpireArgument exception type, and methods
* that throw this exception. Test the modified
* hierarchy.
***********************************************/
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}
class UmpireArgument extends BaseballException {}abstract class Inning {
Inning() throws BaseballException {}
void event () throws BaseballException {}
abstract void atBat()
throws Strike, Foul, UmpireArgument;
abstract void decision() throws UmpireArgument;
void walk() {} // Throws nothing
}class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}interface Storm {
void event() throws RainedOut;
void rainHard() throws RainedOut;
}class StormyInning extends Inning
implements Storm {
StormyInning() throws RainedOut,
BaseballException {}
StormyInning(String s) throws Foul,
BaseballException {}
public void rainHard() throws RainedOut {}
public void event() {}
void atBat() throws PopFoul, UmpireArgument {
throw new UmpireArgument();
}
void decision() throws UmpireArgument {
throw new UmpireArgument();
}
}public class Ex15 {
public static void main(String[] args) {
// Same code as before, still catches
// the new exception:
try {
StormyInning si = new StormyInning();
si.atBat();
} catch(PopFoul e) {
System.err.println("Pop foul");
} catch(RainedOut e) {
System.err.println("Rained out");
} catch(BaseballException e) {
System.err.println("Generic error");
}
// Strike not thrown in derived version.
try {
Inning i = new StormyInning();
i.atBat();
} catch(Strike e) {
System.err.println("Strike");
} catch(Foul e) {
System.err.println("Foul");
} catch(RainedOut e) {
System.err.println("Rained out");
} catch(BaseballException e) {
System.err.println(
"Generic baseball exception");
}
// Or you can add code to catch the
// specific type of exception:
try {
StormyInning si = new StormyInning();
si.atBat();
si.decision();
} catch(PopFoul e) {
System.err.println("Pop foul");
} catch(RainedOut e) {
System.err.println("Rained out");
} catch(UmpireArgument e) {
System.err.println(
"Argument with the umpire");
} catch(BaseballException e) {
System.err.println("Generic error");
}
}
}
/****************** Exercise 16 *****************
* Remove the first catch clause in Human.java
* and verify that the code still compiles and
* runs properly.
***********************************************/
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}public class Ex16 {
public static void main(String[] args) {
try {
throw new Sneeze();
} catch(Annoyance a) {
System.err.println("Caught Annoyance");
}
}
}/****************** Exercise 17 *****************
* Add a second level of exception loss to
* LostMessage.java so that the HoHumException is
* itself replaced by a third exception.
***********************************************/
class VeryImportantException extends Exception {
public String toString() {
return "A very important exception!";
}
}class HoHumException extends Exception {
public String toString() {
return "A trivial exception";
}
}class YetAnotherException extends Exception {
public String toString() {
return "Yet another exception";
}
}class LostMessage {
void f() throws VeryImportantException {
throw new VeryImportantException();
}
void dispose() throws HoHumException {
throw new HoHumException();
}
void cleanup() throws YetAnotherException {
throw new YetAnotherException();
}
}public class Ex17 {
public static void main(String[] args)
throws Exception {
LostMessage lm = new LostMessage();
try {
try {
try {
lm.f();
} finally {
lm.dispose();
}
} finally {
lm.cleanup();
}
} catch(YetAnotherException e) {
System.out.println("Caught " + e);
}
}
}/****************** Exercise 18 *****************
* In Chapter 5, find the two programs called
* Assert.java and modify these to throw their
* own type of exception instead of printing to
* System.err. This exception should be an inner
* class that extends RuntimeException.
***********************************************/
class Assert {
// Don't need perr() anymore, with the exception
static class AssertException
extends RuntimeException {
public AssertException(String s) {
super(s);
}
}
public final static void is_true(boolean exp) {
if(!exp) throw new AssertException(
"Assertion failed");
}
public final static void is_false(boolean exp){
if(exp) throw new AssertException(
"Assertion failed");
}
public final static void
is_true(boolean exp, String msg) {
if(!exp) throw new AssertException(
"Assertion failed: " + msg);
}
public final static void
is_false(boolean exp, String msg) {
if(exp) throw new AssertException(
"Assertion failed: " + msg);
}
}public class Ex18 {
public static void main(String[] args) {
// Use try blocks so program can successfully
// run to completion:
try {
Assert.is_true((2 + 2) == 5);
} catch(RuntimeException e) {
System.out.println("Caught " + e);
}
try {
Assert.is_false((1 + 1) == 2);
} catch(RuntimeException e) {
System.out.println("Caught " + e);
}
try {
Assert.is_true((2 + 2) == 5, "2 + 2 == 5");
} catch(RuntimeException e) {
System.out.println("Caught " + e);
}
try {
Assert.is_false((1 + 1) == 2, "1 +1 != 2");
} catch(RuntimeException e) {
System.out.println("Caught " + e);
}
}
}
/****************** Exercise 19 *****************
* Add an appropriate set of exceptions to
* c08:GreenhouseControls.java.
***********************************************/
class ActionFailed extends Exception {
public ActionFailed(String s) {
super(s);
}
}abstract class Event {
private long evtTime;
public Event(long eventTime) {
evtTime = eventTime;
}
public boolean ready() {
return System.currentTimeMillis() >= evtTime;
}
abstract public void action()
throws ActionFailed;
abstract public String description();
}class EventSet {
private Event[] events = new Event[100];
private int index = 0;
private int next = 0;
public void add(Event e) {
if(index >= events.length)
return; // (In real life, throw exception)
events[index++] = e;
}
public Event getNext() {
boolean looped = false;
int start = next;
do {
next = (next + 1) % events.length;
// See if it has looped to the beginning:
if(start == next) looped = true;
// If it loops past start, the list
// is empty:
if((next == (start + 1) % events.length)
&& looped)
return null;
} while(events[next] == null);
return events[next];
}
public void removeCurrent() {
events[next] = null;
}
}class Controller {
private EventSet es = new EventSet();
public void addEvent(Event c) { es.add(c); }
public void run() {
Event e;
while((e = es.getNext()) != null) {
if(e.ready()) {
try {
e.action();
} catch(ActionFailed f) {
System.out.println("Caught " + f);
}
System.out.println(e.description());
es.removeCurrent();
}
}
}
}
class GreenhouseControls
extends Controller {
private boolean light = false;
private boolean water = false;
private String thermostat = "Day";
private class LightOn extends Event {
public LightOn(long eventTime) {
super(eventTime);
}
public void action() throws ActionFailed {
// Put hardware control code here to
// physically turn on the light.
light = true;
throw new ActionFailed("LightOn");
}
public String description() {
return "Light is on";
}
}
private class LightOff extends Event {
public LightOff(long eventTime) {
super(eventTime);
}
public void action() throws ActionFailed {
// Put hardware control code here to
// physically turn off the light.
light = false;
throw new ActionFailed("LightOff");
}
public String description() {
return "Light is off";
}
}
private class WaterOn extends Event {
public WaterOn(long eventTime) {
super(eventTime);
}
public void action() throws ActionFailed {
// Put hardware control code here
water = true;
throw new ActionFailed("WaterOn");
}
public String description() {
return "Greenhouse water is on";
}
}
private class WaterOff extends Event {
public WaterOff(long eventTime) {
super(eventTime);
}
public void action() throws ActionFailed {
// Put hardware control code here
water = false;
throw new ActionFailed("WaterOff");
}
public String description() {
return "Greenhouse water is off";
}
}
private class ThermostatNight extends Event {
public ThermostatNight(long eventTime) {
super(eventTime);
}
public void action() throws ActionFailed {
// Put hardware control code here
thermostat = "Night";
throw new ActionFailed("ThermostatNight");
}
public String description() {
return "Thermostat on night setting";
}
}
private class ThermostatDay extends Event {
public ThermostatDay(long eventTime) {
super(eventTime);
}
public void action() throws ActionFailed {
// Put hardware control code here
thermostat = "Day";
throw new ActionFailed("ThermostatDay");
}
public String description() {
return "Thermostat on day setting";
}
}
// An example of an action() that inserts a
// new one of itself into the event list:
private int rings;
private class Bell extends Event {
public Bell(long eventTime) {
super(eventTime);
}
public void action() {
// Ring every 2 seconds, 'rings' times:
System.out.println("Bing!");
if(--rings > 0)
addEvent(new Bell(
System.currentTimeMillis() + 200));
}
public String description() {
return "Ring bell";
}
}
public class Restart extends Event {
public Restart(long eventTime) {
super(eventTime);
}
public void action() {
long tm = System.currentTimeMillis();
// Instead of hard-wiring, you could parse
// configuration information from a text
// file here:
rings = 5;
addEvent(new ThermostatNight(tm));
addEvent(new LightOn(tm + 100));
addEvent(new LightOff(tm + 200));
addEvent(new WaterOn(tm + 300));
addEvent(new WaterOff(tm + 800));
addEvent(new Bell(tm + 900));
addEvent(new ThermostatDay(tm + 1000));
// Can even add a Restart object!
addEvent(new Restart(tm + 2000));
}
public String description() {
return "Restarting system";
}
}}
public class Ex19 {
public static void main(String[] args) {
GreenhouseControls gc =
new GreenhouseControls();
long tm = System.currentTimeMillis();
gc.addEvent(gc.new Restart(tm));
gc.run();
}
} -
[Thinking in Java练习题](九)持有你的对象(下)
2006年08月25日
/****************** Exercise 23 *****************
* Produce a Map and a Set containing all the
* countries that begin with 'A.'
***********************************************/
import com.bruceeckel.util.*;
import java.util.*;public class Ex23 {
public static void main(String args[]) {
TreeMap map = new TreeMap();
TreeSet set = new TreeSet();
Collections2.fill(map,Collections2.geography,
CountryCapitals.pairs.length);
Collections2.fill(set,Collections2.countries,
CountryCapitals.pairs.length);
Iterator it = map.keySet().iterator();
String b = null;
while(it.hasNext()) {
String s = (String)it.next();
if(s.startsWith("B")) {
b = s;
break;
}
}
Map aMap = map.headMap(b);
Set aSet = set.headSet(b);
System.out.println("aMap = " + aMap);
System.out.println("aSet = " + aSet);
}
}/****************** Exercise 24 *****************
* Using Collections2.countries, fill a Set
* multiple times with the same data and verify
* that the Set ends up with only one of each
* instance. Try this with both kinds of Set.
***********************************************/
import com.bruceeckel.util.*;
import java.util.*;public class Ex24 {
public static void main(String args[]) {
TreeSet set = new TreeSet();
Collections2.fill(
set, Collections2.countries.reset(), 10);
Collections2.fill(
set, Collections2.countries.reset(), 10);
Collections2.fill(
set, Collections2.countries.reset(), 10);
System.out.println("set = " + set);
}
}import java.util.*;
class Counter {
int i = 1;
public String toString() {
return Integer.toString(i);
}
}class HistoUnit implements Comparable {
Counter counter;
Integer val;
public HistoUnit(Counter counter, Integer val) {
this.counter = counter;
this.val = val;
}
public int compareTo(Object o) {
int lv = ((HistoUnit)o).counter.i;
int rv = counter.i;
return (lv < rv ? -1 : (lv == rv ? 0 : 1));
}
public String toString() {
return "Value = " + val
+ ", Occurrences = " + counter.i + "\n";
}
}public class Ex25 {
public static void main(String[] args) {
HashMap hm = new HashMap();
for(int i = 0; i < 10000000; i++) {
// Produce a number between 0 and 100:
Integer r =
new Integer((int)(Math.random() * 100));
if(hm.containsKey(r))
((Counter)hm.get(r)).i++;
else
hm.put(r, new Counter());
}
// Make a histogram:
List lst = new ArrayList();
Iterator it = hm.keySet().iterator();
while(it.hasNext()) {
Integer key = (Integer)it.next();
lst.add(new HistoUnit(
(Counter)hm.get(key), key));
}
Collections.sort(lst);
System.out.println("lst = " + lst);
}
}
/****************** Exercise 26 *****************
* Rewrite Statistics.java using a HashSet of
* Counter objects (you'll have to modify Counter
* so that it will work in the HashSet). Which
* approach seems better?
***********************************************/
import java.util.*;class Counter2 {
int count = 1;
Integer value;
public Counter2(int val) {
this.value = new Integer(val);
}
public String toString() {
return "value: " + value + ", occurrences: "
+ Integer.toString(count) + " hashcode: "
+ hashCode() + "\n";
}
public int hashCode() {
return value.hashCode();
}
public boolean equals(Object obj) {
return obj instanceof Counter2 &&
((Counter2)obj).value.equals(value);
// This doesn't work!:
//! ((Counter2)obj).value == value;
}
}public class Ex26 {
public static void main(String[] args) {
HashSet hs = new HashSet();
for(int i = 0; i < 100000; i++) {
// Produce a number between 0 and 20:
Counter2 c =
new Counter2((int)(Math.random() * 20));
if(hs.contains(c)) {
// The only way to access the set
// elements is with an iterator:
Iterator it = hs.iterator();
while(it.hasNext()) {
Counter2 ig = (Counter2)it.next();
//! if(ig == c) { // This doesn't work!
if(ig.equals(c)) {
ig.count++;
break;
}
}
}
else
hs.add(c);
}
System.out.println(hs);
}
}/****************** Exercise 27 *****************
* Modify the class in Exercise 13 so that it
* will work with HashSets and as a key in
* HashMaps.
***********************************************/
import com.bruceeckel.util.*;
import java.util.*;class SCompType2 implements Comparable {
String s1, s2;
public SCompType2(String s1i, String s2i) {
s1 = s1i;
s2 = s2i;
}
public String toString() {
return "\n[s1 = "+ s1 + ", s2 = " + s2 + "]";
}
public int compareTo(Object rv) {
String rvi = ((SCompType2)rv).s1;
return s1.compareTo(rvi);
}
public int hashCode() {
// Since the comparisons are based on s1,
// use s1's hashCode:
return s1.hashCode();
}
public boolean equals(Object obj) {
return obj instanceof SCompType2 &&
((SCompType2)obj).s1.equals(s1);
}
private static Arrays2.RandStringGenerator gen =
new Arrays2.RandStringGenerator(7);
public static Generator generator() {
return new Generator() {
public Object next() {
return new SCompType2(
(String)gen.next(),(String)gen.next());
}
};
}
}public class Ex27 {
public static void main(String args[]) {
HashSet hs = new HashSet();
HashMap hm = new HashMap();
Generator gen = SCompType2.generator();
Collections2.fill(hs, gen , 20);
for(int i = 0; i < 20; i++)
hm.put(gen.next(), new Integer(i));
System.out.println("hs = " + hs);
System.out.println("hm = " + hm);
}
}/****************** Exercise 28 *****************
* Using SlowMap.java for inspiration, create a
* SlowSet.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class SlowSet extends AbstractSet {
private ArrayList keys = new ArrayList();
public boolean add(Object key) {
if(!contains(key)) {
keys.add(key);
return true;
} else
return false;
}
public boolean contains(Object key) {
return keys.contains(key);
}
public Iterator iterator() {
return keys.iterator();
}
public int size() {
return keys.size();
}
}public class Ex28 {
public static void main(String[] args) {
SlowSet ss = new SlowSet();
Collections2.fill(ss,
Collections2.countries.reset(), 10);
Collections2.fill(ss,
Collections2.countries.reset(), 10);
Collections2.fill(ss,
Collections2.countries.reset(), 10);
System.out.println(ss);
}
}
/****************** Exercise 29 *****************
* Apply the tests in Map1.java to SlowMap to
* verify that it works. Fix anything in SlowMap
* that doesn't work correctly.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class MPair
implements Map.Entry, Comparable {
Object key, value;
MPair(Object k, Object v) {
key = k;
value = v;
}
public Object getKey() { return key; }
public Object getValue() { return value; }
public Object setValue(Object v){
Object result = value;
value = v;
return result;
}
public boolean equals(Object o) {
return key.equals(((MPair)o).key);
}
public int compareTo(Object rv) {
return ((Comparable)key).compareTo(
((MPair)rv).key);
}
}class SlowMap2 extends AbstractMap {
private ArrayList
keys = new ArrayList(),
values = new ArrayList();
public Object put(Object key, Object value) {
Object result = get(key);
if(!keys.contains(key)) {
keys.add(key);
values.add(value);
} else
values.set(keys.indexOf(key), value);
return result;
}
public Object get(Object key) {
if(!keys.contains(key))
return null;
return values.get(keys.indexOf(key));
}
public Set entrySet() {
Set entries = new HashSet();
Iterator
ki = keys.iterator(),
vi = values.iterator();
while(ki.hasNext())
entries.add(new MPair(ki.next(), vi.next()));
return entries;
}
}public class Ex29 {
static Collections2.StringPairGenerator geo =
Collections2.geography;
static Collections2.RandStringPairGenerator
rsp = Collections2.rsp;
// Producing a Set of the keys:
public static void printKeys(Map m) {
System.out.print("Size = " + m.size() +", ");
System.out.print("Keys: ");
System.out.println(m.keySet());
}
// Producing a Collection of the values:
public static void printValues(Map m) {
System.out.print("Values: ");
System.out.println(m.values());
}
public static void test(Map m) {
Collections2.fill(m, geo, 25);
// Map has 'Set' behavior for keys:
Collections2.fill(m, geo.reset(), 25);
printKeys(m);
printValues(m);
System.out.println(m);
String key = CountryCapitals.pairs[4][0];
String value = CountryCapitals.pairs[4][1];
System.out.println("m.containsKey(\"" + key +
"\"): " + m.containsKey(key));
System.out.println("m.get(\"" + key + "\"): "
+ m.get(key));
System.out.println("m.containsValue(\""
+ value + "\"): " +
m.containsValue(value));
Map m2 = new TreeMap();
Collections2.fill(m2, rsp, 25);
m.putAll(m2);
printKeys(m);
key = m.keySet().iterator().next().toString();
System.out.println("First key in map: "+key);
m.remove(key);
printKeys(m);
m.clear();
System.out.println("m.isEmpty(): "
+ m.isEmpty());
Collections2.fill(m, geo.reset(), 25);
// Operations on the Set change the Map:
m.keySet().removeAll(m.keySet());
System.out.println("m.isEmpty(): "
+ m.isEmpty());
}
public static void main(String[] args) {
System.out.println("Testing SlowMap2");
test(new SlowMap2());
}
}/****************** Exercise 30 *****************
* Implement the rest of the Map interface for
* SlowMap.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class FullSlowMap extends AbstractMap {
private ArrayList
keys = new ArrayList(),
values = new ArrayList();
public Object put(Object key, Object value) {
Object result = get(key);
if(!keys.contains(key)) {
keys.add(key);
values.add(value);
} else
values.set(keys.indexOf(key), value);
return result;
}
public Object get(Object key) {
if(!keys.contains(key))
return null;
return values.get(keys.indexOf(key));
}
public Set entrySet() {
Set entries = new HashSet();
Iterator
ki = keys.iterator(),
vi = values.iterator();
while(ki.hasNext())
entries.add(new MPair(ki.next(), vi.next()));
return entries;
}
public int size() {
return keys.size();
}
public boolean isEmpty() {
return keys.isEmpty();
}
public boolean containsValue(Object value) {
return values.contains(value);
}
public boolean containsKey(Object key) {
return keys.contains(key);
}
public Object remove(Object key) {
if(!containsKey(key)) return null;
int index = keys.indexOf(key);
Object value = values.get(index);
values.remove(index);
keys.remove(index);
return value;
}
public void putAll(Map t) {
Iterator it = t.entrySet().iterator();
while(it.hasNext()) {
Entry me = (Entry)it.next();
put(me.getKey(), me.getValue());
}
// Or you can just call super.putAll(t),
// since it is implemented in
// AbstractMap.
}
public void clear() {
keys.clear();
values.clear();
}
public Set keySet() {
return new HashSet(keys);
}
public Collection values() {
return values;
}
}public class Ex30 {
public static void main(String[] args) {
FullSlowMap m = new FullSlowMap();
Collections2.fill(m,
Collections2.geography, 25);
FullSlowMap m2 = new FullSlowMap();
m2.putAll(m);
System.out.println(
"m2.entrySet() = " + m2.entrySet());
}
}
/****************** Exercise 31 *****************
* Modify MapPerformance.java to include tests of
* SlowMap.
***********************************************/
import com.bruceeckel.util.*;
import java.util.*;public class Ex31 {
private abstract static class Tester {
String name;
Tester(String name) { this.name = name; }
abstract void test(Map m, int size, int reps);
}
private static Tester[] tests = {
new Tester("put") {
void test(Map m, int size, int reps) {
for(int i = 0; i < reps; i++) {
m.clear();
Collections2.fill(m,
Collections2.geography.reset(), size);
}
}
},
new Tester("get") {
void test(Map m, int size, int reps) {
for(int i = 0; i < reps; i++)
for(int j = 0; j < size; j++)
m.get(Integer.toString(j));
}
},
new Tester("iteration") {
void test(Map m, int size, int reps) {
for(int i = 0; i < reps * 10; i++) {
Iterator it = m.entrySet().iterator();
while(it.hasNext())
it.next();
}
}
},
};
public static void
test(Map m, int size, int reps) {
System.out.println("Testing " +
m.getClass().getName() + " size " + size);
Collections2.fill(m,
Collections2.geography.reset(), size);
for(int i = 0; i < tests.length; i++) {
System.out.print(tests[i].name);
long t1 = System.currentTimeMillis();
tests[i].test(m, size, reps);
long t2 = System.currentTimeMillis();
System.out.println(": " +
((double)(t2 - t1)/(double)size));
}
}
public static void main(String[] args) {
int reps = 50000;
// Or, choose the number of repetitions
// via the command line:
if(args.length > 0)
reps = Integer.parseInt(args[0]);
// Small:
test(new TreeMap(), 10, reps);
test(new HashMap(), 10, reps);
test(new Hashtable(), 10, reps);
test(new FullSlowMap(), 10, reps);
// Medium:
test(new TreeMap(), 100, reps);
test(new HashMap(), 100, reps);
test(new Hashtable(), 100, reps);
test(new FullSlowMap(), 100, reps);
// Large:
test(new TreeMap(), 1000, reps);
test(new HashMap(), 1000, reps);
test(new Hashtable(), 1000, reps);
}
}/****************** Exercise 32 *****************
* Modify SlowMap so that instead of two
* ArrayLists, it holds a single ArrayList of
* MPair objects. Verify that the modified
* version works correctly. Using
* MapPerformance.java, test the speed of your
* new Map. Now change the put() method so that
* it performs a sort() after each pair is
* entered, and modify get() to use
* Collections.binarySearch() to look up the key.
* Compare the performance of the new version
* with the old ones.
***********************************************/
import com.bruceeckel.util.Collections2;
import java.util.*;class SlowMap3 extends AbstractMap {
private ArrayList mpairs = new ArrayList();
public Object put(Object key, Object value) {
MPair pair = new MPair(key, value);
if(!mpairs.contains(pair))
mpairs.add(pair);
else
mpairs.set(mpairs.indexOf(pair), pair);
return pair;
}
public Object get(Object key) {
MPair searchKey = new MPair(key, null);
if(!mpairs.contains(searchKey))
return null;
return mpairs.get(mpairs.indexOf(searchKey));
}
public Set entrySet() {
return new HashSet(mpairs);
}
public int size() {
return mpairs.size();
}
// public boolean isEmpty() {
// return mpairs.isEmpty();
// }
// public boolean containsKey(Object key) {
// MPair pair = new MPair(key, null);
// return mpairs.contains(key);
// }
// public Object remove(Object key) {
// if(!containsKey(key)) return null;
// MPair pair = new MPair(key, null);
// int index = mpairs.indexOf(pair);
// Object value =
// ((MPair)mpairs.get(index)).getValue();
// mpairs.remove(index);
// return value;
// }
// public void putAll(Map t) {
// Iterator it = t.entrySet().iterator();
// while(it.hasNext()) {
// Map.Entry me = (Map.Entry)it.next();
// put(me.getKey(), me.getValue());
// }
// }
// public void clear() {
// mpairs.clear();
// }
// public Set keySet() {
// Set ks = new HashSet();
// Iterator it = mpairs.iterator();
// while(it.hasNext())
// ks.add(((MPair)it.next()).getKey());
// return ks;
// }
// public Collection values() {
// Collection vc = new ArrayList();
// Iterator it = mpairs.iterator();
// while(it.hasNext())
// vc.add(((MPair)it.next()).getValue());
// return vc;
// }
}public class Ex32 {
public static void main(String args[]) {
SlowMap3 sm3 = new SlowMap3();
Collections2.fill(sm3,
Collections2.geography, 25);
System.out.println(sm3);
System.out.println("Testing SlowMap3");
Ex29.test(new SlowMap3());
}
}/****************** Exercise 33 *****************
* Add a char field to CountedString that is also
* initialized in the constructor, and modify the
* hashCode() and equals() methods to include the
* value of this char.
***********************************************/
import java.util.*;class CountedString {
private String s;
private char c;
private int id = 0;
private static ArrayList created =
new ArrayList();
public CountedString(String str, char ci) {
s = str;
c = ci;
created.add(s);
Iterator it = created.iterator();
// Id is the total number of instances
// of this string in use by CountedString:
while(it.hasNext())
if(it.next().equals(s))
id++;
}
public String toString() {
return "\nString: " + s + " id: " + id +
" char: " + c +
" hashCode(): " + hashCode();
}
public int hashCode() {
return s.hashCode() * id * c;
}
public boolean equals(Object o) {
return (o instanceof CountedString)
&& s.equals(((CountedString)o).s)
&& c == ((CountedString)o).c
&& id == ((CountedString)o).id;
}
}public class Ex33 {
public static void main(String[] args) {
HashMap m = new HashMap();
CountedString[] cs = new CountedString[10];
for(int i = 0; i < cs.length; i++) {
cs[i] = new CountedString("hi", 'c');
m.put(cs[i], new Integer(i));
}
System.out.println(m);
for(int i = 0; i < cs.length; i++) {
System.out.print("Looking up " + cs[i] + "\n");
System.out.println(m.get(cs[i]));
}
}
}/****************** Exercise 34 *****************
* Modify SimpleHashMap so that it reports
* collisions, and test this by adding the same
* data set twice so that you see collisions.
***********************************************/
import com.bruceeckel.util.Collections2;
import java.util.*;class SimpleHashMap2 extends AbstractMap {
private final static int SZ = 997;
private LinkedList[] bucket= new LinkedList[SZ];
public Object put(Object key, Object value) {
// Key-value pair to add:
MPair pair = new MPair(key, value);
Object result = null;
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
// Lines added here:
else {
System.out.println(
"Collision while adding\n" + pair
+ "\nBucket already contains:");
Iterator it = bucket[index].iterator();
while(it.hasNext())
System.out.println(it.next());
}
// End of lines added
LinkedList pairs = bucket[index];
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
}public class Ex34 {
public static void main(String[] args) {
SimpleHashMap2 m = new SimpleHashMap2();
Collections2.fill(m,
Collections2.geography, 25);
Collections2.fill(m,
Collections2.geography.reset(), 25);
System.out.println(m);
}
}
/****************** Exercise 36 *****************
* Implement the clear() and remove() methods for
* SimpleHashMap.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class SimpleHashMap3 extends AbstractMap {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
private final static int SZ = 997;
private LinkedList[] bucket= new LinkedList[SZ];
public Object put(Object key, Object value) {
Object result = null;
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
LinkedList pairs = bucket[index];
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
public void clear() {
// Effectively erase everything by allocating
// a new empty array of buckets:
bucket= new LinkedList[SZ];
}
public Object remove(Object key) {
// Code is copied from get(), except that
// before returning the value, the MPair is
// removed from the list:
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match)) {
// Changes are here:
Object value = ((MPair)iPair).getValue();
// Removes the last fetched value:
it.remove();
return value;
}
}
return null;
}
}public class Ex36 {
public static void main(String[] args) {
SimpleHashMap3 m = new SimpleHashMap3();
Collections2.fill(m,
Collections2.geography, 10);
System.out.println(m);
System.out.println("m.get(\"BURUNDI\") = "
+ m.get("BURUNDI"));
m.remove("BURUNDI");
System.out.println(
"After removal, m.get(\"BURUNDI\") = "
+ m.get("BURUNDI"));
m.clear();
System.out.println("After clearing: " + m);
}
}
/****************** Exercise 37 *****************
* Implement the rest of the Map interface for
* SimpleHashMap.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class FullSimpleHashMap extends AbstractMap {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
private final static int SZ = 997;
private LinkedList[] bucket= new LinkedList[SZ];
public Object put(Object key, Object value) {
Object result = null;
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
LinkedList pairs = bucket[index];
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
public void clear() {
// Effectively erase everything by allocating
// a new empty array of buckets:
bucket= new LinkedList[SZ];
}
public Object remove(Object key) {
// Code is copied from get(), except that
// before returning the value, the MPair is
// removed from the list:
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match)) {
// Changes are here:
Object value = ((MPair)iPair).getValue();
// Removes the last fetched value:
it.remove();
return value;
}
}
return null;
}
public int size() {
int sz = 0;
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
it.next();
sz++;
}
return sz;
}
public boolean isEmpty() {
// Could just say return size() == 0;
// but this is faster:
for(int i = 0; i < bucket.length; i++)
if(bucket[i] == null) continue;
else return false;
return true;
}
public boolean containsValue(Object value) {
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
if(((MPair)it.next()).getValue()
.equals(value))
return true;
}
return false;
}
public boolean containsKey(Object key) {
// A slight modification of
// the previous method:
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
if(((MPair)it.next()).getKey()
.equals(key))
return true;
}
return false;
}
public void putAll(Map t) {
// AbstractMap has a working implementation:
super.putAll(t);
}
public Set keySet() {
// A variation of entrySet():
Set keys = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
keys.add(((MPair)it.next()).getKey());
}
return keys;
}
public Collection values() {
// A variation of keySet():
Collection values = new ArrayList();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
values.add(((MPair)it.next()).getValue());
}
return values;
}
public boolean equals(Object o) {
// Version in AbstractMap is OK:
return super.equals(o);
}
}public class Ex37 {
public static void main(String args[]) {
FullSimpleHashMap m = new FullSimpleHashMap(),
m2 = new FullSimpleHashMap();
Collections2.fill(m,
Collections2.geography, 10);
Collections2.fill(m2,
Collections2.geography.reset(), 10);
System.out.println("m.size() = " + m.size());
System.out.println("m.isEmpty() = "
+ m.isEmpty());
System.out.println("m.equals(m2) = "
+ m.equals(m2));
System.out.println("m.keySet() = "
+ m.keySet());
System.out.println("m.values() = "
+ m.values());
}
}/****************** Exercise 38 *****************
* Add a private rehash() method to SimpleHashMap
* that is invoked when the load factor exceeds
* 0.75. During rehashing, double the number of
* buckets, then search for the first prime
* number greater than that to determine the new
* number of buckets.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class SimpleHashMap4 extends AbstractMap {
private int count = 0; // Number of elements
private static final double loadFactor = 0.75;
// Use the same initial capacity as in
// java.util.HashMap:
private final static int initialCapacity = 11;
private int capacity = initialCapacity;
private int threshold =
(int)(capacity * loadFactor);
private LinkedList[] bucket =
new LinkedList[capacity];
public Object put(Object key, Object value) {
Object result = null;
int index = key.hashCode() % capacity;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
LinkedList pairs = bucket[index];
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found) {
if (count >= threshold)
rehash();
if(bucket[index] == null)
bucket[index] = new LinkedList();
bucket[index].add(pair);
count++;
}
return result;
}
public Object get(Object key) {
int index = key.hashCode() % capacity;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
private boolean isPrime(int candidate) {
for(int j = 2; j < candidate; j++)
if(candidate % j == 0) return false;
return true;
}
private int nextPrime(int candidate) {
while(!isPrime(candidate))
candidate++;
return candidate;
}
private void rehash() {
// Points to a new Set of the entries, so it
// won't be bothered by what we're about
// to do:
Iterator it = entrySet().iterator();
// Get next prime capacity:
capacity = nextPrime(capacity * 2);
System.out.println(
"Rehashing, new capacity = " + capacity);
bucket = new LinkedList[capacity];
threshold = (int)(capacity * loadFactor);
// Fill new buckets (crude, but it works):
while(it.hasNext()) {
MPair mp = (MPair)it.next();
put(mp.getKey(), mp.getValue());
}
}
}public class Ex38 {
public static void main(String[] args) {
SimpleHashMap4 m = new SimpleHashMap4();
Collections2.fill(m,
Collections2.geography, 50);
System.out.println(m);
}
}/****************** Exercise 39 *****************
* Following the example in SimpleHashMap.java,
* create and test a SimpleHashSet.
***********************************************/
import com.bruceeckel.util.Collections2;
import java.util.*;class SimpleHashSet extends AbstractSet {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
private final static int SZ = 997;
private LinkedList[] bucket= new LinkedList[SZ];
public boolean add(Object key) {
int index = key.hashCode() % SZ;
if (index < 0) index = -index;
if (bucket[index] == null)
bucket[index] = new LinkedList();
ListIterator it = bucket[index].listIterator();
while(it.hasNext())
if (it.next().equals(key))
return false;
// Sets do not permit duplicates and one
// was already in the set.
it.add(key);
return true; // Successful add
}
public boolean contains(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return false;
Iterator it = bucket[index].iterator();
while(it.hasNext())
if(it.next().equals(key))
return true;
return false;
}
public int size() {
int sz = 0;
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
it.next();
sz++;
}
return sz;
}
public Iterator iterator() {
ArrayList al = new ArrayList();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
al.add(it.next());
}
return al.iterator();
}
}public class Ex39 {
public static void main(String[] args) {
SimpleHashSet m = new SimpleHashSet();
Collections2.fill(m,
Collections2.countries, 10);
Collections2.fill(m,
Collections2.countries.reset(), 10);
System.out.println("m = " + m);
System.out.println("m.size() = " + m.size());
Iterator it = m.iterator();
System.out.println("it.next()= "+ it.next());
}
}
/****************** Exercise 40 *****************
* Modify SimpleHashMap to use ArrayLists instead
* of LinkedLists. Modify MapPerformance.java to
* compare the performance of the two
* implementations.
***********************************************/
import java.util.*;
import com.bruceeckel.util.*;class SimpleHashMap5 extends AbstractMap {
private final static int SZ = 997;
private ArrayList[] bucket= new ArrayList[SZ];
public Object put(Object key, Object value) {
Object result = null;
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new ArrayList();
ArrayList pairs = bucket[index];
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
ArrayList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
}public class Ex40 {
private abstract static class Tester {
String name;
Tester(String name) { this.name = name; }
abstract void test(Map m, int size, int reps);
}
private static Tester[] tests = {
new Tester("put") {
void test(Map m, int size, int reps) {
for(int i = 0; i < reps; i++) {
m.clear();
Collections2.fill(m,
Collections2.geography.reset(), size);
}
}
},
new Tester("get") {
void test(Map m, int size, int reps) {
for(int i = 0; i < reps; i++)
for(int j = 0; j < size; j++)
m.get(Integer.toString(j));
}
},
new Tester("iteration") {
void test(Map m, int size, int reps) {
for(int i = 0; i < reps * 10; i++) {
Iterator it = m.entrySet().iterator();
while(it.hasNext())
it.next();
}
}
},
};
public static void
test(Map m, int size, int reps) {
System.out.println("Testing " +
m.getClass().getName() + " size " + size);
Collections2.fill(m,
Collections2.geography.reset(), size);
for(int i = 0; i < tests.length; i++) {
System.out.print(tests[i].name);
long t1 = System.currentTimeMillis();
tests[i].test(m, size, reps);
long t2 = System.currentTimeMillis();
System.out.println(": " +
((double)(t2 - t1)/(double)size));
}
}
public static void main(String[] args) {
SimpleHashMap5 m = new SimpleHashMap5();
Collections2.fill(m,
Collections2.geography, 25);
System.out.println(m);
int reps = 50000;
// Small:
test(new FullSimpleHashMap(), 10, reps);
test(new SimpleHashMap5(), 10, reps);
// Medium:
test(new FullSimpleHashMap(), 100, reps);
test(new SimpleHashMap5(), 100, reps);
// Large:
test(new FullSimpleHashMap(), 1000, reps);
test(new SimpleHashMap5(), 1000, reps);
}
}
/****************** Exercise 41 *****************
* Using the HTML documentation for the JDK
* (downloadable from java.sun.com), look up the
* HashMap class. Create a HashMap, fill it with
* elements, and determine the load factor. Test
* the lookup speed with this map, then attempt
* to increase the speed by making a new HashMap
* with a larger initial capacity and copying the
* old map into the new one, running your lookup
* speed test again on the new map.
***********************************************/
import com.bruceeckel.util.*;
import java.util.HashMap;public class Ex41 {
public static
void testGet(HashMap filledMap, int n) {
for(int tc = 0; tc < 10000000; tc++)
for(int i = 0; i < n; i++) {
Object key = CountryCapitals.pairs[i][0];
if (filledMap.get(key) == null)
System.out.println("Not found: " + key);
}
}
public static void main(String args[]) {
// Initial capacity 11:
HashMap map = new HashMap();
// Fill to less than threshold:
Collections2.fill(map,
Collections2.geography.reset(), 8);
// Initial capacity 22:
HashMap map2 = new HashMap(22);
// Fill to less than threshold:
Collections2.fill(map2,
Collections2.geography.reset(), 16);
long t1 = System.currentTimeMillis();
testGet(map, 8);
long t2 = System.currentTimeMillis();
System.out.println("map : " + (t2 - t1));
t1 = System.currentTimeMillis();
testGet(map2, 8);
t2 = System.currentTimeMillis();
System.out.println("map2 : " + (t2 - t1));
}
}
/****************** Exercise 42 *****************
* In Chapter 8, locate the
* GreenhouseControls.java example, which
* consists of three files. In Controller.java,
* the class EventSet is just a container. Change
* the code to use a LinkedList instead of an
* EventSet. This will require more than just
* replacing EventSet with LinkedList; you'll
* also need to use an Iterator to cycle through
* the set of events.
***********************************************/
import java.util.*;abstract class Event {
private long evtTime;
public Event(long eventTime) {
evtTime = eventTime;
}
public boolean ready() {
return System.currentTimeMillis() >= evtTime;
}
abstract public void action();
abstract public String description();
public String toString() {
return "Event: " + description();
}
}class Controller {
private LinkedList es = new LinkedList();
public void addEvent(Event c) {
System.out.println("Adding " + c);
es.add(c);
}
// This wouldn't work:
// public void run() {
// ListIterator it = es.listIterator();
// while(es.size() != 0) {
// while(it.hasNext()) {
// Event e = (Event)it.next();
// System.out.println("Testing " + e);
// if(e.ready()) {
// System.out.println("Running " + e);
// e.action();
// System.out.println(e.description());
// int prevIndex = it.previousIndex();
// // To prevent concurrent modification:
// LinkedList tmp = new LinkedList(es);
// tmp.remove(e);
// es = tmp;
// it = es.listIterator();
// }
// }
// }
// }
public void run() {
int index = 0;
while(es.size() != 0) {
Event e = (Event)es.get(index);
if(e.ready()) {
e.action();
System.out.println(e.description());
es.remove(index);
}
index = (index + 1) % es.size();
}
}
}public class Ex42
extends Controller {
private boolean light = false;
private boolean water = false;
private String thermostat = "Day";
private class LightOn extends Event {
public LightOn(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here to
// physically turn on the light.
light = true;
}
public String description() {
return "Light is on";
}
}
private class LightOff extends Event {
public LightOff(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here to
// physically turn off the light.
light = false;
}
public String description() {
return "Light is off";
}
}
private class WaterOn extends Event {
public WaterOn(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
water = true;
}
public String description() {
return "Greenhouse water is on";
}
}
private class WaterOff extends Event {
public WaterOff(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
water = false;
}
public String description() {
return "Greenhouse water is off";
}
}
private class ThermostatNight extends Event {
public ThermostatNight(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
thermostat = "Night";
}
public String description() {
return "Thermostat on night setting";
}
}
private class ThermostatDay extends Event {
public ThermostatDay(long eventTime) {
super(eventTime);
}
public void action() {
// Put hardware control code here
thermostat = "Day";
}
public String description() {
return "Thermostat on day setting";
}
}
// An example of an action() that inserts a
// new one of itself into the event list:
private int rings;
private class Bell extends Event {
public Bell(long eventTime) {
super(eventTime);
}
public void action() {
// Ring every 2 seconds, 'rings' times:
System.out.println("Bing!");
if(--rings > 0)
addEvent(new Bell(
System.currentTimeMillis() + 200));
}
public String description() {
return "Ring bell";
}
}
static int iterations = 3;
private class Restart extends Event {
public Restart(long eventTime) {
super(eventTime);
}
public void action() {
if(--iterations <= 0) System.exit(0);
long tm = System.currentTimeMillis();
// Instead of hard-wiring, you could parse
// configuration information from a text
// file here:
rings = 5;
addEvent(new ThermostatNight(tm));
addEvent(new LightOn(tm + 100));
addEvent(new LightOff(tm + 200));
addEvent(new WaterOn(tm + 300));
addEvent(new WaterOff(tm + 800));
addEvent(new Bell(tm + 900));
addEvent(new ThermostatDay(tm + 1000));
// Can even add a Restart object!
addEvent(new Restart(tm + 2000));
}
public String description() {
return "Restarting system";
}
}
public static void main(String[] args) {
Ex42 gc =
new Ex42();
long tm = System.currentTimeMillis();
gc.addEvent(gc.new Restart(tm));
gc.run();
}
}













