Java Programming 4 Java Application Building v1 PDF
Java Programming 4 Java Application Building v1 PDF
Even Mo re Swing
Handling Exceptio ns
Finding the Pro blem
Fixing the Pro blem
Try/Catch Clauses
Anticipating Exceptio ns
Making It Right: Dialo g Bo xes
Types o f Exceptio ns
Checked Exceptio ns
Unchecked Exceptio ns
Erro rs
Pro gramming Respo nsibly
Exceptio n Hierarchy
Using Finally in a Try/Catch Blo ck
Thread States
Thread.State
Mo re o n Multi-Threaded Applicatio ns
Design Pattern: Pro ducer/Co nsumer
Using Threads in an Applicatio n
The Pro ducer
The Co nsumer
The Mo nito r
The GUI View
We Lo ve Threads
Real Games
Blackjack
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Application Building
Welco me to the J ava Applicat io n Building series o f Java co urses. This series will fo cus o n develo ping applicatio ns using
the many to o ls available in Java. As in all OST co urses, the emphasis will be o n interactive instructio n.
Course Objectives
When yo u co mplete this co urse, yo u will be able to :
enhance Graphical User Interfaces in Java using views, frames, panels, and Swing.
implement erro r checking, exceptio n handling, and try/catch clauses to minimize bugs.
catch unchecked exceptio ns and prepare fo r pro blems thro ugh graceful degradatio n.
create and manipulate threads fo r co ncurrent pro gramming.
co nnect with databases using the JDBC API, facto ry design patterns, and view co ntro llers.
do cument and tag co de using Javado c and API pages.
In this co urse, yo u will achieve an understanding o f the structure and purpo ses fo r many o f the classes in the Java API. In-depth
experience with user-interfaces, event and exceptio n handling, database co nnectivity, multiple threads and synchro nizatio n will
pro vide yo u with a to o lkit fo r bo th implementing applicatio ns as well as understanding so urce co de o f o thers. Pro grams
designed in the co urse using Java Threads, Client/Server So ckets and Database Co nnectivity pro vide a so lid basis fo r
applicatio n building.
Fro m beginning to end, yo u will learn by do ing yo ur o wn Java pro jects, within o ur Eclipse Learning Sandbo x we affectio nately
call "Ellipse". These pro jects will add to yo ur po rtfo lio and pro vide needed experience. Besides a bro wser and internet
co nnectio n, all so ftware is pro vided o nline by the O'Reilly Scho o l o f Techno lo gy.
Review
In this series, we assume that yo u have a general fo undatio n o f Java and o bject-o riented pro gramming kno wledge, so
basic pro gramming skills wo n't be co vered in this co urse. We'll wo rk no w to gro w and refine yo ur existing Java
pro gramming skills. If yo u are unable to fo llo w the co de that we use fo r illustratio ns and examples in this co urse, we
reco mmend that yo u take OST's first Java series o f co urses to gain tho se basic pro gramming skills; then yo u'll be
able to reap the full benefits o f the materials presented here.
Co de flexibility
Package declaratio n and usage
Separatio n o f classes to mo del the Mo del/View/Co ntro ller (MVC) design pattern
Interfaces
Casting
Declaratio n and use o f inner classes
Preview
In the first new versio n o f o ur applicatio n, we'll bring in Layo ut Manage rs to pro vide a better user interface. Except fo r
the vario us Layo ut Manage rs and Pane ls, we'll also be using familiar co de and techniques. In upco ming lesso ns,
we will learn additio nal techniques that will enable us to :
Create a new java4 _Le sso n1 pro ject (it may help to take a lo o k at the o verview). No w, create a new m ain class in this
pro ject as sho wn:
Type m ain as sho wn in blue :
CODE TO TYPE: Main
// ****************************************************************
// Main.java
//
// Instantiates and starts the SalesReport class
//
// ****************************************************************
package sales1;
This class instantiates and starts o ur applicatio n. There will be erro rs in Main, because we still haven't created the
class that it instantiates.
import java.util.Scanner;
public SalesReport(){
System.out.print("Enter the number of salespersons: ");
this.SALESPEOPLE = scan.nextInt();
this.sales = new int[SALESPEOPLE];
}
Since Sale sRe po rt do es no t extend Apple t , it is no t an Applet, and since Sale sRe po rt do es no t have a m ain()
metho d, Java is no t sure what to do . We created the Main class to instantiate and start this applicatio n, so we sho uld
go to that class to run it.
In Eclipse, if yo u cho o se Run As, but neither J ava Apple t no r J ava Applicat io n appear as o ptio ns,
Note click in the Editor Window. This lets Eclipse kno w that yo u are running the .java file.
Click o n the Main.java class. (Sale sRe po rt is no lo nger unkno wn, because we have defined it no w.)
Save and Run it. The Co nso le o pens and is ready fo r yo u to pro vide input:
Click in the co nso le windo w, type 2, and press Ent e r. Yo u're asked fo r sales numbers fo r salesperso ns 1 and 2--
enter any number fo r each and press Ent e r. Trace the co de fro m the instantiatio n in Main().
The co de wo rks fine, but we can impro ve it. Previo usly, we wro te co de to find the average and minimum sales, and to
allo w the user to set a number as a go al and determine which salespeo ple reached this go al. The new versio ns o f the
Sale sRe po rt applicatio n we'll write in this co urse will call upo n many o f the added po tentials we learned earlier.
OBSERVE:
private int[] sales;
private int salesBar;
private int totalSales;
private double average;
private int minIndex = 0;
private int maxIndex = 0;
SalesUserInterface myUserInterface;
Here we set up variables fo r the m o de l o f o ur Sales Repo rt Applicatio n. We created the sales array sale s to
ho ld each salesperso n's sales figures. The sale sBar variable will ho ld o ur sales go al. The t o t alSale s and
ave rage variables will keep the to tals and average sales. The m inInde x and m axInde x will ho ld the
lo catio ns in the sale s array fo r the minimum sales and maximum sales.
Sale sUse rInt e rf ace m yUse rInt e rf ace is a reference to the GUI fo r the SalesUserInterface applicatio n that
we'll be making in Lesso n 3. We'll use it to send info rmatio n to and fro m the GUI.
No w add the rest o f the setters fo r the private variables. Add the blue co de as sho wn:
CODE TO EDIT: SalesApp
package salesGUI;
Save it.
OBSERVE: Setters
public void setMyUserInterface(SalesUserInterface myGUI)){
myUserInterface = myGUI;
}
The five m e t ho ds abo ve are setters fo r the variables sale s, t o t alSale s, and ave rage . They are chained
to gether; if we call se t Sale s(), it calls se t T o t alSale s(), which in turn calls se t Ave rage (). This ensures that
when we set the sales, the to talSales and average are up to date and co nsistent with the current sales array
data. Finally, we set the salesBar variable with se t Sale Bar(int go al). The goal will be an integer that is set by
the end user when we build o ur User Interface in a future lesso n.
Save it.
OBSERVE
public double getAverage() {
if (sales.length != 0)
return ((double) totalSales / sales.length);
else
return average;
}
If the sales array length (the user-entered number o f salesperso ns) is no t 0 , ge t Ave rage () calculates the
average befo re returning its value; o therwise, it returns the value o f the ave rage variable.
No w create a metho d that calculates the minimum and maximum sales, using co mpariso ns. Add the co de
sho wn in blue :
CODE TO EDIT: SalesApp
package salesGUI;
Save it.
The calculat e MaxMin() sets the index o f the maximum (m axInde x) and minimum (m inInde x) values in the
sales array. We set lo cal variables m inim um and m axim um to the value in the sales[0 ] element as a
starting po int, then lo o p thro ugh the array. If the value in a particular index is greater than the previo us
maximum, we set maximum to that value. If the value in a particular index is no t greater than the previo us
maximum, we check to see if the value is less than the previo us minimum, and if so , we set minimum to the
new value. We also keep track o f the lo catio n o f the indexes that co ntain the current minimum (m inInde x)
and maximum (m axInde x) values in the array.
Okay, no w we'll add a metho d to determine who the to p sales peo ple are, so we can praise them and then
give them even mo re wo rk! Edit yo ur co de as sho wn in blue :
CODE TO EDIT: SalesApp
package salesGUI;
// Loop through the sales array and see who sold more than the sales bar
for (int x = 0; x < sales.length; x++)
{
if (sales[x] > salesBar) {
performance[x] = 1;
}
else if (sales[x] == salesBar) {
performance[x] = 0;
}
else {
performance[x] = -1;
}
}
return performance;
}
}
Save it.
The metho d de t e rm ine T o pSale sPe o ple () will return the to p-perfo rming salespeo ple in the sales array. It
returns an integer array, asso ciated with the sales array. If a salesperso n's perfo rmance is belo w the
salesBar, then we place a -1 in the co rrespo nding slo t o f the integer array. If perfo rmance is equal to the
salesBar, then we place a 0 in that slo t. And if a salesperso n's perfo rmance is abo ve the salesBar, then we
place a +1 in that slo t.
Coming Attractions: T he View
The "View" is exactly that: the View o r GUI used to interact with the Mo del.
Eventually we'll create the Graphical User Interface (GUI) using Swing co mpo nents, so in the next lesso n we'll co ver
so me Swing basics. Using javax.swing package is similar to using java.awt co mpo nents. In fact, Swing co mpo nents
usually inherit fro m the awt co mpo nents:
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Swing: A Very Brief Overview
Acco rding to the freejavaguide.co m page o n Java Swing: Free Java Tuto rials:
Java Swing is a GUI toolkit for Java. Swing is one part of the Java Foundation Classes (JFC). Swing includes graphical
user interface (GUI) widgets such as text boxes, buttons, split-panes, and tables.
Swing widgets provide more sophisticated GUI components than the earlier Abstract Window Toolkit. Since they are
written in pure Java, they run the same on all platforms, unlike the [first] AWT which is tied to the underlying platform's
windowing system. Swing supports pluggable look and feel – not by using the native platform's facilities, but by roughly
emulating them. This means you can get any supported look and feel on any platform. The disadvantage of lightweight
components is possibly slower execution. The advantage is uniform behavior on all platforms.
Please no te, where po ssible, we have updated o ur links to po int to the new Oracle site fo r Java. Oracle
bo ught Sun Micro systems so me time ago . So me o f Oracle's links po int to lo catio ns that no lo nger exist.
We have no co nto l o ver that. We are so rry fo r any inco nvenience. If yo u are directed to the java.sun.co m
Note do main fro m o ur co urse, it is because we co uld no t find a co rrespo nding o racle .co m URL fo r that
particular reso urce. Oracle has indicated that they want to shut do wn java.sun.co m ; ho wever, they have,
at least fo r the time being, delayed that decisio n, partly due to o utcry fro m the Java co mmunity.
import java.awt.*;
import java.awt.event.*;
No w we'll write the small applicatio n in Swing. In the co mments, yo u can see ho w it differs fro m AWT.
In the java4_Lesso n2 pro ject, add the He llo AppSwing class as sho wn:
import javax.swing.*;
Let's take a lo o k at the im po rt in o ur Swing example. The first line impo rts o nly the main Swing package: im po rt
javax.swing.* This is the o nly package that yo ur applicatio n needs. Ho wever, if yo ur applicatio n had any List e ne rs
(fo r user input), yo ur Swing pro gram might have also needed to impo rt the AWT packages java.awt .* and
java.awt .e ve nt .*. These packages are o ften required because Swing co mpo nents use the AWT infrastructure,
including the AWT event mo del as well. They use the same Listeners and Listener API Tables.
Changing Appearance
Even tho ugh the differences in appearance are o ften subtle, yo u'll still want to co ntro l what yo ur GUI's lo o k like. Yo u
can use any o f these fo ur platfo rm types:
The Swing tuto rial has an example o f a mo re decked o ut GUI. It is replicated exactly here so that yo u can see the
co mments and the co pyright no tice as well (yo u do n't need to type the co pyright no tice tho ugh).
In the java4_Lesso n2 pro ject, add a He llo Wo rldSwing class as sho wn:
package compare;
import javax.swing.*;
Save and run it. Yo u might need to resize the windo w. No w, THAT lo o ks different.
Go to the javax.swing.J Fram e class in the API. Lo o k at the se t De f ault Lo o kAndFe e lDe co rat e d() metho d.
Click o n it to see the detailed descriptio n, and read the discussio n o f the Lo o kAndFe e l.
To learn mo re abo ut Lo o kAndFeel fo r J Fram e s, see Ho w to Make Frames (Main Windo ws), Using Swing
Co mpo nents, and also the page o n Pluggable Lo o k and Feel.
In o ur first examples with the AWT and Swing applicatio ns, we did no t use a Runnable interface to access ano ther
thread fro m o ur m ain() metho d. This can lead to race co nditio ns in the class's co nst ruct o rs and/o r init () metho ds.
Because o f these differences between the Swing and the AWT packages, Oracle suggests making J Fram e s fo r
applicatio ns and J Apple t s differently.
Back o n the Ho w to Make Applets page, we have the link, Features Pro vided by JApplet, which sho ws us ho w
to add co mpo nents to the Co ntent Pane. Go ahead and read this who le page to beco me familiar with the
to o ls and co ncepts there.
The Co nt e nt Pane is a Co nt aine r that wo rks similarly to the way do uble-buffering do es when we paint o n
the Graphics area in applets. In the same way that the
se t De f ault Clo se Ope rat io n(Windo wCo nst ant s.DISPOSE_ON_CLOSE) handles the Windo w listener
fo r yo u, the Co nt e nt Pane will take care o f do uble-buffering fo r yo u and help graphics run mo re smo o thly.
Applets aren't much different fro m applicatio ns. The main difference between them is in the ways they are
started and in the way yo u pro duce a GUI fo r an applicatio n. In o rder to have a GUI fo r an applicatio n, yo u
need to instantiate the Frame (o r JFrame).
Let's co mpare the two . Go back to the Ho w to Make Applets page, then to the sectio n Threads in Applets. It
has an example o f an init () metho d that lo o ks a lo t like the m ain() metho d o f their J Fram e applicatio n.
Save and run it (yo u might need to resize the Applet windo w).
Our example JApplet co de sho ws two metho ds: init () and cre at e GUI(). These metho ds are similar to the
applicatio n's m ain() and cre at e AndSho wGUI() metho ds; starting JApplets is very similar to starting
applicatio ns. But the JApplet's init () metho d with its javax.swing.SwingUt ilit ie s.invo ke AndWait () call, is
different fro m the applicatio n's javax.swing.SwingUt ilit ie s.invo ke Lat e r() call.
The invo keLater metho d is no t appro priate fo r so me JApplets because it co uld allo w init () to return befo re
initializatio n is co mplete. This co uld cause applet pro blems that are difficult to debug (such as co nstructo rs
that mistakenly have a return type).
Take a lo o k at the class LabelDemo .java (fro m Ho w to Use Labels), which extends JPanel. m ain() invo kes
cre at e AndSho wGUI(), which instantiates a JFrame, then adds a Labe lDe m o (which is a JPanel), then
gives the frame the Co ntentPane o f this JPanel. LabelDemo 's co nstructo r adds all o f the co mpo nents to the
JPanel.
Here's an example that's a bit mo re co mplex: Ico nDemo App (fro m Ico n Demo ), and an applicatio n. While
we're at it, here's the Table o f Examples fo r a tuto rial o n Swing Co mpo nents.
The Oracle Swing tuto rial includes Creating a GUI with JFC/Swing.
The Swing Seco nd Editio n Bo o k has a link to free versio n o f the first editio n.
O'Reilly Media has published several bo o ks o n Swing including Java Swing, Seco nd Editio n, by Marc Lo y,
Ro bert Eckstein, Dave Wo o d, James Ellio tt, and Brian Co le.
Oracle pro vides Java Lo o k and Feel Design Guidelines.
Our perpetual so urce o f Java kno wledge, the API includes do cumentatio n o n the javax.swing package and
sub-packages.
Oracle has a list o f Training and Tuto rials: Graphical User Interfaces and Printing.
Finally, check o ut the Swing Set Demo . Yo u can test it fro m this web page o r, if yo u do wnlo aded Java and the demo s
o n to yo ur o wn machine, yo u have Swing Set Demo in the java directo ry. Play aro und with this demo , all it takes is a
few mo use clicks!
We still have a lo t mo re Swing co ming up in the next lesso n. See yo u there!
Views
In this lesso n, we'll create a user interface and learn abo ut the Layo ut Manage r. Mo st o f the co nstructs in this co de
were demo nstrated in the previo us Java co urse series, so yo u'll pro bably reco gnize them. But using the Pane l and
the vario us Layo utManagers fo r GUI Frame's Pane ls will be new. To learn mo re abo ut layo ut managers, check o ut the
java.awt.Layo utManager in the API. If yo u want to dig deeper still into layo ut managers, visit the Visual Guide to Layo ut
Managers Tuto rial.
When it runs to co mpletio n, o ur applicatio n will have three separate JPanels (InitPanel, InputPanel, and OutputPanel);
o ne fo r each stage o f the run. In the picture belo w, they are separated by re d lines so yo u can differentiate between
them:
Swing co mpo nents are referred to as "light weight" (as o ppo sed to AWT co mpo nents which are "heavy
weight"), meaning that the co mpo nents use the o perating system to create co mpo nents like Checkbo xes and
Cho ices. Swing co mpo nents are created and drawn by the Swing library rather than relying o n the o perating
system to draw them. This gives Java applicatio ns and applets a unifo rm lo o k and feel acro ss multiple
o perating systems. And when using Swing, the lo o k and feel o f yo ur applicatio ns can be changed by altering
a few lines o f co de.
In the java4_Lesso n1 pro ject, create a new Sale sUse rInt e rf ace class as sho wn:
Go to the Sale sUse rInt e rf ace edito r windo w and edit it as sho wn in blue :
CODE TO TYPE: SalesUserInterface
package salesGUI;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
pack();
setVisible(true);
}
}
Save it. It wo n't run, because we haven't created a Main class yet. We'll do that, but first let's take a clo ser
lo o k at the co de we do have:
OBSERVE: SalesUserInterface
package salesGUI;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
pack();
setVisible(true);
}
}
Next, we set up the variables fo r this applicatio n to use. The app variable is a reference to the Sale sApp
class that we created earlier. The o ther variables are o f type JMenuBar, JMenu, and JMenuOptio n, all o f which
are Swing co mpo nents we'll use fo r o ur menu bar. Again, the "J" is used here to differentiate Swing
co mpo nents fro m AWT co mpo nents.
The co nstructo r fo r this class accepts a Sale sAPP o bject as a parameter. This enables the SalesApp o bject
to make co mputatio ns fro m this GUI.
We call app.se t MyUse rInt e rf ace (t his), which passes the SalesUserInterface o bject to the SaleApp
instance. (This may be a bit co nfusing right no w, because we haven't used this handle yet. Do n't wo rry, we'll
get there. Patience grassho pper.)
Next, we call the JFrame metho d se t Layo ut Manage r(ne w Bo rde rLayo ut ()), in which we create a new
Bo rde rLayo ut ()--we'll use the Bo rderLayo ut manager. Well, we aren't actually using it just yet, but it will be
used to lay o ut the JPanels when we add them. Fo r no w, let's get the windo w up with the File menu and Exit
o ptio n.
In the dark re d co de abo ve, we instantiate a J Me nuBar called m b, and then set the menu bar o n the
SalesUserInterface JFrame with se t J Me nuBar(m b);. Then we add the JMenu "File" to the menu bar, and
add the "Exit" JMenuItem to that.
We add an Act io nList e r to the Exit Menu Item to catch the click event. To do that, we use the ano nymo us
inner class technique. Then we call Syst e m .e xit (0 ); in the implemented interface metho d Actio nPerfo rmed()
to kill the Applicatio n pro cess.
Finally, we call pack(); and se t Visible (t rue ); to sho w the GUI. The metho d pack() is actually inherited fro m
Windo w, and causes the windo w to be set to its preferred size. se t Visible () makes the windo w visible o n the
screen. These two metho ds sho uld always be called when using a JFrame.
Okay, let's make a Main Class and get this applicatio n running!
Start a new Main Class file in the same lo catio n as yo ur Sale sUse rInt e rf ace class. Type the blue co de as
sho wn:
package salesGUI;
package salesGUI;
Here we instantiate a Sale sApp o bject we call ne wApp. Then we instantiate a SalesUserInterface o bject and
pass the ne wApp o bject to it as a parameter. In the SalesUserInterface o bject, we get that ne wApp o bject
and it beco mes app, which will ultimately make calculatio ns fo r us.
No w, add the first JPanel: Init Pane l. We'll add this class as an Inner Class to SalesUserInterface. We do that
fo r two reaso ns:
This class is specific to the SalesUserInterface and we do n't plan to reuse it.
It will make it easier to access aspects o f the SalesUserInterface later in this lesso n.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Yo u'll see the "Enter the Number o f Sales Peo ple" JLabel, an input JTextfield, and a Submit JButto n. Of
co urse, it do esn't do anything just yet.
OBSERVE: InitPanel
package salesGUI;
import java.awt.*;
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
We created a new class called Init Pane l, which e xt e nds J Pane l. We added a JLabel, JTextfield, and
JButton. We used the add() metho d fro m JPanel to add each o f tho se instantiated o bjects to o ur JPanel.
Then we added the variables used in InitPanel to the glo bal sco pe o f SalesUserInterface. Yo u'll see why we
did that later in this lesso n.
OBSERVE
InitPanel specifyNumber = new InitPanel();
add("North", specifyNumber);
Just fo r practice, try changing "No rth" to "East" o r "So uth" and running the pro gram again to o bserve the effect
it has.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
Save it. We can't view it o n o ur SalesUserInterface yet, because we haven't added this InputPanel to o ur
SalesUserInterface JFrame. Let's do that no w!
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Save this SalesUserInterface and run the Main. Yo u'll see the pro mpt Give value s f o r e ach
sale spe rso n. That's o ur t o pPane l!
So far, we've added the to pPanel, a JPanel, into InputPanel. We still need to make the middle panel to do all
o f the wo rk in InputPanel. We'll add so me co de to prepare o ur InputPanel to accept the number o f sales
peo ple entered fro m the InitPanel as well.
CODE TO EDIT: InputPanel
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
Save it. We've added lo ts o f new co de here. Let's just get it wo rking so we can actually see it in actio n first,
then we'll go o ver it in detail.
In o rder fo r the butto n in the InitPanel to wo rk, we'll create a new private inner class in SalesUserInterface.java
that will serve as the butto n's listener. Let's call it Num Pe o ple Sale sList e ne r.
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Save it and run Main.java. When yo ur applicatio n appears, type in a number and press Subm it . Yo u'll see
the input fields fo r yo ur salespeo ple.
No w let's go o ver this, bit by bit. First we'll lo o k o ver the co de we added to Input Pane l:
OBSERVE: InputPanel
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
add("North", topPanel);
prompt = new JLabel("Give values for each salesperson:");
topPanel.add(prompt);
The co de in blue is already familiar, so we'll turn o ur attentio n to the new stuff. When we call this
Input Pane l() co nstructo r in SalesUserInterface, we will supply the parameters num Pe o ple and gridX.
Tho se parameters are used in the GridLayo ut (ro ws, co ls) co nstructo r (go ahead and lo o k up GridLayo ut
in the API). num Pe o ple is the number o f ro ws that o ur grid will have and gridX is the to tal number o f
co lum ns o ur grid will have.
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
pack();
setVisible(true);
}
We've added the actio nlistener Num Sale sPe o ple List e ne r to the JButto n jbNum Pe o ple . And we've
added the Num Sale sPe o ple List e ne r class that implements Act io nList e ne r. In the implemented
actio nPerfo rmed() metho d, we've added an if statement that checks to see if an inputPanel exists already. If
we change the number o f sales peo ple, then we rebuild that existing inputPanel. We re m o ve (input Pane l)
and create a new SalesApp to pass to the new InputPanel. We retrieve the num Pe o ple using the ge t T e xt ()
metho d in peo pleField (a JTextField o bject). No w, when we create an instance o f InputPanel, we pass it
num Pe o ple (the number o f ro ws we want) and 2 (the number o f co lumns we want).
Next, we add the inputPanel, po sitio n it in the " Ce nt e r" , and then call Sale sUse rInt e rf ace .t his.validat e ().
We call JFrame's validat e () metho d when we rebuild and re-add the inputPanel co mpo nent. In o ur co de, we
called pack() befo re we called se t Visible (). Once a panel is visible o n a JFrame, we call validat e () to get
o ur applicatio n to redraw. Because Num Sale sPe o ple List e ne r is an inner class, we can use
Sale sUse rInt e rf ace .t his to access the JFrame's validat e () metho d.
So far, so go o d. No w let's turn o ur InputPanel into a listener and make o ur do ne JButto n grab the numbers
the user enters and send them to o ur SalesApp.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
Save and run it (run the Main.java). No w type in a number (we used 4 ) and when the input panel co mes up,
enter numbers into that as well; include the sales go al. Then click All Se t as sho wn:
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
The act io nPe rf o rm e d() metho d o f this InputPanel class determines whether the so urce o f the e ve nt is a
J But t o n. If it is, we use a f o r lo o p to go thro ugh the number o f peo ple and lo o k in each o f the TextFields
defined by the jt f Sale s[] array. We use ge t T e xt () to get the text the user typed in and we use
Int e ge r.parse Int () to co nvert that text into an integer. Then we call the se t Sale s() metho d o f the SalesApp
o bject. We determine the value o f the go al and set the salesBar to that value.
Okay, nice wo rk! Take a break, pat yo urself o n the back, and bask in the glo ry o f yo ur acco mplishments so far! We'll do
the Output Panel fo r this user interface in the next lesso n. See yo u there!
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Graphical User Interfaces, continued
We can take advantage o f JLabel's ability to display HTML to fo rmat the o utput.
Using the same java4_Lesso n1 pro ject we used in the previo us lesso n, create an Out put Pane l class as sho wn:
The o utput panel we're go ing to build will actually co nsist o f two panels: o ne in the East area and o ne in the We st
area o f the layo ut. They will be used to display the o utput o f the applicatio n to the user.
package salesGUI;
import javax.swing.*;
import java.text.DecimalFormat;
JLabel jlSalesOutput;
JPanel leftPanel, rightPanel;
JLabel jlSalesBar;
JTextField jtfSalesBar;
JButton done;
SalesApp app;
int salesBar;
int [] sales;
Next we'll add metho ds to fo rmat and display the results. The writ e Out put () metho d uses co ncatenatio n (+=) to
build a +=t xt Out put String that co ntains all o f o ur o utput. We are using JLabel's ability to display HTML co ntent, and
displaying the data as we wo uld in an HTML do cument.
Note HTML break tags (<br>) are used fo r new lines in the t xt Out put St rings fo r the o utput JLabel.
CODE TO EDIT: OutputPanel
package salesGUI;
import java.awt.Panel;
import javax.swing.*;
import java.text.DecimalFormat;
JLabel jlSalesOutput;
Panel leftPanel, rightPanel;
JLabel jlSalesBar;
JTextField jtfSalesBar;
JButton done;
SalesApp app;
int salesBar;
int [] sales;
jlSalesOutput.setText(txtOutput);
validate();
repaint();
}
Here we use JLabel's ability to display HTML to display the sales to tals o f each salesperso n, and which were greater
than, lo wer than, o r equal to the sales bar.
Fo r mo re info rmatio n o n the javax.swing.JLabel, lo o k at the API, as well as Ho w to Use Labels in the Java Tuto rial
o n Using Swing Components.
Click o n Input Pane l.java. If yo u haven't do ne so , save it no w--any erro rs yo u have sho uld go away.
Click o n Sale sUse rInt e rf ace .java; it sho uld be free o f erro rs as well. No w let's add the Results o ptio n and
OutputPanel. Edit SalesUserInterface as sho wn in blue belo w:
CODE TO EDIT: SalesUserInterface
package salesGUI;
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Save it and run the Main class. Enter a number o f salespeo ple, their sales numbers and the go al, and then click All
Se t . Select Opt io ns | Re sult s, and yo u sho uld see so mething like this:
Copyright © 1998-2014 O'Reilly Media, Inc.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Error Checking and Exception Handling
Crashes
In the java4 _Le sso n1 pro ject, go to the sale sGUI package, o pen the Main.java class, and Run it. No w
give it these values:
In the applicatio n that's currently running, select Opt io ns | Re sult s. Yo u'll no tice even mo re re d in the
Co nso le:
Again, the user still do esn't see any o f this; they just kno w that the lo usy pro gram isn't wo rking!
Clo se the running applicatio n using the menu item File | Exit .
If an applicatio n is o pen and running, it will co ntinue to use the same .class (old co mpiled co de) that it was
o pened with, even if yo u make changes to the applicatio n and save it again. If yo u edit, resave, and rerun an
applicatio n, but still have the o lder (erro neo us) co de running, it can cause frustratio n. Always make sure to
clo se an applicatio n pro perly, befo re editing and running a new versio n.
Go to the java.lang package. Scro ll do wn to the Exce pt io n Sum m ary, then to the Exce pt io n class.
There are quite a few Dire ct Kno wn Subclasse s (we edited mo st o f them o ut in the image belo w tho ugh,
because the list was so lo ng):
And that's just the beginning. Go back to java.lang's Exce pt io n Sum m ary. Scro ll do wn to
Runt im e Exce pt io n (just o ne o f the Direct Kno wn Subclasses o f Exce pt io n). Click o n
Runt im e Exce pt io n and check o ut all o f its Direct Kno wn Subclasses.
Pro grams and users may behave in an infinite number o f unexpected ways. When the unexpected happens,
o ur co de (with the help o f Java) will t hro w an Exce pt io n (the java.lang.Exce pt io n class extends (o r
inherits fro m) the class java.lang.T hro wable ).
So , what's an exceptio n? Oracle's Java tuto rial says, "An exception is an event, which o ccurs during the
executio n o f a pro gram, that disrupts the no rmal flo w o f the pro gram's instructio ns." If we do n't want o ur
pro grams to crash and cause o ur users to beco me frustrated, then we need to plan fo r all po tential
Exce pt io ns.
Handling Exceptions
Finding the Problem
When Java thro ws an Exce pt io n, it tells us which type o f Exce pt io n it was and where it o ccurred.
In o ur first exceptio n, Java pro vided a lo ng debugging trace o f its lo catio n. Usually, the last co uple o f lines in a
trace are the mo st impo rtant fo r pro grammers. Fo r example, when the user entered the value o f 3.4 in the
Input Pane l, we saw:
We can tell fro m the Exce pt io n that an input string o f 3.4 caused a java.lang.Num be rFo rm at Exce pt io n.
We can also determine that the exceptio n o ccurred in the Input Pane l.java class at line number 7 6 .
Open the InputPanel.java class and display the line numbers (o n the left side bar, right -click and cho o se
Sho w Line Num be rs). Go to line 7 6 . Yo u sho uld see sale s[x] =
Int e ge r.parse Int (jt f Sale s[x].ge t T e xt ());.
Do yo u reco gnize the pro blem? The sale s[ ] array is declared as Int e ge r. We to ld Java to expect an int , but
the user gave us a decimal. A decimal is no t an int ; it's a do uble o r a f lo at . So , ho w do we remedy this?
T ry/Catch Clauses
Anticipating Exceptions
If we want to catch exceptio ns, we need to kno w when they might o ccur. So metimes co de pro vided in the API
indicates that it will thro w vario us types o f exceptio ns. We'll address tho se exceptio ns in greater detail later,
but fo r no w, let's get a handle o n the general idea. If we had researched the metho ds we were using carefully
in the API befo rehand, we co uld have anticipated po tential pro blems befo re writing the co de.
We co uld have anticipated that a user might enter a decimal number rather than an integer. Pro grammers
need to be ready fo r all kinds o f po tentially unexpected situatio ns.
So , ho w can we be prepared? Well, if the user behaves as we wo uld like them to , the co de wo rks great. But if
the user do esn't, we need to cat ch the Exce pt io n. If a m e t ho d thro ws an Exce pt io n, then we sho uld
instruct o ur co de to t ry that metho d's piece o f co de.
If o ur pro grams do no t catch exceptio ns, then Java is fo rced to t hro w them farther. Java will keep thro wing
exceptio ns until so mething catches it, o r until it gets to the "to p o f the stack" (mo re o n this in a later lesso n). At
that po int, if an exceptio n has no t been caught, it will cause erro rs in the co nso le.
In the Input Pane l class, where the exceptio n o ccurred (aro und line 76 ), edit the act io nPe rf o rm e d()
metho d as sho wn in blue :
CODE TO EDIT: InputPanel
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
this.setLayout(new BorderLayout());
topPanel = new JPanel();
topPanel.setLayout(new FlowLayout());
middlePanel = new JPanel(new GridLayout(numPeople, gridX));
bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout());
leftPanel = new JPanel();
rightPanel = new JPanel();
add("North", topPanel);
add("Center", middlePanel);
add("South", bottomPanel);
add("East", rightPanel);
add("West", leftPanel);
JOptionPane.showMessageDialog(this, messageLine1+message
Line2+messageLine3,"Input Error", JOptionPane.ERROR_MESSAGE);
sales[x]= (int)Double.parseDouble(jtfSales[x].getText())
;
jtfSales[x].setText(Integer.toString(sales[x]));
}
}
app.setSales(sales);
goal = Integer.parseInt(jtfSalesBar.getText()); // so don't hav
e to be sure they hit enter
app.setSalesBar(goal);
}
}
}
}
Run the Main class. Enter a decimal number fo r o ne o f the values and click All Se t .
That info rmatio n helps the user and the pro grammer. We can pro vide additio nal St rings o f info rmatio n fo r
the user in the dialo g bo xes to o . Or we can just fix things witho ut no tifying them at all. Cho o sing ho w to
respo nd depends o n the applicatio n and the significance o f each piece o f data.
There are several o ther types o f dialo g bo x o ptio ns; let's take a lo o k at ano ther o ne. Replace the cat ch
clause inside the f o r lo o p as sho wn in blue :
CODE TO EDIT: InputPanel
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
this.setLayout(new BorderLayout());
topPanel = new JPanel();
topPanel.setLayout(new FlowLayout());
middlePanel = new JPanel(new GridLayout(numPeople, gridX));
bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout());
leftPanel = new JPanel();
rightPanel = new JPanel();
add("North", topPanel);
add("Center", middlePanel);
add("South", bottomPanel);
add("East", rightPanel);
add("West", leftPanel);
app.setSales(sales);
goal = Integer.parseInt(jtfSalesBar.getText());
app.setSalesBar(goal);
}
}
}
}
Run the Main class. Enter a decimal number fo r o ne o f the values and click All Se t :
Fo r mo re o n dialo g bo xes, see the Oracle tuto rial o n Ho w to Make Dialo gs.
T ypes of Exceptions
The Java pro gramming language uses e xce pt io ns to handle erro rs and o ther exceptio nal events. Exce pt io ns are
unusual co nditio ns that a well-written applicatio n will anticipate and remedy. Java pro vides two main types o f
exceptio ns: checked and unchecked. Che cke d e xce pt io ns can be checked at co mpile time. All exceptio ns are
checked exceptio ns, except fo r tho se that are instances o f the Erro r and Runt im e Exce pt io n classes and their
subclasses.
Checked Exceptions
If a metho d has a checked exceptio n, Java info rms the pro grammer using the metho d. The class that uses
the metho d will no t co mpile (o r Eclipse will repo rt erro rs) and the pro grammer will no t be able to run the
pro gram until the exceptio n in the co de has been handled; the pro grammer is f o rce d to handle that
exceptio n.
In additio n, pro grammers can o ften anticipate pro blems that co uld o ccur in a metho d they have written. The
autho r o f the metho d is o bliged to warn o ther pro grammers who may use it, that such pro blems are a
po ssibility. A go o d pro grammer will handle tho se pro blems within the applicatio n. Pro grammers must
co nsider o ther pro grammers, as well as users when writing metho ds and applicatio ns:
A metho d's autho r needs to make sure that o ther programmers who use the metho d do n't
experience surprise failures.
An applicatio n's autho r needs to make sure that the users o f their applicatio n do n't have surprise
failures.
Of co urse, the autho r o f a metho d can't always anticipate which enviro nment a pro grammer will use, o r the
type o f applicatio n a pro grammer may want to create. Because o f such variables, the metho d autho r can't
predict ho w each applicatio n might handle a pro blem. The best the metho d autho r can do is to info rm users
o f the metho d that a pro blem might exist, and that using the metho d might thro w an Exce pt io n. Then the
metho d's autho r sho uld include t hro ws in the metho d definitio n.
Unchecked Exceptions
Erro rs, Runtime Exceptio ns, and their subclasses are unche cke d e xce pt io ns. The co de we wro te to
retrieve user-entered sales values had the po tential to present the pro blems asso ciated with unche cke d
e xce pt io ns. Its specificatio n in the API clearly stated that it thro ws a Num be rFo rm at Exce pt io n. But we
were still able to co mpile and run the co de initially witho ut a try/catch clause. Why?
OR
Open Input Pane l.java in the Edito r. Go to the line that specifies the NumberFo rmatExceptio n in the catch
clause. Highlight it. Right-click and cho o se Ope n T ype Hie rarchy:
A hierarchy windo w o pens in the left panel (there are actually two panels there):
Num be rFo rm at Exce pt io n is a subclass o f Runt im e Exce pt io n. All exceptio ns are checked exceptio ns,
e xce pt fo r tho se that are instances o f the Erro r and Runt im e Exce pt io n classes, and their subclasses.
So metimes exceptio ns arise when a pro gram is run, depending o n which variables are present at that
particular time. These are called Runtime Exceptions.
The exceptio ns that we have lo o ked at in this lesso n have been unchecked (Runtime Exceptions), because
the co mpiler canno t anticipate what a user will enter. So , even tho ugh the metho d
java.lang.Int e ge r.parse Int (St ring s) states that it might thro w an exceptio n, Java allo wed the co de to
co mpile. As the Oracle Tuto rial states:
Runtime exceptions represent problems that are the result of a programming problem, and as such, the API
client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems
include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object
through a null reference; and indexing exceptions, such as attempting to access an array element through an
index that is too large or too small.
Because such exceptio ns can happen anywhere in a pro gram, and o ften runtime exceptio ns are no t easy to
spo t, the co mpiler do esn't require pro grammers to catch runtime exceptio ns. But so o ner o r later, exceptio ns
will make their presence kno wn. The Java Virtual Machine is merciless and wo n't hesitate to bro adcast the
re d details o f o ur uncaught exceptio ns all o ver the co nso le.
T he Other Problem
When we ran o ur applicatio n at the beginning o f this lesso n, we saw two exceptio ns:
When we fixed the first exceptio n (the Num be rFo rm at Exce pt io n) with the t ry/cat ch clause, the seco nd exceptio n
disappeared.
So , we're go ing to do what mo st sensible beginning pro grammers do : fo rget abo ut it. But remember to expect the
unexpected. That pro blem will po p up again.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Unchecked Exceptions: Keeping Our Applications
Running
About Exceptions
We kno w that all exceptio ns are checked exceptio ns, aside fro m tho se identified by Erro r and Runt im e Exce pt io n
and their subclasses. If co de includes metho ds with checked exceptio ns, that co de wo n't co mpile until the exceptio ns
are handled thro ugh t ry/cat ch clauses. A metho d that causes a checked exceptio n has to specify that it throws the
exceptio n.
In the previo us lesso n, we were able to co mpile and run o ur applicatio n co de, so we kno w o ur co de didn't co ntain
metho ds with checked exceptio ns. Do es that mean o ur co de is free fro m erro rs and exceptio ns? Sadly no . As we saw
in the last lesso n, o ur co de co ntained o ne unchecked exceptio n that had to be fixed. Unchecked exceptio ns usually
o ccur because a user do es so mething unexpected at runtime. In this lesso n, we'll lo o k at co mmo n subclasses o f
Runt im e Exce pt io ns.
NullPo interExceptio n
ArithmeticExceptio n
Array Out o f Bo unds
NullPointerException
A null po inter exceptio n o ccurs when yo ur co de tries to access an instance o f an o bject that has no t been
pro perly instantiated. Declaring a variable to be o f a certain type is no t the same as instantiating it. If yo ur
variable is no t o f a primitive data type, it has been declared as a type o f Obje ct (remember that every o bject
inherits fro m Obje ct and is a subclass). If such an o bject has no t been instantiated, then it do esn't po int to
anything in memo ry, so it's a null pointer.
Null po inter pro blems may o ccur when a user calls a metho d inco rrectly. If an argument is null, the metho d
might thro w a NullPo interExceptio n, which is an unchecked exceptio n. Let's lo o k at such an exceptio n in the
first o f five examples we'll use in this lesso n:
Example 1
In the java4_Lesso n1 pro ject, SalesGUI package, edit Main.java as sho wn in blue and re d:
Edit Main.java as sho wn (we're reverting to the previo us versio n, so yo u can use the Undo key co mbinatio n
[Ct rl+Z ] to undo the typing yo u did earlier):
package salesGUI;
Save and run it again to make sure that all's well. Make sure to exit the running applicatio n afterward, so it's
ready fo r the next test.
Example 2
Open the Input Pane l.java class. In the co nstructo r, co mment o ut the line where we instantiate the sale s
array, as sho wn in re d:
CODE TO EDIT: InputPanel
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
this.setLayout(new BorderLayout());
topPanel = new JPanel();
topPanel.setLayout(new FlowLayout());
middlePanel = new JPanel(new GridLayout(numPeople, gridX));
bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout());
leftPanel = new JPanel();
rightPanel = new JPanel();
add("North", topPanel);
add("Center", middlePanel);
add("South", bottomPanel);
add("East", rightPanel);
add("West", leftPanel);
Save it.
Run the Main.java class. Enter a value fo r the number o f SalesPeo ple and click Subm it to o pen the
InputPanel. Enter a value fo r a particular Salesperso n, then click All Se t .
At o r near line 78 in the InputPanel class is the line sale s[x] = Int e ge r.parse Int (jt f Sale s[x].ge t T e xt ());
(yo ur line numbers may vary slightly, depending o n ho w yo u co ded yo ur dialo g bo x.) The erro r message
appears because we co mmented o ut the instantiatio n o f the sale s [ ] array, so it's no t there to have elements
added into it. New pro grammers o ften think that because they declared the array, it exists: int [] sale s; (at o r
near line 16 in Input Pane l). When yo u declare a variable as an instance variable and it is an Object, Java
gives it the default value o f null. So in the co nstructo r, yo u need the line sale s = ne w int [num Pe o ple ]; to
allo w yo ur variable a no n-null value and size.
Clo se this applicatio n instance using File | Exit , unco mment (in o ther wo rds, remo ve the // fro m) the line yo u
co mmented o ut in Input Pane l.java. Save it, and run it again fro m Main to make sure it wo rks. Then, exit the
applicatio n again, using File | Exit .
Example 3
Here's ano ther po tential snag in o ur current applicatio n:
Run the Main.java class and enter values fo r Sales Peo ple and fo r the Sales Go al, but do not click All
Se t . Select Opt io ns | Re sult s in the menu. Take a lo o k at the Co nso le:
Yo ur line numbers may be slightly different. Do es this lo o k familiar? It's the exceptio n we didn't fix in the
previo us lesso ns.
We'll trace this erro r fro m the bo tto m up:
OBSERVE
at salesGUI.SalesUserInterface$3.actionPerformed(SalesUserInterface.java:48)
at salesGUI.OutputPanel.writeOutput(OutputPanel.java:33)
at salesGUI.SalesApp.calculateMinMax( SalesApp.java:70)
Sale sUse rInt e rf ace .java:4 8 is re sult s.writ e Out put ();} } );. re sult s is an instance o f Out put Pane l. We
are calling its metho d, writ e Out put ().
Out put Pane l.java:33 is the first line in that metho d. There is a call to app.calculat e MinMax();. app is an
instance o f Sale sApp; we are calling its metho d calculat e MinMax().
Sale sApp.java:7 0 is the first line in that metho d. We see int m inim um = sale s[0 ];--so , why the null
po inter exceptio n? Because we do n't have a sale s[0 ]. The user hasn't clicked Se t All, so the sale s [] array
never received its values, and so sale s[0 ] do esn't exist.
There are vario us ways to fix these pro blems. We'll illustrate just o ne. All o f the menu items were made in the
Sale sUse rInt e rf ace class, so let's lo o k there to find o ut ho w to fix it.
Open the Sale sUse rInt e rf ace .java class. See the co nstructo r, where the Results MenuItem is added at
m 1.add(t = ne w Me nuIt e m (" Re sult s" ));. Check o ut the Act io nList e ne r and its requirements.
The Me nuIt e m requires the array set in o rder to perfo rm the metho ds described in its Act io nList e ne r.
Here are so me po ssible remedies:
Set a flag to indicate whether the array has been set and if no t, set it.
Ask the user to click the AllSe t butto n.
Set everything to zero s so we start with a kno wn quantity.
Make sure that it is set by do ing it o urselves again.
Fo r this example, let's set all o f the values to whatever is currently in the J T e xt Fie lds. To do that we'll need
to check the inputs again and then set the array. Also , we'll need ano ther metho d that do es almo st the same
thing as act io nPe rf o rm e d() in Input Pane l. To pro mo te mo dularity o f co de, edit Input Pane l. There are
two majo r changes: act io nPe rf o rm e d() is edited and much o f its co ntents go into a new metho d named
se t AllInput s():
CODE TO EDIT: InputPanel
package salesGUI;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
this.setLayout(new BorderLayout());
topPanel = new JPanel();
topPanel.setLayout(new FlowLayout());
middlePanel = new JPanel(new GridLayout(numPeople, gridX));
bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout());
leftPanel = new JPanel();
rightPanel = new JPanel();
add("North", topPanel);
add("Center", middlePanel);
add("South", bottomPanel);
add("East", rightPanel);
add("West", leftPanel);
JOptionPane.showMessageDialog(this, messageLine1+messageLine2+me
ssageLine3,"Input Error", JOptionPane.ERROR_MESSAGE);
sales[x]= (int)Double.parseDouble(jtfSales[x].getText());
jtfSales[x].setText(Integer.toString(sales[x]));
}
}
app.setSales(sales);
goal = Integer.parseInt(jtfSalesBar.getText()); // so don't have to be
sure they hit enter
app.setSalesBar(goal);
}
}
Save it and run Main.java. Once yo u've co nfirmed that it still wo rks co rrectly, fix the menu cho ices. Edit
Sale sUse rInt e rf ace as sho wn in blue :
CODE TO EDIT: SalesUserInterface
package salesGUI;
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Save it and Run Main.java. Enter the values, but do no t click All Se t . Select Opt io ns | Re sult s fro m the
menu.
Example 4
Be sure yo ur co nstructo rs do not have a return type. If a metho d has a return type, then it is no t a co nstructo r.
Co nstructo rs do no t have return types; by default they return an instance o f themselves.
In so me cases, yo u may think yo u've called a co nstructo r to create an instance o f so mething, but yo u really
haven't. In this next example, o ur co de wo n't give us a NullPo int e rExce pt io n, because it never creates an
instance.
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
m1.add(t=new JMenuItem("Results"));
t.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
inputPanel.setAllInputs(); // added method call to make sure al
l is set
if (processed)
{
remove(results);
}
results = new OutputPanel(app);
add("South", results);
processed = true;
results.writeOutput();
}
});
Save and run the applicatio n fro m Main. Check the Co nso le to make sure that bo th print ln co mments
appear. Make sure that the rest o f the applicatio n wo rks as expected. No w, give the Sale sUse rInt e rf ace
class's constructor (fo und aro und line 21) a vo id return type. Add vo id to the Sale sUse rInt e rf ace ()
co nstructo r as sho wn:
CODE TO EDIT: SalesUserInterface
package salesGUI;
java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
m1.add(t=new JMenuItem("Results"));
t.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
inputPanel.setAllInputs(); // added method call to make sure al
l is set
if (processed)
{
remove(results);
}
results = new OutputPanel(app);
add("South", results);
processed = true;
results.writeOutput();
}
});
Save bo th classes, and run the Main class. No thing o pens and we see this in the co nso le:
We did no t get the Syst e m .o ut .print ln Did I ge t m ade ? fro m o ur Sale sUse rInt e rf ace co nstructo r. And
we didn't get a NullPo interExceptio n until the line after the instantiatio n in Main. The line o f co de intended to
make an instance fo r Sale sUse rInt e rf ace ran, but no thing happened. Why?
Because vo id was given as a return type, the Sale sUse rInt e rf ace class didn't really have a co nstructo r, so
Java just let the class inherit the co nstructo r fro m its supe r. The line Sale sUse rInt e rf ace appFram e = ne w
Sale sUse rInt e rf ace (); ran as expected, but its Co nstructo r was o nly run fro m J Fram e . As a result o f
inheritance, we did no t get a NullPo interExceptio n--yet. We called access to the applicatio n in the Main, but it
should have been called in the Co nstructo r. Since Java never made the instance in the pro per Co nstructo r,
mo st o f the variables we tho ught were set weren't.
This is a difficult erro r to find, so make sure yo u never give a co nstructo r declaratio n a return
Note type.
Example 5
Edit Sale sApp as sho wn in blue and re d:
CODE TO EDIT: SalesApp
package salesGUI;
Can yo u see why there's a null po inter? Yo u do n't have a sale s[] array instantiated yet.
Division By Zero
We'll keep wo rking with the last example to explo re ano ther subclass (java.lang.Arit hm e t icExce pt io n) o f
Runt im e Exce pt io n.
It's difficult fo r the co mpiler to catch these kinds o f exceptio ns befo re runtime. When the co mpiler scans the
co de fo r pro per syntax, it do esn't kno w in advance whether a value fo r num Sale sPe o ple has been set. The
co mpiler wo n't kno w whether the value is 0 at the time o f co mpilatio n.
Co de to Edit: Main
package salesGUI;
Yo u can go o ut o f bo unds pretty easily using f o r lo o ps. Take a lo o k. Create a new class as sho wn:
Type Sale sPe o ple as sho wn in blue :
package salesGUI;
salesPeople[0] = "John";
salesPeople[1] = "Paul";
salesPeople[2] = "George";
salesPeople[3] = "Ringo";
The attribute le ngt h o f an array is equal to the number o f elements in the array, but the indices start at 0, so
the last index is le ngt h - 1. If we try to lo o p to the value o f sale s[le ngt h], we will get a
java.lang.ArrayInde xOut Of Bo undsExce pt io n.
OBSERVE: Main
package sales1;
Because we have included if (args.le ngt h > 0 ), the user can enter arguments either at the co mmand line o r
via a GUI pro mpt. In an earlier versio n o f this Main.java class, we tried to determine whether the user had
entered an argument at the co mmand line by using the co nditio nal statement: if (args[0 ] != null). This
co nditio nal statement actually lo o ks fo r args[0 ], but might no t find an args array at all. In that case, args[0 ]
wo uld already be o ut o f bo unds. Let's try it again. Edit the co nditio nal statement as sho wn in blue :
CODE TO EDIT: Main
package sales1;
Save and run it. Yo u'll see a message in the Co nso le: Exce pt io n in t hre ad " m ain"
java.lang.ArrayInde xOut Of Bo undsExce pt io n: 0 .
It is generally time-co nsuming and inefficient fo r Java to use t ry and cat ch blo cks when an appro priate if
statement wo rks well eno ugh. But let's try it anyway just to illustrate the idea o f catching an
ArrayInde xOut Of Bo undsExce pt io n. Edit the Main in sales1 as sho wn in blue belo w:
try
{
int argIn = Integer.parseInt(args[0]); // if no args[0],
will throw ArrayIndexOutOfBoundsException
SalesReport mySalesInfo = new SalesReport(argIn);
mySalesInfo.testMe();
}
catch (ArrayIndexOutOfBoundsException exception)
{
SalesReport mySalesInfo = new SalesReport();
mySalesInfo.testMe();
}
}
}
Because try/catch clauses are mo re labo r intensive (fo r Java and fo r yo u) than co nditio nal
T ip statements, exceptio n handling sho uld be just that: an exception to the no rm.
Errors
Erro rs are co nditio ns that happen outside o f the applicatio n; fo r example, Out Of Me m o ryErro r. They are usually the
result o f a majo r pro gramming mistake. Fo r example, a recursive pro gram (a pro gram with a metho d that calls itself)
might no t have a sto p statement, which means an infinite lo o p wo uld be created. This co uld then generate a
St ackOve rf lo wErro r.
Save and run it. This is what yo u don't want yo ur custo mers to see!
Unfo rtunately, Erro rs can also o ccur when we do distributed co mputing--that is, when we go o utside o f the
enviro nment o f o ur o wn machine. When a dynamic linking failure o r o ther hard failure (that is, a failure that needs to be
fixed by a pro grammer) o ccurs in the Java virtual machine, the virtual machine thro ws an Erro r. Acco rding to the Oracle
Tuto rial's sectio n o n Erro rs in The Catch o r Specify Requirement:
"The seco nd kind o f exceptio n is the error. These are exceptio nal co nditio ns that are external to the applicatio n, and
that the applicatio n usually canno t anticipate o r reco ver fro m. Fo r example, suppo se that an applicatio n successfully
o pens a file fo r input, but is unable to read the file because o f a hardware o r system malfunctio n. The unsuccessful
read will thro w java.io .IOErro r. An applicatio n might cho o se to catch this exceptio n, in o rder to no tify the user o f the
pro blem — but it also might make sense fo r the pro gram to print a stack trace and exit.
Erro rs are not subject to the Catch o r Specify Requirement. Erro rs are tho se exceptio ns indicated by Erro r and its
subclasses."
We've already seen that the API is a valuable so urce o f Interface, Class, and Exceptio n info rmatio n; no w we'll see ho w
it helps us tackle Erro rs.
Go to the java.lang package in the API. Scro ll do wn to the Erro r Sum m ary. Read abo ut a few o f them. Bo th
Exce pt io ns and Erro rs inherit fro m the class T hro wable ...interesting.
Simple pro grams typically do no t catch o r thro w Erro rs, but checked exceptio ns are subject to the Cat ch o r Spe cif y
Re quire m e nt . We'll discuss that requirement in detail in the next lesso n.
Programming Responsibly
In this lesso n, we've seen examples o f subclasses o f runtime exceptio ns and ho w to prevent them by careful co ding.
Since pro grammers share co de with o ne ano ther so o ften, that's pretty impo rtant.
Altho ugh Java requires that metho ds catch o r specify checked exceptio ns, metho ds that we write do no t have to catch
o r specify unchecked exceptio ns (such as runtime exceptio ns). And because catching o r specifying an exceptio n
requires mo re wo rk, pro grammers are o ccasio nally tempted to write co de that thro ws o nly runtime exceptio ns and
therefo re do esn't have to catch o r specify them. This is exception abuse, and is no t reco mmended. Fo r mo re
info rmatio n, see the Oracle Tuto rial Unchecked Exceptio ns - The Co ntro versy.
The mo re yo u check yo ur co de to prevent unchecked exceptio ns fro m o ccurring at runtime, the better fo r all co ncerned.
Do n't make Duke angry.
Copyright © 1998-2014 O'Reilly Media, Inc.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Checked Exceptions: Catching Problems
Degrading Gracefully
In this lesso n, we'll fo cus o n checked exceptions. A well-written applicatio n will anticipate and pro vide mechanisms fo r
reco very fro m these exceptio nal co nditio ns. We want yo u to understand exactly what's happening when an Exce pt io n
is thro wn. We'll illustrate that pro cess so yo u'll be co nfident using, and ultimately defining yo ur o wn checked
exceptio ns.
I/O Exceptions
Other than Runt im e Exce pt io n and its subclasses, the mo st co mmo n exceptio ns o ccur when attempting to access
files that are either no nexistent o r inaccessible. The next co urse will discuss Java's classes fo r input and o utput (I/O) in
mo re explciit detail, but fo r no w, we'll use an less co mplicated example that reads a file to demo nstrate the use o f
checked exceptio ns in the java.io package.
Create a new java4 _Le sso n7 pro ject. If yo u're given the o ptio n to Ope n Asso ciat e d Pe rspe ct ive , click No . In this
new pro ject, create a File Fe t che r class as sho wn:
package exceptionTesting;
import java.io.FileReader;
import java.io.BufferedReader;
Save and run it anyway. Even tho ugh Java co mplains abo ut Erro rs, click Pro ce e d.
We have Unre so lve d co m pilat io n pro ble m s. (Also , since o ur pro gram co uld no t co mpile, it threw a
java.lang.Erro r):
On the first line o f co de with an erro r, we invo ke the File Re ade r co nstructo r, so let's go to that part o f the API to find
o ut mo re.
Go to the java.io package. Scro ll do wn to the File Re ade r class in the Class Sum m ary. Lo o k at its co nstructo r
File Re ade r(File f ile ):
In the Edito r, o n the next line with an erro r, we are calling the in.re adLine () metho d. in is an instance o f
Buf f e re dRe ade r, so let's lo o k at its re adLine () metho d.
Go back to the java.io package. Scro ll do wn to the Buf f e re dRe ade r class in the Class Sum m ary. Lo o k at its
re adLine () metho d. Sure eno ugh, there's o ur exceptio n:
Exception T ypes
We have seen vario us types o f exceptio ns. No t every cat ch clause will wo rk fo r every exceptio n that's thro wn.
An exceptio n handler is co nsidered appro priate if the type o f the exceptio n o bject thro wn matches the
Note type that it can handle.
import java.io.FileReader;
import java.io.BufferedReader;
Edit File Fe t che r. Add the impo rts and declare the instance o f File Re ade r and Buf f e re dRe ade r so they
can be seen by all metho ds:
CODE TO EDIT: FileFetcher
package exceptionTesting;
Of co urse, we can't find a file--we haven't made o ne yet. Let's make o ne no w. This time we're making a new
File , no t a Java Class. Right-click o n the java4 _Le sso n7 Pro ject fo lder. Select Ne w | File . Enter the name
ho m e wo rk.t xt and click Finish.
Save it and run the File Fe t che r class. Yo ur co de has this in the Co nso le no w:
To see the entire text file in yo ur co nso le o utput, edit File Fe t che r as sho wn:
CODE TO EDIT: FileFetcher
package exceptionTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
All co de in an o bject-o riented pro gram (like Java) is perfo rmed thro ugh the use o f metho ds, and metho ds
that call o ther metho ds. So exceptio ns will always be thro wn in (o r mo re accurately, by) metho ds to so me
o ther metho d that invo ked it.
In fact, this is precisely the reaso n it is thro wing the exceptio n. If a metho d (say m e t ho d1()) can handle an
exceptio nal co nditio n, it sho uld. Only when a metho d do esn't know what to do with an exceptio n, do es it need
to thro w it to the metho d (say m e t ho d2()) that is using m e t ho d1() with the po tentially exceptio nal co nditio n.
Keep in mind that if m e t ho d1() is thro wing, then m e t ho d2() needs to cat ch--assuming m e t ho d2 is in an
enviro nment where it kno ws what to do .
If m e t ho d2() is not in such an enviro nment, then it needs to specify that it will thro w (fo rward) the exceptio n
as well. Then the metho d that called it (say m e t ho d3()) wo uld need to cat ch it.
Example
We will let o ur File Fe t che r class represent a student who is suppo sed to be writing a file named
homework.txt. Our student wants to co nvince his parents that he has to o much to do and canno t do his
ho mewo rk this time aro und; he is no t go ing to "handle" the ho mewo rk situatio n. He is no t go ing to handle
the exceptio ns fo r retrieving his ho mewo rk file in the File Fe t che r metho d o f ge t Ho m e wo rk(). Here are the
co nditio ns that represent Metho d2 fo r us:
1. The Metho d(s) where the erro r o ccurred thro w the exceptio ns. Co nstructo r
File Re ade r(" ho m e wo rk.t xt " ) and re adLine () will be Metho d1(a) and Metho d1(b), respectively.
2. The File Fe t che r metho d o f ge t Ho m e wo rk() is Metho d2: Metho d witho ut an exceptio n
handler.
So , after all that wo rk we did to handle the pro blem within the metho d itself, no w o ur student says he is go ing
to fo rward the exceptio ns. We'll see.
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
// try {
myFile = new FileReader("homework.txt");
System.out.println("I did get here");
in = new BufferedReader(myFile);
// }
// catch (FileNotFoundException e){
// System.out.println("Can't find the file, but keep going anyway -
allows for future problems");
// }
while (aLine != null){
// try {
aLine = in.readLine();
// }
// catch(IOException e){
// System.out.println("Now we have some other I/O problem");
// }
if (aLine !=null) System.out.println(aLine); // we had a
nother readLine after the check for null
}
}
The o nly active pieces o f co de in the ge t Ho m e wo rk() metho d no w are the FileReader instance, the print ln
statements, and the while lo o p fo r reading and printing lines fro m the ho mewo rk file.
We might as well co mment o ut the m ain() metho d to o . As yo u can see by the erro r message, if the
ge t Ho m e wo rk() metho d do esn't handle the exceptio ns, then the instance t e st Me canno t call the metho d,
unless it handles them.
It lo o ks like o ur irrespo nsible student isn't go ing to handle anything. Instead he's letting his Mo m do it.
Co mment o ut the entire m ain metho d here so there are no erro rs:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
If a metho d in a class do es no t catch the exceptio ns fro m metho d calls within itself, then that metho d needs to
thro w tho se uncaught exceptio ns o r it will no t co mpile. Thro wing exceptio ns rather than handling them is not
the preferred way to write metho ds. Only do it when it's absolutely necessary. If yo ur metho d can handle the
exceptio ns fro m the metho ds that it uses, it sho uld. Thro wing metho ds sho uld happen o nly when the
applicatio n canno t deal with the exceptio n in its current metho d enviro nment.
import java.io.FileNotFoundException;
import java.io.IOException;
Save and run it. Yo u might get a warning that there are still erro rs--click Pro ce e d anyway.
We are thro wing an exceptio n in this m ain() metho d to demo nstrate that it's a terrible thing to do , because no
o ne can catch fro m m ain(). That's the reaso n Eclipse warned that yo u still had erro rs. Ho wever, the co de
do es run. No exceptio n was thro wn, so there was no thing fo r the file name to catch.
Go back to the File Fe t che r class and change the file name as sho wn:
CODE TO EDIT: FileFetcher
package exceptionTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
Save it. Yo u haven't created a ho mewo rk2.txt file, so yo u pro bably have a little pro blem.
Open the Mo m class and run it. We can see that Mo m caught the File No t Fo undExce pt io n; the Co nso le
sho ws the print ln fro m the cat ch clause blo ck. No w in File Fe t che r, change the filename back to
ho m e wo rk.t xt .
package exceptionTesting;
import java.io.IOException;
Save and run it. Yo u do not get any erro rs, because no w yo u've caught all Exceptio ns.
And in o ur example that passed an exceptio n do wn the call stack, we saw this:
CODE TO EDIT: Mo m
package exceptionTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
package exceptionTesting;
import java.io.FileNotFoundException;
Even tho ugh this was a File No t Fo undExce pt io n, Mo m caught it--we see the o utput fro m her catch in the Co nso le.
Why? Because she was suppo sed to catch the IOExce pt io ns and Dad was suppo sed to catch the
File No t Fo undExce pt io ns.
Go to the java.io package. Scro ll do wn to File No t Fo undExce pt io n in the Exce pt io n Sum m ary and take a
lo o k at its hierarchy:
Exceptio ns also pay attentio n to inheritance. Mo m said she wo uld catch IOExce pt io ns, and
File No t Fo undExce pt io n inhe rit s fro m IOExce pt io ns, so it actually is an IOExce pt io n. If yo u want to make sure
to catch the right exceptio ns, always catch the mo re specific o ne first. Exceptio ns are o ften the results o f I/O pro blems.
The Mo m class also added a f inally clause, to remind Dad that he sho uld clo se his files and input streams
when he finishes reading them. The f inally clause always executes when the t ry blo ck exits. This guarantees
that the f inally blo ck is executed even if an unexpected exceptio n o ccurs. We want to allo w a pro grammer to
"clean up" after exceptio ns have o ccurred because a call fro m a t ry clause may have jumped o ut o f co de
prematurely. The f inally blo ck is a key to o l fo r preventing reso urce leaks.
Additional Information
There is plenty mo re to see in the Java Tuto rial Lesso n o n Exceptio ns. Check it o ut. See yo u in the next lesso n...
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Threads: Introduction
Multi-T asking
In the next few lesso ns, we'll explo re the ways Java allo ws us to co o rdinate multiple tasks. Pro grammers need be
able to determine which o peratio ns are executed and in what o rder. The Java pro gramming language allo ws us to
write vario us individual pro grams that, while running seperately and co ncurrently, appear as a single, unified and
seamless o peratio n to the user. This is acco mplished by pro viding mechanisms fo r synchro nizing the co ncurrent
activity o f threads.
T hreads
A thread is a single sequential flo w o f co ntro l within a pro gram. The API says, "A thread is a thread o f executio n in a
pro gram. The Java Virtual Machine allo ws an applicatio n to have multiple threads o f executio n running co ncurrently."
Befo re we discuss the theo ry o f Threads, we'll lo o k at the to o ls Java pro vides fo r us to weave them into o ur co de. We
will lo o k at Threads themselves mo re explicitly in the next lesso n.
Go to the java.lang package and scro ll do wn to the T hre ad class and read its intro ductio n. A thread has these
qualities:
1. supe r(st r)
2. the try/catch clause surro unding the sle e p() metho d
Let's go to the API to find o ut mo re abo ut this co de. Go to java.lang.T hre ad and check o ut the inheritance tree.
Our Sim ple T hre ad class inherits fro m T hre ad. What wo uld T hre ad Co nst ruct o r inherit if a St ring was passed to
it via supe r(st r)?
Go to the java.lang.T hre ad Me t ho d Sum m ary and lo o k at the metho ds there. Bo th metho ds present thro w
Int e rrupt e dExce pt io ns. We need to handle them using try/catch clauses.
We've seen the static metho d call Mat h.rando m () and casting befo re, so this might lo o k familiar to yo u already. If no t,
go to the java.lang.Mat h class and lo o k at the rando m () metho d.
Yo u see a menu cho ice Ope n Run Dialo g, and then a windo w:
Go ahead and cho o se Run. Hmm. So mething's wro ng. There are a number o f questio ns to co nsider:
Is yo ur class an Apple t ?
Do es yo ur applicat io n have a m ain() metho d?
Have yo u instantiated yo ur Sim ple T hre ad to make an instance?
Did Eclipse simply grab the last applicatio n yo u ran?
Let's add a m ain() metho d to test. Edit Sim ple T hre ad as sho wn in blue belo w:
CODE TO EDIT: SimpleThread
package demo;
No thing happened. That's because you have direct co ntro l o f yo ur thread, so you must start it explicitly. Java T hre ads
need to be instantiated like any o ther class. Ho wever, yo u do n't call the run() metho d explicitly; yo u begin by invo king
the st art () metho d. Edit Sim ple T hre ad again. Add the co de in blue as sho wn:
Go to the java.lang.T hre ad class and lo o k at its st art () metho d. Here (and in general) we inherit the metho d
st art () fro m o ur thread Sim ple T hre ad's parent T hre ad.
In the instance o f the T hre ad that we're running here, we instruct it to sle e p() fo r a few milliseco nds. This sto ps it fro m
running fo r at least the specified time and then allo ws it to co ntinue.
Let's see what happens when we co mment o ut the t ry/cat ch blo ck with the sleep call:
Save and run it. Take the co mment slashes (//) o ut, then save and run it again. Putting threads to sle e p() allo ws
mo re time fo r o ther actio ns (fro m o ther threads) to take place.
Manipulating T hreads
Let's experiment so me mo re. Create a new Ano t he rT hre ad class in the java4_Lesso n8 pro ject as sho wn:
Type Ano t he rT hre ad as sho wn in blue :
CODE TO TYPE: Ano therThread
package demo;
We have defined the class Ano t he rT hre ad, which has a nested class named T , which extends T hre ad. The
variable t in the m ain() metho d o f class Ano t he rClass sho uld co ntain a valid thread o f executio n fo r an
instance o f the subclass o f T hre ad that we named T . We co ntro l this thread in the run() metho d.
Once inside the run() metho d, we're able execute statements just like in any pro gram. In these examples, we
are pausing fo r a specified perio d o f time. In o ur first example, the perio d o f time was rando m; in the abo ve
class, it's 30 0 milliseco nds. In o ur co de it's written like this: sle e p(30 0 ).
The sle e p() metho d tells a thread to pause fo r at least the specified number o f milliseco nds. The sle e p()
metho d do es no t take up system reso urces while the thread sleeps. Other threads can co ntinue to wo rk.
No rmally, threads sto p when their run() metho d is co mplete. In this thread, ho wever, we have an infinite lo o p
in the run() metho d.
[Ct rl+c] will sto p mo st executio n pro cesses. However, in this case (that is, within Eclipse within a thread
within o ur co ntro l), yo u click the T e rm inat e bo x to sto p executio n:
Here's ano ther example that uses threads and passes parameters. In the java4_Lesso n8 pro ject, add a new
T e st T hre ad class as sho wn:
Type T e st T hre ad as sho wn in blue belo w:
CODE TO TYPE: TestThread
package demo; // Define our simple threads.
They will pause for a short time
// and then print out their nam
es
class TestThread extends Thread {
private String whoAmI;
private int delay;
The run() metho d serves as the m ain() ro utine fo r threads. Just like m ain(), when run() finishes, so do es
the thread.
Applicatio ns use the m ain() metho d to retrieve their arguments fro m the args parameter (which is typically
set in the co mmand line). A newly created thread must receive its arguments pro grammatically fro m the
o riginating thread. That way parameters can be passed in thro ugh the co nstructo r, static variables, o r any
o ther technique designed by the develo per. In the T e st T hre ad example, we pass the parameters thro ugh the
co nstructo r. We need to create a class to instantiate a few instances o f this T e st T hre ad.
In the java4_Lesso n8 pro ject, add a new class named Mult iT e st as sho wn:
Type Mult iT e st as sho wn in blue belo w:
Remember that these are random, so the o rder in which they appear do es no t necessarily indicate increased
o r decreased delays.
T hreads in Applets
Apple t s can have T hre ads to o . With a few adaptatio ns, o ur applicatio n abo ve can be turned into an Applet.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
Save and run it. Click o n the butto n. There's o utput in the Co nso le because we used
Syst e m .o ut .print ln. Fo r no w, clo se this Applet. We'll co me back to it later when we lo o k at Thread States.
in the java.lang package, go to the Int e rf ace Sum m ary and cho o se Runnable . Scro ll do wn its descriptio n to
see the metho ds that this interface specifies. Yo u'll actually o nly see o ne metho d in the Me t ho d Sum m ary: run().
If a class im ple m e nt s Runnable , then the class must implement the run() metho d. An instance o f the class can then
be allo cated, passed as an argument when creating a T hre ad, and started. We'll go to the API to see what this means,
and demo nstrate it.
Go to the class java.lang.Thread and read thro ugh its co nstructo rs. Many o f them have a parameter o f type
Runnable :
Let's try an example. In java4_Lesso n8 , create a new class as sho wn:
Type T hre ade dApple t as sho wn in blue :
CODE TO TYPE: ThreadedApplet
package demo;
import java.applet.Applet;
import java.awt.Graphics;
This pro gram is an Apple t with a run() metho d that cycles to print different messages. When the Applet starts, it
instantiates the T hre ad and then starts the Thread instance. In this example, we passed the Thread Co nstructo r an
instance o f an o bject that implements Runnable (that is, the Applet itself--t his). The Thread then co mes back to the
Applet to get the run() metho d that it implemented. This is especially co nvenient, because then the
T hre ade dApple t 's paint (Graphics g) metho d and the implemented run() metho d can share the m e ssage s[ ]
instance variable.
Here the ThreadedApplet class has a st art () metho d f o r t he Apple t . In this metho d, the thread is instantiated and its
st art () metho d (apple t T hre ad.st art ();) is invo ked. Of co urse, we'll want a st o p fo r o ur thread to o . Fo r no w, yo u
can sto p the thread and applet by quitting the applet.
The Runnable interface specifies the run() metho d that is required. Any class that implements this interface can
pro vide the body o f a thread. By implementing the Runnable interface, yo u declare yo ur intentio n to run a separate
thread.
Whichever way yo u lo o k at threads, the o perative wo rd is run(). Mo re details o n Java Threads are o n the way!
Copyright © 1998-2014 O'Reilly Media, Inc.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Threads: Concurrent Programming
A process has a self-co ntained executio n enviro nment. Mo st co mputer users use pro cesses witho ut kno wing it.
Pro cesses are usually lo cated at the level o f o perating systems so ftware, o r kernel-level entities. A pro cess generally
has a co mplete, private set o f basic run-time reso urces. Specifically, each pro cess has its o wn registers, pro gram
co unter, stack po inter, and memo ry space.
Threads exist within a pro cess-—every pro cess has at least o ne thread. In Java, co ncurrent pro gramming is
acco mplished mo stly thro ugh threads. So metimes threads are called lightweight pro cesses o r execution contexts.
Bo th pro cesses and threads pro vide an executio n enviro nment (like pro cesses, threads have their o wn registers,
pro gram co unters, stack po inters, etc.), but threads are clo ser to a user-level entity. We can create threads and tell
them what to do using fewer reso urces than we do when we create and info rm new pro cesses.
Multiple threads running at the same time and sharing reso urces have the po tential to cause pro blems.
Note We'll go o ver so me o f these issues in this lesso n. We'll talk abo ut o thers in the next lesso n when we
explo re synchro nizatio n. Fo r no w, we'll fo cus o n plain o ld multi-tasking.
Multi-threaded Applications
T he Life of a T hread
Let's start with an example o f multi-tasking. In the edito r, o pen yo ur java4_Lesso n8 fo lder to the de m o
package and o pen the T hre ade dApple t class. Edit T hre ade dApple t as sho wn in blue belo w:
CODE TO TYPE: ThreadedApplet
package demo;
import java.awt.Graphics;
import java.applet.Applet;
Save and run it. Watch it run fo r a while, then in the Applet Viewer Windo w, select Apple t | St o p to sto p it.
No w, watch the Co nso le fo r a minute.
Our Applet has sto pped (it's no lo nger painting), but its Thread is still running (it's still putting o utput into the
Co nso le). Quit the Applet to clo se the Applet Viewer Windo w; the actio n in the Co nso le sto ps.
We will fix this by making o ur co de cleaner, but first let's go o ver o ne mo re backgro und item.
Garbage Collection
One example o f a thread wo rking in the backgro und in Java is in garbage collection--retrieving memo ry that
has been allo cated, but is no lo nger being used. Java co llects garbage using T hre ads. While yo u are
running yo ur pro gram, the Java Virtual Machine has a garbage co llectio n thread cleaning up in the
backgro und.
Here are so me links to mo re info rmatio n o n this to pic. This JavaWo rld article explains the co ncept o f garbage
co llectio n. Oracle also pro vides a useful page that explains Tuning Garbage Co llectio n.
T hread States
The first Java tuto rial o n T hre ads pro vides the state transitio n diagram belo w described as "an o verview o f the
interesting and co mmo n facets o f a thread's life":
Each o val in the diagram represents a po ssible state o f the thread. The arro ws represent po tential transitions amo ng
the states. We will give yo u a new versio n o f o ur T hre ade dApple t and co mment in the co de when the thread is in
o ne o f tho se po tential states listed.
import java.awt.Graphics;
import java.applet.Applet;
Thread appletThread;
String messages[] = {"Hello Thread World!" , "I'm doing fine." , "Good-bye for now!
"};
int i = 0;
This time, when o ur Applet was sto pped (no lo nger painting), its Thread was also sto pped (no new o utput in Co nso le).
This is because when we sto pped the Applet, we actually killed the thread (we made it null), but we aren't do ne yet!
Restart the Applet (Apple t | Re st art ). When we Restart, it calls the st art () metho d o f the Applet, which starts a new
Thread. The thread begins again--bo th in the Applet's paint () metho d and in the Co nso le. No w, try to Start the Applet
(Apple t | St art ). Lo o k at the bo tto m o f the Applet Viewer Windo w:
This time, the Applet was already in the start state, as was its Thread. A thread canno t be started with the st art ()
metho d after it has already been started (click here to learn mo re abo ut st art () fo r T hre ads). That's why we checked
first to find o ut if the thread already existed in the st art () metho d fo r the applet. If it did no t exist, we wo uld've created it.
If it had existed, we wo uldn't have had to do anything because it still wo uld've been there, even if the applet had been
delayed fo r a while. Let's lo o k mo re clo sely at thread states and see what else is po ssible.
T hread.State
In o rder to start the thread, we called a st art () metho d fo r the thread inside o f the st art () metho d fo r the applet. So
why do n't we do the same thing to sto p? We wro te a st o p() metho d fo r o ur applet, so why did we kill the thread (by
making it null) rather than call a thread st o p() metho d?
Go to java.lang.T hre ad. Scro ll to the Me t ho d Sum m ary. Check o ut these metho ds: de st ro y(), re sum e (),
st o p(), and suspe nd().
In each o f these metho ds yo u see the wo rd deprecated and a descriptio n o f the reaso n. Each new release o f Java
includes new functio nality and fixes. If a metho d is deprecated, it means that the metho d sho uld no t be used in new
co de because a pro blem was fo und that co uld no t be fixed, but that metho d is retained (perhaps tempo rarily) in o rder
to maintain co mpatibility with o lder versio ns o f Java. There is an inherent pro blem with the o lder implementatio n, so
newer versio ns o f Java sho uld no t use it. If yo u are respo nsible fo r maintaining co de that co ntains a deprecated
metho d, replace that metho d if po ssible.
Each deprecated metho d po ints to the Oracle tuto rial Java Thread Primitive Deprecatio n.
T hre ads was altered in versio n 1.5 o f Java to alleviate pro blems with deprecated metho ds. They also want to make
sure that users do n't enco unter pro blems due to the speed o f co mputers by adding Enum States fo r T hre ads. Let's
take a lo o k at tho se changes.
Go to java.lang.T hre ad. Scro ll to the Ne st e d Class Sum m ary. Click o n T hre ad.St at e . Scro ll to the descriptio n
o f the states:
If Oracle created Enum Co nst ant s in their o wn Enum class T hre ad.St at e , then T hre ad states must be impo rtant.
This particular T hre ad.St at e class is dedicated so lely to pro viding an enumeratio n o f the states and metho ds that
indentify tho se states.
We'll include a mo nito r when we create o ur applicatio n. Our threaded applicatio ns will have these three
co mpo nents:
T he Producer
Make a new java4 _Le sso n9 pro ject. If yo u're given the o ptio n to "Open Asso ciated Perspective", click No . In
this pro ject, create a new Class as sho wn:
try {
sleep((int)(Math.random() * 2000)); // sleep for a while so it
is not too fast to see
} catch (InterruptedException e) { }
}
}
}
Save it.
T he Consumer
In java4_Lesso n9 , create a new Co nsum e r class as sho wn:
T ype Co nsum e r as sho wn in blue :
CODE TO TYPE: Co nsumer
package prodcons;
try {
sleep((int)(Math.random() * 3000)); // have consumer sleep a
little longer or sometimes we never see the alphabets!
} catch (InterruptedException e) { }
}
}
}
Save it.
T he Monitor
To ensure that shared info rmatio n within the mo nito r do esn't beco me co rrupted, we'll synchronize the add
and re m o ve metho ds in this class. Synchro nizatio n prevents multiple metho ds fro m accessing a shared
reso urce simultaneo usly. If a metho d in a class is synchro nize d, it BLOCKs o ther T hre ads fro m accessing
any o ther synchro nize d metho ds in that instance o f that class.
A class with synchro nize d metho ds pro vides a lo ck and prevents what are kno wn as deadlock co nditio ns.
Here's ho w a deadlo ck co nditio n might lo o k in real life. Let's say we're waiting in line in a bank. I am at the
fro nt o f the line, waiting to withdraw cash. The bank is o ut o f cash, but I am willing to wait fo r so me cash to be
depo sited. The bank o nly has o ne teller, who canno t handle ano ther transactio n until the current transactio n is
finished. I am still waiting to receive my mo ney, so my transactio n is no t finished. Yo u are in line behind me
with a millio n do llars to depo sit. Yo u can't depo sit the mo ney until I finish my transactio n, and I will no t be
finished until so meo ne depo sits so me mo ney. We are in a deadlock.
In o ur example, we'll use synchro nize d blo cks o f co de to prevent deadlo ck. A few o ther elements o f o ur
example yo u sho uld also be aware o f:
Only 6 alphabet letters may be in the so up at a given time, so we set the variable capacit y to 6 .
We'll determine whether there are alphabet letters in the so up (the buffer) befo re we take any o ut.
We'll determine whether the so up is full (that is, at it's capacity o f 6 letters) befo re we add any mo re.
Two impo rtant metho ds fo r T hre ads will be used during this pro cess: no t if yAll() and wait ()
Go to java.lang.T hre ad in the API. Scro ll do wn to the Me t ho d Sum m ary. Lo o k fo r the metho ds
no t if yAll() and wait (). Remember to lo o k at all o f the metho ds fo r T hre ads--including the o nes inherited
fro m Obje ct .
import java.util.*;
try {
wait(); //
if so, we WAIT until someone puts something there
} catch (InterruptedException e) {} //
doing so temporarily allows other synchronized methods to run (specifically - a
dd)
} //
we will not get out of this while until something is there to eat
String toReturn = buffer.get((int)(Math.random() * buffer.size())); //
get a random alphabet in the soup
buffer.remove(toReturn); //
remove it so no one else can eat it
buffer.trimToSize(); //
reduce the size of the buffer to fit how many pieces are there
notifyAll(); //
tell anyone WAITing that we have eaten something and are done
return(toReturn); //
actually return the alphabet piece to the consumer who asked to eat it
}
Save it.
T he GUI View
No w let's put it all to gether, using an Apple t to pro vide a nice vie w fo r o ur users.
import java.applet.Applet;
import java.util.*;
import java.awt.*;
Save and run it. Lo o k at the Co nso le and the Soup Bowl. The letters mo ve aro und because they are being
"stirred" as they are eaten.
Run it a few times (be sure to clo se the applets when yo u're finished so they do n't pile up). If yo u run the
pro gram eno ugh times, eventually yo u'll have pro blems:
Play with the sle e p frequency in the Pro duce r and Co nsum e r to see ho w changing that number effects the way the
Applet runs.
And, fo r yo ur added enjo yment, here's ano ther simple illustratio n o f pro ducer/co nsumer/mo nito r co de at wo rk. Enjo y!
And see yo u in the next lesso n...
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Threads: Synchronization
Race Conditions
In the last lesso n we made o ur first pro ducer/co nsumer design patterns pro gram. In this lesso n, we'll explo re
synchro nizatio n further, expanding o n o ur earlier examples. First we'll edit o ur So up pro gram to facilitate a cleaner
design.
No t to wo rry. We pro grammers can always find ways to fix a pro blem! Let's go o ver the initial text in re d first:
Exce pt io n in t hre ad " AWT -Eve nt Que ue -1" java.ut il.Co ncurre nt Mo dif icat io nExce pt io n
Race co nditio ns usually invo lve o ne o r mo re pro cesses accessing a shared reso urce (such as a file o r variable),
where multiple access is no t co ntro lled pro perly.
Here's ho w a race co nditio n might lo o k in real life. Suppo se o n a given day, a husband and wife bo th decide to empty
the same bank acco unt and, purely by chance, they empty the acco unt at the same time. If the two withdraw fro m the
bank at the exact same time, causing the metho ds to be called at the exact same time, bo th ATMs co uld co nfirm that
the acco unt has eno ugh cash and dispense it. The two threads access the acco unt database at the same time.
The race co nditio n exists here because the actio ns o f checking the account and changing the account balance are no t
atomic. An atomic ro utine is o ne that can't be interrupted during its executio n. In o ur banking example, if the actio ns o f
checking the acco unt and changing the acco unt balance were ato mic, it wo uld be impo ssible fo r a seco nd thread to
check o n the acco unt, until the first thread had finished changing the acco unt status.
To avo id race co nditio ns, we synchro nize the e at () and add() metho ds. Synchro nizatio n prevents race co nditio ns by
preventing a seco nd metho d fro m running befo re the first metho d is co mplete.
No w let's go back to the erro r in o ur So up example. Our red text info rms us o f the lo catio n o f the erro r:
Because we are accessing the variable that represents o ur shared reso urce in the ge t Co nt e nt s() metho d o f So up,
the metho d sho uld be synchronized so it wo n't be initiated while it is being accessed by ano ther metho d. If we access
and co py o ur metho d at the very mo ment that it is changing, it co uld cause the Co ncurre nt Mo dif icat io nExce pt io n.
This is an example o f a race co nditio n.
And even if we synchro nized the metho d, we wo uld still have pro blems. Since mo st co llectio ns in Java (fo r example,
arrays and ArrayList s) are sent by reference, even tho ugh we use a metho d to get the co ntents and put them into
ano ther variable, they still po int to the same place in memo ry. So when we get the co ntents back to the Applet and then
print them o ut, we co ntinue to access the shared reso urce in a po tentially dangero us way. This is a pro blem with
ArrayList s. In o rder to address these issues, we'll co py the buffer and then pass it back.
try {
sleep((int)(Math.random() * 3000)); // have consumer sleep a little lo
nger or sometimes we never see them!
} catch (InterruptedException e) { }
}
}
}
Save it.
A thread sto ps when its run() metho d has finished. So in o ur example, after 10 alphabet letters have been pro duced
and then co nsumed, their respective threads will sto p and as such, they are co nsidered "dead."
import java.util.*;
class Soup {
private ArrayList <String> buffer = new ArrayList<String>();;
private int capacity = 6;
Save it.
In java4_Lesso n9 /src/pro dco ns, edit the MyT able Se t t ing class as sho wn in blue and re d:
CODE TO EDIT: MyTableSetting
package prodcons;
import java.applet.Applet;
//import java.util.*; // don't need anymore because we have array copy
import java.awt.*;
p1.start();
c1.start();
System.out.println("Consumer is in state " + c1.getState()); // show the stat
e of the thread at this point
}
g.setColor(Color.yellow);
g.fillOval(bowlX,bowlY, bowlWidth, bowlLength);
g.setColor(Color.cyan);
g.fillOval(10,25, 40, 55);
g.fillOval(25,80, 8, 75);
g.setColor(Color.black);
g.drawOval(10,25, 40, 55);
g.drawOval(25,80, 8, 75);
g.drawOval(bowlX,bowlY, bowlWidth, bowlLength);
Font standardFont = getFont(); // tell what just ate in
spoon
Font bigFont = new Font("Helvetica", Font.BOLD, 20);
g.setFont(bigFont);
if (justAte != null) {
g.drawString(justAte, 25, 55);
justAte = null;
}
else {
g.setFont(standardFont);
g.drawString("waiting", 13, 55);
g.setFont(bigFont);
}
Object [] contents = s.getContents(); // bring back a fresh array of Object
for(Object each : contents){ // no longer tied in memory to buffer in
Soup
x = bowlX + bowlWidth / 4 + (int)(Math.random() * (bowlWidth / 2));
y = bowlY + bowlLength / 4 + (int)(Math.random() * (bowlLength / 2));
g.drawString((String)each, x, y); // show the al
phabet piece being eaten
}
System.out.println("Producer is in state " + p1.getState()); // show state of
Producer (remember that we put it to sleep)
System.out.println("Consumer is in state " + c1.getState());
if(c1.getState()==Thread.State.TIMED_WAITING){ // note access t
o enumerated types for Thread States
checkState(); // get last rep
aint() in so see TERMINATED
}
}
Save and run it. Lo o k o ver the o utput in bo th the Co nso le and the Applet's bo wl and fo llo w the pro gressio n o f the
states. Co mment o ut the print lns and run it again witho ut tho se distractio ns. Yo u'll see that so me states o f the
T hre ad are accessible thro ugh their inner enumerated class T hre ad.St at e .
This sho uldn't happen tho ugh, because o ur pro gram wo uld thro w a NullPo int e rExce pt io n if it had tried to eat
so mething fro m the buffer that wasn't there yet. So the letter must have been in the buffer in o rder to then have been
taken o ut. Hmm.
Maybe the Syst e m .o ut .print lns o f MyT able Se t t ing were running first and gave us a race co nditio n. The main
thread (the applicatio n o r the applet) always takes prio rity. Fo rtunately, the class T hre ad co ntains metho ds to handle
such situatio ns, including jo in(), wait (), sle e p(), ge t Prio rit y(), and se t Prio rit y(), to name just a few.
Additional Resources
There's lo ts o f material available to help yo u to wo rk thro ugh co ncurrency and threads. Here's are just a few o f them:
A running example is pro vided here fo r yo u. Play aro und with it befo re we write the co de, then as yo u write the co de,
the classes and their metho ds will make sense.
T he Bomb
Each bo mb has a life o f its o wn and is its o wn thread. Each bo mb is asso ciated with the set o f letters o r word
presented underneath it and each has its o wn fuse (the red line under the wo rd) that displays the amo unt o f
time remaining.
As yo u type the co de, co mments in the co de pro vide info rmatio n abo ut the reaso n fo r each metho d. Also , the
fo rmal parameter specifies (char c) fo r metho ds that have a char passed--this do es no t mean the value is c.
It just means that c is the variable name fo r the character passed.
Our java4_Lesso n10 pro ject co mes with an images fo lder fo r this example. Click here, and then o pen it in the
Package Explo rer. It sho uld lo o k like this:
import java.awt.*;
import java.applet.Applet;
Save it.
No w o ur co de co ntains the asse rt statement. The asse rt statement was added to Java versio n 1.4 as a
debugging to o l. We'll address debugging practices in depth later, but fo r no w, check o ut Oracle's
do cumentatio n pages abo ut Pro gramming with Assertio ns.
Producing Words
The Pro duce r in o ur Bo mb game pro gram is also a T hre ad that pro duces the words to type.
In the java4_Lesso n10 pro ject, create a new Pro duce r class as sho wn:
No w type Pro duce r as sho wn in blue :
CODE TO TYPE: Pro ducer
package bomb;
import java.applet.Applet;
Save it.
Consuming Keys
In o ur example, users are the co nsumers. As users type, they co nsume the wo rds that have been placed in
the Wo rld. To allo w o ur users to do this, we include a Ke yList e ne r class. But since we wo n't need all o f the
Ke yList e ne r metho ds, we'll also use a Ke yAdapt e r.
Lo o k at the Adapter Class java.awt .e ve nt .Adapt e r and the interface that it implements
java.awt .e ve nt .Ke yList e ne r to find o ut which metho ds are available.
In the java4_Lesso n10 pro ject, create a new Co nsum e r class as sho wn:
import java.applet.Applet;
import java.awt.event.*;
Save it.
Monitoring Words
The mo nito r in this example watches o ver all o f the wo rds presented, as well as the user's typing speed and
accuracy. Each new word has a bo mb asso ciated with it. This mo nito r co nsiders the co nsumptio n o f the
wo rds in two ways:
In the java4_Lesso n10 pro ject, create a new Wo rld class as sho wn:
Type Wo rld as sho wn in blue :
CODE TO TYPE: Wo rld
package bomb;
import java.awt.*;
if (num_bombs == MAX_BOMBS)
{
isFull = true;
}
isEmpty = false;
notifyAll();
}
Save it.
T he User Interface
The graphical user interface fo r o ur example is relatively straightfo rward:
Do uble-buffering, specifically a Do uble-Buffer Applet, was used here to create the GUI.
In the java4_Lesso n10 pro ject, create a new T ype OrDie class as sho wn:
Type T ype o rDie as sho wn in blue :
CODE TO TYPE: TypeOrDie
package bomb;
import java.awt.event.*;
import java.awt.*;
import java.applet.Applet;
myWorld.draw(bufferGraphics);
g.drawImage(offscreen, 0, 0, this);
}
Save and run it. Alternate between running the co de and reading what each o bject do es so yo u understand
the reaso ns behind the implementatio n.
We Love T hreads
Threads are a challenge, but with practice they'll serve yo u well. Check o ut these implementatio ns o f threads:
Real Games
Yo u'll find lo ts o f real games po wered by Java here.
Blackjack
Blackjack is o ne o f the mo st po pular casino games in the wo rld. Given o ur kno wledge o f threads, and the
card capabilities we acquired in the last co urse, we co uld create o ur o wn blackjack game that allo ws multiple
players.
No w suppo se yo u have two o r three players spread acro ss the internet and they all cho o se to be Hit at the
same time. Yo u could have a race co nditio n, and yo u could co rrupt the game by giving all o f the players the
same card! Having the game set up so that multiple players can each play o n their o wn separate thread will
allo w yo ur game to go o ff witho ut a hitch. Successful java pro gramming--it's all abo ut the threads.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Databases: Connectivity through Java
T he JDBC API
The next few lesso ns fo cus o n co nnecting Java to databases to access info rmatio n.
What is JDBC?
JDBC is a Java API asso ciated with accessing tabular data; that is, data that yo u'd generally want to reco rd in
a table. A table is a single sto re o f related info rmatio n; a database can co nsist o f o ne o r mo re tables o f
info rmatio n that are related in so me way. JDBC is used to pro cess SQL statements and enable yo ur
pro grams to access relatio nal databases. Like o ther Java APIs, the JDBC API co nsists o f classes and
interfaces written in the Java pro gramming language. Their main purpo se is to pro vide a standard API fo r
database develo pers and make it po ssible to write database applicatio ns using a pure Java API, which in turn
ensures that yo ur co de will be po rtable.
Go to the java.sql package to see so me o f the available classes and interfaces. Skim thro ugh the
Package java.sql Descriptio n and its histo ry. Go to the javax.sql package to see so me o f the extended
server-side functio nality that its classes and interfaces pro vide. This co urse fo cuses o n the java.sql package.
(The server-side info rmatio n in javax.sql applies in the J2EE co urse in this series.)
Altho ugh JDBC pro vides many classes and interfaces fo r use with databases, tho se three are the mo st
co mmo nly used. Here we've set up a table o f the co mmo n JDBC tasks and their co rrespo nding classes o r
interfaces:
Access to a Database
SQL can co mmunicate with mo st database systems witho ut changing the SQL co mmands. The MySQL
database server is likely the mo st po pular o pen so urce database so ftware amo ng pro grammers and is
available fo r use o n a wide variety o f platfo rms. We'll use the MySQL database fo r o ur examples.
In this co urse, yo u have been granted access to the MySQL database o n the O'Reilly Scho o l o f Techno lo gy
server. Yo u can access that database using the same username and passwo rd that yo u use to lo g o nto yo ur
co urses.
OST uses a master passwo rd (and Sandbo x lo gin) fo r all lo gin instances. In so me cases, the
passwo rd fo r MySQL can beco me o ut o f sync and cause this o r a similar erro r:
Note This erro r will also appear if the lo gin o r passwo rd is inco rrect. Ho wever, fo r OST, it is mo st
likely a “passwo rd o ut-o f-sync” issue.
To fix this, update the passwo rd fo r the OST Sandbo x fro m the My Acco unt sectio n o f the
Student Start Page (students.o reillyscho o l.co m/student/). This will reset the passwo rd fo r all
lo gin instances, including MySQL. Yo u can use yo ur current passwo rd witho ut changing it.
Remember that the Sandbo x lo gin and passwo rd are case sensitive.
Even tho ugh SQL is standardized, each database vendo r has a different interface, as well as different
extensio ns o f SQL. Our no tes and examples here will be all-purpo se so yo u can use them o n this, as well as
o ther databases.
T he Driver
Pro grammers use many different databases. Each database needs a driver to co nnect it to the Java pro gram.
There are fo ur types o f JDBC drivers. We will use a Type 4 driver, because it will co mmunicate directly with o ur
data so urce. Let's go ahead and start the Pro ject and get the driver. Create a new dat abase Drive r pro ject fo r
this lesso n.
The driver is actually a co llectio n o f Java classes that assist co nnectivity that are packaged into
Note o ne .jar (Java ARchive) file, similar to a .zip o r .tar file, used to ho ld multiple files. The Java VM
can get into .jar files fo r classes and files it needs if the .jar is in the CLASSPATH.
Put the driver into the CLASSPATH fo r yo ur pro ject. To do this, do wnlo ad the appro priate driver (we've already
do ne this fo r yo u), then right-click the dat abase Drive r pro ject, cho o se Build Pat h | Add Ext e rnal
Archive s, bro wse to the C:\jdbc fo lder and select the m ysql-co nne ct o r-java-5 .1.5 -bin.jar file:
Yo u might find a newer versio n o f the JDBC driver in this fo lder. The newer versio ns sho uld be
Note backward co mpatible with the versio ns referenced in this lesso n.
Then yo u'll see this file:
It pro vides Java with a lo catio n fo r sto ring classes that it needs fo r this applicatio n. Yo u will need to access
this path fo r each pro ject that uses the database, so remember this pro cedure.
It appears that Eclipse places these "external archives" into a fo lder called Re f e re nce d Librarie s, but
because this is the Referenced Library, Eclipse actually just po ints to the lo catio n o f the real file. A
CLASSPATH is a PATH to the CLASSES that Java requires fo r an applicatio n.
import java.sql.*;
try {
// Establish the database connection, create a statement for execution of SQL
commands.
connection = DriverManager.getConnection (url, username, password );
// username and password are passed into this Constructor.
statement = connection.createStatement();
// statement used to do things in the database (e.g., create the PhoneBook tab
le).
}
catch (SQLException exception ) {
System.out.println ("\n*** SQLException caught ***\n");
while (exception != null)
{
// grab the exception caught to tell us the problem.
System.out.println ("SQLState: " + exception.getSQLState() );
System.out.println ("Message: " + exception.getMessage() );
System.out.println ("Error code: " + exception.getErrorCode() );
exception = exception.getNextException ();
System.out.println ( "" );
}
}
catch (java.lang.Exception exception) {
// perhaps there is an exception that was not SQL related.
exception.printStackTrace();
// shows a trace of the exception error--like we see in the console.
}
}
}
Save it.
Let's go o ver this particular line o f co de first: St ring url = " jdbc:m ysql://sql.use ract ive .co m :330 6 /" +
use rnam e ; pro vides JDBC a way to identify a database. Its structure is such that the appro priate driver
reco gnizes and establishes a co nnectio n with it. The driver writer determines the JDBC URL that identifies
their particular driver. Yo u need no t wo rry abo ut ho w to fo rm a JDBC URL; just use the URL supplied with the
drivers. Fo r instance, if yo ur username is blob, then yo ur url to access the MySQL server at the O'Reilly
Scho o l o f Techno lo gy is jdbc:m ysql://sql.use ract ive .co m :330 6 /blo b.
(The rest o f the co de will be explained in the next few sectio ns o f the lesso n.)
T he Factory Design Pattern
There are certain design patterns in Java that are used frequently. By beco ming familiar with design patterns,
pro grammers can avo id co mmo n pitfalls that may arise when using particular designs. We have already seen two
such frequently used patterns: Model/View/Controller (MVC) and Producer/Consumer (in threads). The co de in o ur
example abo ve inco rpo rates ano ther co mmo n design pattern called the Factory Design Pattern.
The facto ry metho d within the facto ry pattern produces an o bject. Facto ry metho ds are st at ic metho ds that return an
instance o f the interface o r class, usually thro ugh the use o f a Co nstructo r and the ne w co mmand. Facto ry metho ds
enable pro grams to pro duce o bjects witho ut specifying the precise class that will access the o bject because they are
o ften instantiated as an interface rather than a class.
unlike co nstructo rs, may have meaningful names, which can clarify co de.
do no t need to create a new o bject o n each invo catio n--o bjects can be cached and reused, if necessary.
can return a subtype o f their return type. That is, they can return an o bject who se implementatio n class is
unkno wn to the caller. This is a very valuable and widely used feature in many framewo rks that use
interfaces as the return type o f static facto ry metho ds.
Co mmo n names fo r facto ry metho ds include ge t Inst ance () and value Of (), tho ugh using these names is o ptio nal--
cho o se whatever makes sense fo r yo ur particular usage.
In o ur example, when co nnecting to the database, we do n't use ne w, but o btain o bjects using the statements
Class.f o rNam e (" co m .m ysql.jdbc.Drive r" ), co nne ct io n = Drive rManage r.ge t Co nne ct io n(url, use rnam e ,
passwo rd), and st at e m e nt = co nne ct io n.cre at e St at e m e nt ().
Go to the java.lang.Class class and lo o k at the st at ic metho d f o rNam e (St ring classNam e ). This metho d
auto matically creates an instance o f a driver and registers it with the DriverManager, so yo u do n't have to create an
instance o f the class.
Go to the java.sql.Drive rManage r class and lo o k at the st at ic metho d ge t Co nne ct io n(St ring url, St ring
use r, St ring passwo rd). The metho d returns an inst ance o f the int e rf ace Co nne ct io n--because it is an interface,
it do es no t have a Co nstructo r and canno t be created with the ne w co mmand. By returning an inst ance o f the
interface, the metho ds are implemented and yo u can use them.
In the java.sql.Drive rManage r class, the Class.f o rNam e () is no lo nger needed. Later we'll co mment it o ut and run
the co de to see if it wo rks as specified.
Go to the java.sql.Co nne ct io n interface and then to the cre at e St at e m e nt () metho d. It returns an instance o f
the int e rf ace St at e m e nt . Again, because St at e m e nt is an interface, it do es no t have a Co nstructo r and canno t be
created with the ne w co mmand.
Finally, when a metho d is st at ic, it can be called fro m the class. Many o f the metho ds we'll use fo r databases and
netwo rking will be st at ic and many o f the classes will use the facto ry metho d pattern.
T he Main
In the java4_Lesso n11 pro ject, create a new Pho ne Bo o k class as sho wn:
Type Pho ne Bo o k as sho wn in blue :
No te that "Iam" and "so Co o l" are not a valid username and passwo rd; replace them with yo ur o wn.
Save and run it. Yo u'll see this in the co nso le:
We'd better change the co de back to the way it was befo re:
public static void main ( String[] args ) { // args[0] must be the usernam
e and args[1] must be the password to connect to the mysql database
DatabaseManager databaseManager = new DatabaseManager( args[0], args[1]
); // Create the database manager.
}
}
Right -click in the edito r windo w fo r Pho neBo o k.java. Cho o se Run As | Run Co nf igurat io ns...:
In the Run windo w that o pens, cho o se the Argum e nt s tab. Pro vide yo ur username and passwo rd in the
Pro gram argum e nt s: bo x. Again, use the username and passwo rd yo u use to access the co urse. Click
Run:
Yo u still see this:
This pro blem is all to o co mmo n. The Co nso le says "Faile d t o lo ad J DBC/ODBC drive r." That text is fro m
the Dat abase Manage r class, in the cat ch blo ck aro und line 16 .
We tho ught that Class.f o rNam e (" co m .m ysql.jdbc.Drive r" ) wo uld go and get the driver, but apparently it
didn't find that driver, because it threw an Exce pt io n that was caught by o ur co de.
We put the driver's .jar into the dat abase Drive r Pro ject, and we put these Java classes into the
java4 _Le sso n11 Pro ject. No w we need to get the driver into the Pro ject we're wo rking o n:
Right-click o n the java4_Lesso n11 Pro ject, then cho o se Build Pat h | Add Ext e rnal Archive s, which o pens
the file bro wser fo r yo u to get the driver. In the file dialo g, start to type the path C:\jdbc\m ysql-co nne ct o r-
java-5 .1.5 -bin.jar. The auto -co mplete sho uld allo w yo u to press Tab to fill in the file name m ysql-
co nne ct o r-java-5 .1.5 -bin.jar.
Run Pho neBo o k again, giving it the arguments as sho wn abo ve (Eclipse may remember them fo r us).
It's a go o d thing we included that Syst e m .o ut .print ln. If o ur pro gram runs the way we want it to , " Drive r is
se t ; re ady t o go !" will appear in the Co nso le.
Create a table in the database named Pho neBo o k: st at e m e nt .e xe cut e (" cre at e t able
Pho ne Bo o k(Nam e varchar (32), Pho ne Num be r varchar (18) )" );
Add names and pho ne numbers to the PhoneBook: st at e m e nt .e xe cut e (" inse rt int o Pho ne Bo o k
value s ('" + nam e + " ', '" + pho ne Num be r + " ');" );
Mo st o f the metho d calls are to the instance o f the interface St at e m e nt named st at e m e nt . Even tho ugh o nly a few
metho d calls are to the database, co nstructing them still requires a lot o f co de. Mo st o f that co de is co ntained within
t ry/cat ch blo cks and Syst e m .o ut .print lns and pro vides info rmatio n abo ut exceptio ns.
Go to the interface java.sql.St at e m e nt . Scro ll to the Me t ho d De t ail sectio n (o r click here). Scro ll do wn thro ugh
the metho ds; every o ne o f them thro ws an SQLExce pt io n.
When writing co de with many metho ds that thro w exceptio ns, lo calize yo ur t ry/cat ch blo cks. That is, place
T ip each statement (o r small gro uping) into its o wn t ry clause so yo u can identify the metho d that threw the
exceptio n.
In o ur example, each metho d we define in Dat abase Manage r co ntains relatively few metho d calls. And each metho d
has its o wn try/catch clause fo r the set o f metho d calls within the metho d blo ck. There's no o ther way to do it.
import java.sql.*;
try { //
Establish the database connection, create a statement for execution of SQL commands.
connection = DriverManager.getConnection (url, username, password ); //
username and password are passed into this Constructor
statement = connection.createStatement();
statement.execute("create table PhoneBook (Name varchar (32), PhoneNumber v
archar (18));"); // create a table in the database
}
catch (SQLException exception ) {
System.out.println ("\n*** SQLException caught ***\n");
while (exception != null)
{ /
/ tell us the problem
System.out.println ("SQLState: " + exception.getSQLState() );
System.out.println ("Message: " + exception.getMessage() );
System.out.println ("Error code: " + exception.getErrorCode() );
exception = exception.getNextException ();
System.out.println ( "" );
}
}
catch ( java.lang.Exception exception ) {
exception.printStackTrace();
}
}
Save it.
In the java4_Lesso n11 pro ject, create a Use rInt e rf ace class as sho wn:
package db;
import java.sql.*;
import java.util.*;
if ( command.charAt(0) == 'A' )
{
System.out.println ("Enter name: ");
String name = in.nextLine();
System.out.println ("Enter phone number: ");
String phoneNumber = in.nextLine();
database.addEntry (name, phoneNumber); // Add this entry to the
database.
}
}
}
}
Save it.
The st art () metho d o f the class has a lo o p that starts with while (t rue ). This allo ws the applicatio n to stay
o pen fo r co ntinuo us input until the user finishes. After each user input, the lo o p perfo rms the specified actio n
and then returns to pro mpt again.
Edit the Pho ne Bo o k class to instantiate and start this interface as sho wn in blue :
CODE TO EDIT: Pho neBo o k
package db;
Save and run it. Make sure to click in the Co nso le so yo ur input go es there.
Except fo r the red line po inting to the Terminate butto n, yo u'll see this (the gre e n text is o ur sample input):
Run Pho ne Bo o k again to see ano ther reaso n that an applicatio n must always clo se its o pen co nnectio ns
and pro cesses:
The first statement that we execute after getting o ur co nnectio n is:
st at e m e nt .e xe cut e (" cre at e t able Pho ne Bo o k (Nam e varchar (32), Pho ne Num be r varchar (18)
);" );
Specifically, we execute a statement to create a table named Pho ne Bo o k in the database. So , when we run it
the seco nd time, after terminating witho ut pro per pro cedure, we are trying to create a table that is already
there. We have two ways aro und this pro blem: either avo id re-creating the table every time we access the
database or remo ve the table when finished with the demo nstratio n.
In the pro ject fo r this lesso n, yo u'll need to fix the pro blem so that we can sto p o ur pro gram with so me dignity.
Additional Resources
Here are so me additio nal items yo u can read to learn abo ut Java and database co nnectivity.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Databases and Java: Processing Information
Getting Results
In this lesso n, we'll add metho ds to o ur co de that will allo w us to :
We used an instance st at e m e nt o f St at e m e nt to execute a CREAT E and INSERT . This co urse uses the
technique that uses JDBC, but info rmatio n can be inserted into a table in any o f these ways:
Altho ugh we've o nly created o ne table in o ur example, we can add and manipulate any number o f tables
using the same techniques. Fo r instance, we can J OIN related data fro m multiple tables. Ho wever, in this
lesso n, we'll co ntinue to use o ur simple example and start the pro cedure fo r retrieving info rmatio n.
The JDBC returns results fro m a St at e m e nt 's query in a Re sult Se t o bject, so we need an instance o f the
Re sult Se t interface to ho ld o ur results. The Re sult Se t interface pro vides metho ds fo r retrieving and
manipulating the results o f queries; particularly, it pro vides getter metho ds (such as ge t Bo o le an() and
ge t Lo ng()) fo r retrieving co lumn values fro m the current ro w.
Fo r specifics and examples, see the Oracle tuto rial Relatio nal Database Overview.
ResultSet
A Re sult Se t is the table o f results fro m yo ur query. This table can have o ne o r mo re ro ws. Yo u need to
manipulate these results to get the info rmatio n yo u want fro m the table. Altho ugh we usually lo o k at a table as
a two -dimensio nal array, the JDBC pro vides the Re sult Se t to manipulate this array to extract whatever
info rmatio n yo u need. We'll go o ver so me examples in this lesso n and the next, but the Oracle tuto rial is
always a go o d so urce fo r mo re info rmatio n: Retrieving Values fro m Result Sets—and o f co urse, the API.
Go to the java.sql.Re sult Se t interface and read the intro ductio n.
Metadata
metaknowledge is kno wledge abo ut kno wledge.
metalanguage is a language abo ut languages.
metatheory is the theo ry abo ut theo ries.
metadata is data abo ut data.
Go to the java.sql package. Scro ll thro ugh the Int e rf ace Sum m ary. We see so me interesting names:
DatabaseMetaData
ParameterMetaData
ResultSetMetaData
These interfaces can be instantiated by instances o f the o bjects that help identify the data. Let's take a lo o k at
a metho d that illustrates this idea.
In the java4_Lesso n11 Pro ject, edit Dat abase Manage r as sho wn in blue :
CODE TO EDIT: DatabaseManager
package db;
import java.sql.*;
statement = connection.createStatement();
statement.execute ("create table PhoneBook (Name varchar (32), Phone
Number varchar (18) );"); // create a table in the database
}
catch (SQLException exception ) {
System.out.println ("\n*** SQLException caught ***\n");
while (exception != null)
{
// tell us the problem
System.out.println ("SQLState: " + exception.getSQLState() )
;
System.out.println ("Message: " + exception.getMessage() )
;
System.out.println ("Error code: " + exception.getErrorCode() )
;
exception = exception.getNextException ();
System.out.println ( "" );
}
}
catch ( java.lang.Exception exception ) {
exception.printStackTrace();
}
}
Save and run it (fro m Pho ne Bo o k). Yo u'll see so mething like this:
Even tho ugh yo u may exit the applicatio n by clicking the red T e rm inat e square, yo u sho uld also either
"Remo ve Launch" (single X) o r "Remo ve All Terminated Launches" by clicking the do uble X:
In databases, when a query returns a Re sult Se t , it is returning a table o f data. Re sult Se t s are used to
retrieve data so that it can be manipulated. Suppo se yo u want to lo o p thro ugh the data to find so mething, but
yo u do n't kno w ho w many ro ws o r co lumns o f data exist, so yo u do n't kno w ho w many times to lo o p. This
wo uld be a perfect time to use Re sult Se t Me t aDat a.
Creating a T able
If o ne do esn't exist already, we'll create a new Pho ne Bo o k table. By do ing this, we wo n't need to dro p the
database table; we can keep the info rmatio n we have just submitted in it fo r the next time we access it. We'll
use bo th the Re sult Se t and the Re sult Se t Me t aDat a interfaces.
In the java4_Lesso n11 Pro ject, edit Dat abase Manage r as sho wn in blue belo w:
CODE TO EDIT: DatabaseManager
package db;
import java.sql.*;
try {
// Establish the database connection, create a statement for execution of SQL
commands.
connection = DriverManager.getConnection (url, username, password );
// username and password are passed into this Constructor
statement = connection.createStatement();
DatabaseMetaData aboutDB = connection.getMetaData ();
// do more useful things with the meta class
String [] tableType = {"TABLE"};
ResultSet rs = aboutDB.getTables(null, null, "PhoneBook", tableType
); // for more info about this method, see the getTables method in DatabaseMeta
Data in the API
if (!inspectForTable(rs))
// use this method (written below) to see if we already have the table PhoneB
ook
statement.execute ("create table PhoneBook (Name varchar (32), Phon
eNumber varchar (18) );"); // if we do NOT already have one, we want to do this
rs.close();
// in this example, the ResultSet is local, so close it here
}
catch (SQLException exception ) {
System.out.println ("\n*** SQLException caught ***\n");
while (exception != null)
{
// tell us the problem
System.out.println ("SQLState: " + exception.getSQLState() )
;
System.out.println ("Message: " + exception.getMessage() )
;
System.out.println ("Error code: " + exception.getErrorCode() )
;
exception = exception.getNextException ();
System.out.println ( "" );
}
}
catch ( java.lang.Exception exception ) {
exception.printStackTrace();
}
}
Save and run it (fro m Pho ne Bo o k). Terminate it and run it again. The SQL Exceptio n alerting yo u to an
existing table sho uld no lo nger appear. We've added a few extra print lns in o ur co de so we can o bserve
what's been returned. We can remo ve them later.
Closing Properly
In the o bjective fo r the last lesso n, yo u added a metho d to clo se (). We'll include it here to o , but we'll also give the user
the o ptio n to either keep the info rmatio n o r dro p the table.
import java.sql.*;
try { // Establish
the database connection, create a statement for execution of SQL commands.
connection = DriverManager.getConnection (url, username, password ); // us
ername and password are passed into this Constructor
statement = connection.createStatement();
}
catch (SQLException exception ) {
System.out.println ("\n*** SQLException caught ***\n");
while (exception != null)
{ /
/ tell us the problem
System.out.println ("SQLState: " + exception.getSQLState() );
System.out.println ("Message: " + exception.getMessage() );
System.out.println ("Error code: " + exception.getErrorCode() );
exception = exception.getNextException ();
System.out.println ( "" );
}
}
catch ( java.lang.Exception exception ) {
exception.printStackTrace();
}
}
Save it.
No w we need to acco mmo date the o ptio n in the user interface. In the java4_Lesso n11 pro ject, edit Use rInt e rf ace as
sho wn in blue :
CODE TO EDIT: UserInterface
package db;
import java.sql.*;
import java.util.*;
if (command.charAt(0) == 'A')
{
System.out.println ("Enter name: ");
String name = in.nextLine();
System.out.println ("Enter phone number: ");
String phoneNumber = in.nextLine();
database.addEntry (name, phoneNumber); // Add this entry to the databa
se.
}
else if (command.charAt(0) == 'K')
{
System.out.println("Bye");
database.close(false); // The user entered the quit command, but d
oes not want to delete info.
return;
}
else if (command.charAt(0) != 'Q')
{
System.out.println ("Invalid command. Please enter either A, K, or Q.")
;
}
else // com
mand is Q
{
System.out.println("Bye");
database.close(true); // Th
e user entered the quit command, so shutdown the database and return.
return;
}
}
}
}
Save and run it (fro m Pho ne Bo o k). Exit with K to Keep the table. Run it again.
import java.sql.*;
try { //
Establish the database connection, create a statement for execution of SQL commands.
connection = DriverManager.getConnection (url, username, password ); //
username and password are passed into this Constructor
statement = connection.createStatement();
if (!inspectForTable (rs)) //
use this method to see if we already have the table PhoneBook
statement.execute ("create table PhoneBook (Name varchar (32), PhoneNum
ber varchar (18) );"); // if we do NOT already have one, we want to do this
rs.close(); //
in this example, the ResultSet is local - so close it here
}
catch (SQLException exception ) {
System.out.println ("\n*** SQLException caught ***\n");
while (exception != null)
{ /
/ tell us the problem
System.out.println ("SQLState: " + exception.getSQLState() );
System.out.println ("Message: " + exception.getMessage() );
System.out.println ("Error code: " + exception.getErrorCode() );
exception = exception.getNextException ();
System.out.println ( "" );
}
}
catch ( java.lang.Exception exception ) {
exception.printStackTrace();
}
}
}
catch (SQLException exception)
{
System.out.println ("\n*** SQLException caught ***\n");
exception = exception.getNextException();
System.out.println("");
}
}
catch (java.lang.Exception exception )
{
exception.printStackTrace();
}
}
exception = exception.getNextException();
System.out.println("");
}
}
catch(java.lang.Exception exception)
{
exception.printStackTrace();
}
}
}
Save it.
We have lo ts o f new additio ns to the DatabaseManager; let's give o ur users mo re capabilities to keep up with tho se
additio ns.
package db;
import java.util.*;
if ( command.charAt(0) == 'A' )
{
System.out.println ("Enter name: ");
String name = in.nextLine();
System.out.println ("Enter phone number: ");
String phoneNumber = in.nextLine();
database.addEntry (name, phoneNumber); // Add this entry to the databa
se.
}
else if (command.charAt(0) == 'D')
{
database.getEntries(); // Query the database for the resultSet
}
else if (command.charAt(0) == 'K' )
{
System.out.println("Bye");
database.close(false); // The user entered the quit comma
nd, but does not want to delete info.
return;
}
else if ( command.charAt(0) != 'Q' )
{
System.out.println ("Invalid command, please enter either A, D, K, or Q
.");
}
else // command is Q
{
System.out.println("Bye");
database.close(true); // The user entered the quit comma
nd, so shutdown the database and return.
return;
}
}
}
}
Note Did yo u no tice the mo dularity here? After adding each metho d, we made a mino r edit to the user interface.
Save and run it (fro m Pho ne Bo o k.java). Use the D o ptio n to see all the entries that may be there already. Type Q
to Quit--this calls the clo se () metho d o f Dat abase Manage r, which dro ps the table and clo ses all o pen co nnectio ns
to the database.
Run it again. Since it was clo sed pro perly, there sho uldn't be any erro rs. Use the D o ptio n to see that all o f the entries
were remo ved. Add a few new entries and try the D co mmand again. Exit with the K o ptio n. In fact, try bo th the Q and K
o ptio ns until yo u feel co nfident that they behave as expected.
SQL Commands
Lo o k o ver the co de in this Observe bo x:
package db;
import java.sql.*;
We've remo ved all o f the t ry/cat ch clauses and Syst e m .o ut .print ln statements to sho w what's left o f the
Dat abase Manage r (o ther than the Meta questio ns). Yo u might be tempted to try to pro gram database applicatio ns
witho ut all o f tho se try/catch clauses, but that wo uld make yo ur applicatio n unstable and, fo r all intents and purpo ses,
unusable. In fact, Java wo n't even let yo u do it. SQLExce pt io ns are no t Runt im e Exce pt io ns and therefo re must be
handled.
We used a wild card (*) in the SELECT query to retrieve all o f the entries fro m o ur data. Explo re mo re o ptio ns using
SELECT with these reso urces:
Oracle's JDBC Intro ductio n.
Mo re fro m Oracle o n the Statement class metho ds.
The SQL SELECT link fro m Key Data.
One o f many bo o ks available o n SQL.
Logging In
So no w we have a running applicatio n, but what user wants to use the co mmand line to enter co mmands? We'll begin
to fix this pro blem by creating a to o l to lo g in. In the next lesso n, we'll reto o l the who le applicatio n to take advantage o f
the info rmatio n we no w kno w abo ut Swing.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public static void main(String [] args) { // create the frame first and then give
it that frame as owner
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final PasswordDialog addPassword = new PasswordDialog(frame);
addPassword.setVisible(true);
System.exit(0); // terminates
}
}
Save and run it. That's much mo re efficient than go ing into Eclipse frames to set variables. Of co urse, no rmally we
wo uldn't just run a Lo gin Dialo g and sto p there, so the m ain() metho d might seem a little weird as it is.
Let's add a metho d to access the Passwo rdDialo g fro m o ther classes, and change it so it do esn't print the username
and passwo rd.
This example do es no t address security issues--it simply passes the info rmatio n as elements in an
Note array.
package db;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public static void main(String [] args){ // create the frame first and then give i
t that frame as owner
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final PasswordDialog addPassword = new PasswordDialog(frame);
addPassword.setVisible(true);
}
Save it. No w, let's link it to o ur database. Edit Pho ne Bo o k as sho wn in blue belo w:
package db;
public PhoneBook(){
String [] info = PasswordDialog.login(this); // st
atic login so can call from class
DatabaseManager databaseManager = new DatabaseManager(info[0], info[1]); // Cr
eate the database manager and pass login info.
UserInterface userInterface = new UserInterface(databaseManager ); // Cr
eate access for user input
userInterface.start();
}
Fo r o ther examples o f impro ved lo gin dialo gs, see Swing Co mpo nents and Oracle's Java Lo o k and Feel Design
Guidelines bo o k (bo th are co pyright-pro tected so we can't pro vide the co de fo r them here).
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Database Application With GUI
Cre at ing a dat abase : create the database o utside o f Java, with to o ls supplied by the database vendo r, o r
with SQL statements fed to the database fro m a Java pro gram.
Co nne ct ing t o a dat a so urce : use a bridge to co nnect to the data so urce. (yo u can learn ho w to co nnect
to databases o n Windo ws machines using the JDBC/ODBC Bridge.)
Inse rt ing inf o rm at io n int o a dat abase : either enter data o utside o f Java, using database-specific to o ls,
o r with SQL statements sent by a Java pro gram.
Se le ct ive ly re t rie ving inf o rm at io n: use SQL co mmands fro m Java to get results and then use Java to
display o r manipulate that data.
1. create the database table using SQL that was written into the applicatio n initially to po pulate a table.
2. pro vide the user with a graphical user interface that:
has a graphical display.
allo ws users to search the table fo r desired entries.
allo ws users to edit the database table (add and delete).
Co py the Passwo rdDialo g class fro m the previo us Pro ject (java4_Lesso n11) and paste it into the
java4_Lesso n13 pro ject, greenDB package.
Open the new co py o f Passwo rdDialo g in the edito r to verify that it co ntains package gre e nDB.
Save and run it. We aren't running it fro m ano ther applicatio n, we're just checking the Lo gin dialo g itself.
As yo u type this class, yo u may no tice so me mino r changes. Fo r example, so me variable and metho d
names have been changed.
The inspe ct Fo rT able () metho d has been made mo re general; it passes the name o f the table yo u are
lo o king fo r rather than having it hard-co ded. This is always a better cho ice fo r reusable co de.
In the java4_Lesso n13 pro ject, create a Dat abase Manage r class as sho wn. (Because it is in a different
package, it can have the same name as the class used in previo us lesso ns):
Type Dat abase Manage r as sho wn in blue :
CODE TO TYPE: DatabaseManager
package greenDB;
import java.sql.*;
try {
// Connect to the database.
// Give the whole URL as a parameter rather than using a variable
conn = DriverManager.getConnection("jdbc:mysql://sql.useractive.com:
3306/" + username, username, password);
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, Resul
tSet.CONCUR_UPDATABLE); // Create a Statement
// Execute the creation and initialization of table query
DatabaseMetaData aboutDB = conn.getMetaData();
String [] tableType = {"TABLE"};
ResultSet rs = aboutDB.getTables(null, null, "Listings", tableType)
;
if (!inspectForTable (rs, "Listings")) { // Find out if the tabl
e is already there
// there is no table--make it from the initialization listing
String [] SQL = initListingsTable(); // code for this method
is below
for (int i=0; i < SQL.length; i++)
{
stmt.execute(SQL[i]);
}
}
}catch (SQLException e) {
e.printStackTrace();
}
}
public ResultSet getResultSet() { // a new method that will let the GUI get
the resultSet to manipulate it
return rset;
}
try {
if (remove)
stmt.execute ("drop table Listings;");
stmt.close();
conn.close();
}
catch ( SQLException e ) {
System.out.println ("\n*** SQLException caught ***\n");
e.printStackTrace();
}
}
}
We need a class to instantiate and start this applicatio n. We'll create the necessary class, but it wo n't be ready
fo r co nsumptio n until we make the GUI. Please be patient--we need all the ingredients befo re we can co o k!
In the java4_Lesso n13 pro ject, create Sim ple Pho ne Bo o k as sho wn:
import javax.swing.JFrame;
Even tho ugh there are erro rs, save it. The erro rs are there because we haven't defined the GUI and its
co mpo nents yet.
Click here to see what the Pho neBo o kFrame will lo o k like, so yo u can co mpare the co de and the GUI as yo u write the
co de.
In the java4_Lesso n13 pro ject, create a Pho ne Bo o kFram e class as sho wn:
Type Pho ne Bo o kFram e as sho wn in blue :
CODE TO TYPE: Pho neBo o kFrame
package greenDB;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
public PhoneBookFrame() {
String [] info = PasswordDialog.login(this); // static login so can call from
class
// create and initialize the listings table
myDB = new DatabaseManager(info[0], info[1]);
// should have access so make GUI
JButton getButton = new JButton("Get"); // get the listing
JButton add = new JButton("+"); // add a listing
JButton rem = new JButton("-"); // remove a listing
JLabel space = new JLabel(" ");
// set the window size and title
setTitle("Simple Phone Book");
setSize(WIDTH, HEIGHT);
// if user presses Enter, get button pressed
getRootPane().setDefaultButton(getButton);
// create the panel for looking up listing
JPanel south = new JPanel();
south.setLayout(new FlowLayout(FlowLayout.LEFT));
south.add(new JLabel("Last:"));
south.add(lNameField);
south.add(new JLabel(" First:"));
south.add(fNameField);
south.add(new JLabel(" Phone: ("));
south.add(areaCodeField);
south.add(new JLabel(") "));
south.add(prefixField);
south.add(new JLabel("-"));
south.add(suffixField);
south.add(new JLabel(" "));
south.add(getButton);
// create the panel for adding and deleting listings
JPanel east = new JPanel();
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
east.setLayout(gb);
add.setFont(new Font("SansSerif", Font.BOLD, 12));
rem.setFont(new Font("SansSerif", Font.BOLD, 12));
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(add, gbc);
gb.setConstraints(space, gbc);
gb.setConstraints(rem, gbc);
east.setLayout(gb);
east.add(add);
east.add(space);
east.add(rem);
// when the UI first displays, do an empty lookup so the center panel doesn't l
ook funny
getButton.doClick();
lNameField.requestFocus(); // set focus to last name field (most common lookup
)
}
Terminate the current running pro cess fro m the co nso le. Right-click the java4 _Le sso n13 Pro ject and select Build
Pat h | Add Ext e rnal Archive s to o pen the file bro wser so yo u can get the driver. cho o se Build Pat h | Add
Ext e rnal Archive s, which o pens the file bro wser fo r yo u to get the driver. Again, in the file dialo g, start to type the path
C:\jdbc\m ysql-co nne ct o r-java-5 .1.5 -bin.jar. The auto -co mplete feature sho uld allo w yo u to press Tab to fill in the
file name m ysql-co nne ct o r-java-5 .1.5 -bin.jar. Then, click Ope n.
We've made a nice little user interface here, but it may no t seem that impressive yet because we have no t added
listeners. So far, the o nly co mpo nent o n the Pho ne Bo o kFram e that listens at all is the Windo w. At least we can clo se
it.
Clo se the Windo w by clicking the X in the upper right co rner o f the applicatio n windo w.
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
public PhoneBookFrame() {
String [] info = PasswordDialog.login(this); // static login so can call from
class
// create and initialize the listings table
myDB = new DatabaseManager(info[0], info[1]);
// Should have access so make GUI
JButton getButton = new JButton("Get"); // get the listing
JButton add = new JButton("+"); // add a listing
JButton rem = new JButton("-"); // remove a listing
JLabel space = new JLabel(" ");
// set the window size and title
setTitle("Simple Phone Book");
setSize(WIDTH, HEIGHT);
// if user presses enter, get button pressed
getRootPane().setDefaultButton(getButton);
// create the panel for looking up listing
JPanel south = new JPanel();
south.setLayout(new FlowLayout(FlowLayout.LEFT));
south.add(new JLabel("Last:"));
south.add(lNameField);
south.add(new JLabel(" First:"));
south.add(fNameField);
south.add(new JLabel(" Phone: ("));
south.add(areaCodeField);
south.add(new JLabel(") "));
south.add(prefixField);
south.add(new JLabel("-"));
south.add(suffixField);
south.add(new JLabel(" "));
south.add(getButton);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(add, gbc);
gb.setConstraints(space, gbc);
gb.setConstraints(rem, gbc);
east.setLayout(gb);
east.add(add);
east.add(space);
east.add(rem);
// Add listeners
// When the application closes, drop the Listings table and close the connectio
n to MySQL
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent wEvent) {
myDB.close(false);
}
});
// Replace any single quote chars w/ space char or SQL will think the ' is
the end of the string
last = last.replace('\'', ' ');
first = first.replace('\'', ' ');
ac = ac.replace('\'', ' ');
pre = pre.replace('\'', ' ');
sfx = sfx.replace('\'', ' ');
// Get rid of the last result displayed if there is one
if(scrollPane != null)
getContentPane().remove(scrollPane);
// Only execute the query if one or more fields have data, else just displa
y an empty table
if(last.length() > 0 ||
first.length() > 0 ||
ac.length() > 0 ||
pre.length() > 0 ||
sfx.length() > 0) {
// build the query and execute it. Provide the results to the table mod
el
myDB.doGetQuery(buildQuery(last, first, ac, pre, sfx));
ResultSet rset = myDB.getResultSet();
tblModel = new ListingsTableModel(rset);
table = new JTable(tblModel);
} else {
table = new JTable();
}
// Allows the user to only delete one record at a time
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Add the table with the results to the contentPane and display it.
scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
doLayout();
}
public String buildQuery(String last, String first, String ac, String pre, Stri
ng sfx) {
String whereClause = " where";
// Build the where clause
if(last.length() > 0)
whereClause += (" LAST_NAME = '" + last + "'");
if(first.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" FIRST_NAME = '" + first + "'");
}
if(ac.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" AREA_CODE = '" + ac + "'");
}
if(pre.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" PREFIX = '" + pre + "'");
}
if(sfx.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" SUFFIX = '" + sfx + "'");
}
We've go t a few erro rs, all referring to a List ingT able sMo de l. We need to define this List ingT able sMo de l so that
o ur GUI can display o ur entries in a table fo rmat.
In the java4_Lesso n13 pro ject, create a List ingsT able Mo de l class as sho wn:
Type List ingsT able Mo de l as sho wn in blue :
CODE TO TYPE: ListingsTableMo del
package greenDB;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.swing.table.AbstractTableModel;
} catch (SQLException e) {
e.printStackTrace();
return "";
}
}
last ()
ge t Ro w()
ge t Me t aDat a()
abso lut e (int )
ge t Obje ct (int )
Go back to the Pho ne Bo o kFram e class and its Instance Variables and unco mment the co de that declares the
ListingsTableMo del, as sho wn in blue :
CODE TO EDIT: Pho neBo o kFrame
package greenDB;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
public PhoneBookFrame() {
String [] info = PasswordDialog.login(this); // static login so can call from
class
// create and initialize the listings table
myDB = new DatabaseManager(info[0], info[1]);
// should have access so make GUI
JButton getButton = new JButton("Get"); // get the listing
JButton add = new JButton("+"); // add a listing
JButton rem = new JButton("-"); // remove a listing
JLabel space = new JLabel(" ");
// set the window size and title
setTitle("Simple Phone Book");
setSize(WIDTH, HEIGHT);
// if user presses Enter, get button pressed
getRootPane().setDefaultButton(getButton);
// create the panel for looking up listing
JPanel south = new JPanel();
south.setLayout(new FlowLayout(FlowLayout.LEFT));
south.add(new JLabel("Last:"));
south.add(lNameField);
south.add(new JLabel(" First:"));
south.add(fNameField);
south.add(new JLabel(" Phone: ("));
south.add(areaCodeField);
south.add(new JLabel(") "));
south.add(prefixField);
south.add(new JLabel("-"));
south.add(suffixField);
south.add(new JLabel(" "));
south.add(getButton);
// create the panel for adding and deleting listings
JPanel east = new JPanel();
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
east.setLayout(gb);
add.setFont(new Font("SansSerif", Font.BOLD, 12));
rem.setFont(new Font("SansSerif", Font.BOLD, 12));
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(add, gbc);
gb.setConstraints(space, gbc);
gb.setConstraints(rem, gbc);
east.setLayout(gb);
east.add(add);
east.add(space);
east.add(rem);
// when the UI first displays, do an empty lookup so the center panel doesn't l
ook funny
getButton.doClick();
lNameField.requestFocus(); // set focus to
last name field (most common lookup)
}
// Replace any single quote chars w/ space char or SQL will think the ' is
the end of the string
last = last.replace('\'', ' ');
first = first.replace('\'', ' ');
ac = ac.replace('\'', ' ');
pre = pre.replace('\'', ' ');
sfx = sfx.replace('\'', ' ');
// Get rid of the last result displayed if there is one
if(scrollPane != null)
getContentPane().remove(scrollPane);
// Only execute the query if one or more fields have data, else just displa
y an empty table
if(last.length() > 0 ||
first.length() > 0 ||
ac.length() > 0 ||
pre.length() > 0 ||
sfx.length() > 0) {
// build the query and execute it. Provide the results to the table mod
el
myDB.doGetQuery(buildQuery(last, first, ac, pre ,sfx));
ResultSet rset = myDB.getResultSet();
tblModel = new ListingsTableModel(rset);
table = new JTable(tblModel);
} else {
table = new JTable();
}
// Allows the user to only delete one record at a time
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Add the table with the results to the contentPane and display it.
scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
doLayout();
}
public String buildQuery(String last, String first, String ac, String pre, Stri
ng sfx) {
String whereClause = " where";
// Build the where clause
if(last.length() > 0)
whereClause += (" LAST_NAME = '" + last + "'");
if(first.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" FIRST_NAME = '" + first + "'");
}
if(ac.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" AREA_CODE = '" + ac + "'");
}
if(pre.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" PREFIX = '" + pre + "'");
}
if(sfx.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" SUFFIX = '" + sfx + "'");
}
Once List ingsT able Mo de l is saved and its variable declared (unco mmented) in Pho ne Bo o kFram e , yo ur
pro grams sho uld be free o f erro rs, at least fo r the mo ment.
Run it (fro m Sim ple Pho ne Bo o k). Type J o hn in the First Name text field.
Click Ge t to display o ur database table entries that have a first name o f J o hn:
While yo u're there, no tice the area co des in the pho ne numbers. The o ther text fields are listening as well. Keep J o hn
in the First Name text field, and type 7 0 7 in the Pho ne ( ) area co de field. Press Ent e r to display o ur database table
entries that have a first name o f J o hn and a pho ne area co de o f 7 0 7 :
Isn't that co o l? We're o n a ro ll! No w let's inco rpo rate the o ther listeners.
In the java4_Lesso n13 pro ject, add a Pho ne Do cum e nt List e ne r class as sho wn:
Type Pho ne Do cum e nt List e ne r as sho wn in blue :
CODE TO TYPE: Pho neDo cumentListener
package greenDB;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
Save it.
In the java4_Lesso n13 pro ject, create Pho ne Fo cusList e ne r as sho wn:
Type Pho ne Fo cusList e ne r as sho wn in blue :
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JTextField;
/** an event generated as a result of focus being gained on this telephone number f
ield. */
public void focusGained(FocusEvent fEvent) {
JTextField tf = (JTextField)fEvent.getSource();
tf.setText("");
}
We need to add these listeners to o ur Pho ne Bo o kFram e . While we're there, we'll also add the listeners fo r the add
(+) and remo ve (-) butto ns to the JFrame.
package greenDB;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
public PhoneBookFrame() {
String [] info = PasswordDialog.login(this); // static login so can call from
class
// create and initialize the listings table
myDB = new DatabaseManager(info[0], info[1]);
// Should have access so make GUI
south.add(new JLabel("Last:"));
south.add(lNameField);
south.add(new JLabel(" First:"));
south.add(fNameField);
south.add(new JLabel(" Phone: ("));
south.add(areaCodeField);
south.add(new JLabel(") "));
south.add(prefixField);
south.add(new JLabel("-"));
south.add(suffixField);
south.add(new JLabel(" "));
south.add(getButton);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(add, gbc);
gb.setConstraints(space, gbc);
gb.setConstraints(rem, gbc);
east.setLayout(gb);
east.add(add);
east.add(space);
east.add(rem);
// Add listeners
// When the application closes, drop the Listings table and close the connectio
n to MySQL
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent wEvent) {
myDB.close(false);
}
});
areaCodeField.addFocusListener(new PhoneFocusListener());
areaCodeField.getDocument().addDocumentListener(new PhoneDocumentListener(areaC
odeField, 3));
prefixField.addFocusListener(new PhoneFocusListener());
prefixField.getDocument().addDocumentListener(new PhoneDocumentListener(prefixF
ield, 3));
suffixField.addFocusListener(new PhoneFocusListener());
suffixField.getDocument().addDocumentListener(new PhoneDocumentListener(suffixF
ield, 4));
// remove (-) listener--delete the highlighted listing from the result set and
database
rem.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
try {
int selected = table.getSelectedRow();
ResultSet rset = myDB.getResultSet();
if(selected != -1 && selected < tblModel.getRowCount()) {
rset.absolute(table.getSelectedRow() + 1);
rset.deleteRow();
table.repaint();
table.clearSelection();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
});
// Replace any single quote chars w/ space char or SQL will think the ' is
the end of the string
last = last.replace('\'', ' ');
first = first.replace('\'', ' ');
ac = ac.replace('\'', ' ');
pre = pre.replace('\'', ' ');
sfx = sfx.replace('\'', ' ');
// Get rid of the last result displayed if there is one
if(scrollPane != null)
getContentPane().remove(scrollPane);
// Only execute the query if one or more fields have data, else just displa
y an empty table
if(last.length() > 0 ||
first.length() > 0 ||
ac.length() > 0 ||
pre.length() > 0 ||
sfx.length() > 0) {
// build the query and execute it. Provide the results to the table mod
el
myDB.doGetQuery(buildQuery(last, first, ac, pre ,sfx));
ResultSet rset = myDB.getResultSet();
tblModel = new ListingsTableModel(rset);
table = new JTable(tblModel);
} else {
table = new JTable();
}
// Allows the user to only delete one record at a time
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Add the table with the results to the contentPane and display it.
scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
doLayout();
}
public String buildQuery(String last, String first, String ac, String pre, Stri
ng sfx) {
String whereClause = " where";
// Build the where clause
if(last.length() > 0)
whereClause += (" LAST_NAME = '" + last + "'");
if(first.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" FIRST_NAME = '" + first + "'");
}
if(ac.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" AREA_CODE = '" + ac + "'");
}
if(pre.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" PREFIX = '" + pre + "'");
}
if(sfx.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" SUFFIX = '" + sfx + "'");
}
There's o nly o ne erro r; we might have expected it--we didn't define the AddList ingList e ne r.
In the java4_Lesso n13 pro ject, add the AddList ingList e ne r class as sho wn:
Type AddList ingList e ne r as sho wn in blue :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
In the java4_Lesso n13 pro ject, add an AddList ingDialo g class as sho wn:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
// Create the center panel which contains the fields for entering the new listi
ng
JPanel center = new JPanel();
center.setLayout(new GridLayout(3, 2));
center.add(new JLabel(" Last Name:"));
center.add(lNameField);
center.add(new JLabel(" First Name:"));
center.add(fNameField);
// Here we create a panel for the phone number fields and add it to the center
panel.
JPanel pnPanel = new JPanel();
pnPanel.add(new JLabel("("));
pnPanel.add(areaCodeField);
pnPanel.add(new JLabel(") "));
pnPanel.add(prefixField);
pnPanel.add(new JLabel("-"));
pnPanel.add(suffixField);
center.add(new JLabel(" Phone Number:"));
center.add(pnPanel);
areaCodeField.getDocument().addDocumentListener(new PhoneDocumentListener(areaC
odeField, 3));
prefixField.getDocument().addDocumentListener(new PhoneDocumentListener(prefixF
ield, 3));
suffixField.getDocument().addDocumentListener(new PhoneDocumentListener(suffixF
ield, 4));
areaCodeField.addFocusListener(new PhoneFocusListener());
prefixField.addFocusListener(new PhoneFocusListener());
suffixField.addFocusListener(new PhoneFocusListener());
cancelButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
dispose();
}
});
// Replace any single quote chars with a space char so the string will not get
truncated by SQL
last = last.replace('\'', ' ');
first = first.replace('\'', ' ');
ac = ac.replace('\'', ' ');
pre = pre.replace('\'', ' ');
sfx = sfx.replace('\'', ' ');
addButton.setEnabled(true);
if(dEvent.getDocument() == suffixField.getDocument()) {
addButton.requestFocus();
getRootPane().setDefaultButton(addButton);
}
}
}
addButton.setEnabled(false);
}
In the Pho ne field, type 314 825 witho ut mo ving the mo use o r using the Tab key--see ho w the "fo cus" mo ves to the
o ther Pho ne field area? That's really co nvenient fo r the user.
No w, click Ge t . The entry that has tho se first 6 digits in the pho ne number is retrieved.
Clear the Pho ne number fields, and in the First name field, type Edgar and press Ent e r.
So there ARE names in o ur table o ther than Jo hn! No w let's add so me entries o f o ur o wn.
Click the AddButto n (+). Type a name in the Last Nam e field. The Add butto n is no t an o ptio n--can yo u see where this
was set in yo ur co de?
Add the remaining info rmatio n into the Add Listing Dialo g Bo x. No te that when all o f the fields have values, Add is
enabled. Click Add no w.
One SQL statement and/o r query do es no t implicitly invo ke o thers. It is up to the pro grammer to tell the
Note applicatio n what to do .
To see yo ur new entry, query fo r it, using the appro priate text field(s).
Play with the GUI. Yo u can cut and paste fro m o ne text field to ano ther and there's co o l ways to o f tabs, etc. And, with
each capability yo u no tice, lo o k at the co de and see ho w it was do ne--o r, if it was inherited, ho w someone (Java?
Swing?) did all the wo rk fo r yo u!
Additional Resources
We've created a go o d applicatio n and learned so me o f the basics o f JDBC. But there's still a lo t mo re o ut there. Here
are a few mo re useful reso urces:
We've illustrated many facets o f JDBC, but lo ts o f additio nal techniques are available. Amo ng o ther tasks, yo u may
want to :
Oracle's JDBC Techno lo gy Guide links to Getting Started with the JDBC API.
JDBC Intro ductio n.
Three nice tuto rials:
Basic Tuto rial: includes JDBC Basics.
Advanced Tuto rial: sho ws deleting and adding ro ws and much mo re.
Ro wSet Tuto rial: useful fo r enterprise applicatio ns.
The next lesso n has additio nal reso urce links fo r SQL and do cumentatio n capabilities, because we want you to write
great Java co de!
Copyright © 1998-2014 O'Reilly Media, Inc.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Documentation: Javadoc, Doc Comments, and
Annotation
Pro grammers estimate that abo ut 70 % o f all pro gramming effo rt go es to ward maintenance. Given this percentage,
alo ng with the likeliho o d that so meday your co de wil be maintained by o thers, yo u want to be sure to do cument yo ur
co de adequately. Fo rtunately, Java makes it easy.
But befo re we create tho se pages, let's add do cumentatio n to the co de that we created in earlier lesso ns. The edits we
make first will no t affect the running o f o ur applicatio n because they'll co nsist o f co mments, no t new co de. The
co mments will co ntain the fo rmat and do cumentatio n tags that will enable us to make beautiful--and accessible--
do cumentatio n.
DatabaseManager
In the java4_Lesso n13 pro ject, greenDB package, edit Dat abase Manage r as sho wn in blue :
CODE TO EDIT: DatabaseManager
package greenDB;
import java.sql.*;
/* DatabaseManager Constructor */
/**
* This constructor connects to the MySQL database at jdbc:mysql://sql.usera
ctive.com:3306.
* It creates instances of Statement and ResultSet that will be used by the
other methods
* in the class. It also checks to see if the Listings table already exists.
If it does, it
* simply returns to the caller. Otherwise, it instantiates the method to cr
eate a table
* called Listings, and then populates the table.
* <pre>
* PRE: MySQL server is available and account for user has been established
.
* The MySQL driver is installed on the client workstation and its loc
ation
* has been defined in CLASSPATH (or for Eclipse, in its Referenced Li
braries).
* Username and password are not null.
* POST: A connection is made and the Listings table is either created and i
nitialized on
* jdbc:mysql://sql.useractive.com:3306, or the already existing Listi
ngs table is
* identified.
* </pre>
*/
public DatabaseManager (String username, String password ) { // the constru
ctor for the database manager
// Connect to database and execute the SQL commands for creating and ini
tializing the Listings table.
try {
Class.forName ("com.mysql.jdbc.Driver"); // Load the MySQL JDBC dri
ver
}
catch (ClassNotFoundException e) {
System.out.println("Failed to load JDBC/ODBC driver.");
e.printStackTrace();
return;
}
/* initListingsTable */
/**
* Creates the Listings table and initializes it with some records. This met
hod connects
* to the MySQL database at jdbc:mysql://sql.useractive.com:3306. It then cr
eates a table
* called Listings and initializes the table with some arbitrary records.
* <pre>
* PRE: True
* POST: SQL String is created for the initial population of a table named L
istings.
* </pre>
*/
private String [] initListingsTable() {
// Executable SQL commands for creating Listings table and inserting ini
tial names and phone numbers.
String[] SQL = {
"create table Listings ("+
"LAST_NAME varchar (16)," +
"FIRST_NAME varchar (16)," +
"AREA_CODE varchar(3)," +
"PREFIX varchar(3)," +
"SUFFIX varchar(4))",
"insert into Listings values ('ANDERSON', 'JOHN', '314', '825',
'1695')",
"insert into Listings values ('CABLES', 'WALLY', '212', '434',
'9685')",
"insert into Listings values ('FRY', 'EDGAR', '415', '542',
'5885')",
"insert into Listings values ('MARTIN', 'EDGAR', '665', '662',
'9001')",
"insert into Listings values ('TUCKER', 'JOHN', '707', '696',
'8541')",
};
return SQL;
}
/* inspectForTable */
/**
* Determines if a table exists in the db.
* <pre>
* PRE: Connection to database has been established. rs is not null.
* POST: Table has not been changed, but its presence is verified (or not).
* </pre>
* @param rs ResultSet from DatabaseMetaData query about existing Tables
* @param tableName String identifying the table in question
*/
private boolean inspectForTable (ResultSet rs, String tableName) throws SQL
Exception { // exception will be caught when method is used
int i;
ResultSetMetaData rsmd = rs.getMetaData ();
// Get the ResultSetMetaData. This will be used for the col
umn headings
int numCols = rsmd.getColumnCount ();
// Get the number of columns in the result set
/* doGetQuery */
/**
* Executes the select query specified.
* <pre>
* PRE: Connection to database has been established. Query is assigned and
is a simple
* select statement against the Listings table.
* POST: The query is executed.
* </pre>
* @param query a simple select query against the Listings table
*/
public void doGetQuery(String query) {
// rather than the "getEntries" of the previous example
try {
rset = stmt.executeQuery(query);
} catch (SQLException e) {
e.printStackTrace();
}
}
/* doInsertQuery */
/**
* Executes an insert statement, specified by query.
* <pre>
* PRE: Connection to database has been established. Query is assigned and
is a simple
* insert statement into the Listings table.
* POST: The query is executed.
* </pre>
* @param query a simple insert query into the Listings table
*/
public void doInsertQuery(String query) { // rather than the hard-coded "a
ddEntry" of the previous example
try {
stmt.executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
}
/* getResultSet */
/**
* Returns the current value of the ResultSet instance
* <pre>
* PRE: True
* POST: ResultSet instance value is returned, its value remains the same as
upon entry.
* </pre>
*/
public ResultSet getResultSet() { // a new method that will let the GUI get
the resultSet to manipulate it
return rset;
}
/* close */
/**
* Closes opened Statements and the Connection.
* <pre>
* PRE: Connection to database has been established. Statement has been cre
ated. Listings is a table in the db
* POST: If remove is true, table Listings is dropped, otherwise it is prese
rved. Open Connection and Statement are closed
* </pre>
* @param remove boolean to specify if the table Listings should be dropped
or not.
*/
public void close(boolean remove){
// closes all open connections
try {
if (remove)
stmt.execute ("drop table Listings;");
stmt.close();
conn.close();
}
catch ( SQLException e ) {
System.out.println ("\n*** SQLException caught ***\n");
e.printStackTrace();
}
}
}
Save it.
Creating Javadocs
In the to p Eclipse Menu Bar, select Pro je ct | Ge ne rat e J avado c...:
In the Generate Javado c windo w, use the Co nf igure ... butto n to get to the C:\jdk\bin\ directo ry. Cho o se
javado c.e xe to retrieve the javado c executable co de. The default sho uld remain Privat e ; this allo ws us to
view all members (private, package, pro tected and public). Keep the Destinatio n as it is, so that the resulting
Javado c will be lo cated with the Pro ject. Click Finish:
In the Update Javado c Lo catio n dialo g bo x that appears, yo u're given the o ptio n to cho o se Javado c lo catio n
as the destinatio n fo lder. Click Ye s:
The co nso le displays the actio ns taking place and then displays a new do c fo lder in the java4_Lesso n13
Pro ject:
Open the do c fo lder and its gre e nDB subfo lder, then do uble-click o n Dat abase Manage r.ht m l. Scro ll
thro ugh this API page o f the applicatio n and o bserve the way the co mments were printed. There is mo re
do cumentatio n within the Co nst ruct o r Sum m ary and Me t ho d Sum m ary, because we used mo re
co mments in tho se areas than in o thers:
When the Javado c e xe cut able runs, it lo o ks fo r the special co mments that begin with /** and end with */.
When they're written fo r class members (instance and class metho ds and variables), these co mments sho uld
be entered just before the field's definitio n o r declaratio n in yo ur co de.
Note "@" is used to deno te tags that will be created within the API pages.
So me metho ds include the wo rds PRE and POST . These stand fo r preco nditio ns and po stco nditio ns. Such
specificatio ns fo r metho ds are useful fo r the design, implementatio n, and use o f co de:
A PREco nditio n is an assertio n that must be true in o rder fo r the o peratio n to run pro perly. A preco nditio ns o f true (o r
empty) means that there are no stipulatio ns o n running the particular metho d.
A POST co nditio n is an assertio n that prevails upo n co mpletio n o f the o peratio n. Po stco nditio ns describe the results
o f the actio ns perfo rmed by the o peratio n. They must be accurately and precisely stated.
The implementer must make the POST co nditio n is true and co des acco rdingly.
The user assumes it will be exactly and co mpletely true after the co de runs.
We will edit and save each class in o ur database applicatio n, and then run the Javado c executable o n the entire
package when the classes all have Javado c co mments.
SimplePhoneBook
In java4_Lesso n13, edit Sim ple Pho ne Bo o k as sho wn in blue belo w:
import javax.swing.JFrame;
/* class SimplePhoneBook */
/**
* This is the entry point of the SimplePhoneBook application. SimplePhoneBook i
s a Java application
* that uses JDBC to store, retrieve, add, and delete phone number listings in a
MySQL
* database. The SimplePhoneBook class instantiates the application window frame
and displays it
* on screen.
*
* @author David Green
* @version 1.0
*/
public class SimplePhoneBook {
/* main */
/**
* The entry point for the SimplePhoneBook application. The main method inst
antiates the
* application's frame window and displays it.
* <pre>
* PRE:
* POST: SimplePhoneBook started.
* </pre>
* @param args not used.
*/
public static void main(String args[]) {
// Instantiate the phone book frame window and display it.
Save it.
PhoneBookFrame
In java4_Lesso n13, edit Pho ne Bo o kFram e as sho wn in blue belo w:
CODE TO EDIT: Pho neBo o kFrame
package greenDB;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
/* PhoneBookFrame */
/**
* The PhoneBookFrame constructor.
*/
public PhoneBookFrame() {
String [] info = PasswordDialog.login(this); // static login so can cal
l from class
// create and initialize the listings table
myDB = new DatabaseManager(info[0], info[1]);
// Should have access so make GUI
south.add(new JLabel("Last:"));
south.add(lNameField);
south.add(new JLabel(" First:"));
south.add(fNameField);
south.add(new JLabel(" Phone: ("));
south.add(areaCodeField);
south.add(new JLabel(") "));
south.add(prefixField);
south.add(new JLabel("-"));
south.add(suffixField);
south.add(new JLabel(" "));
south.add(getButton);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(add, gbc);
gb.setConstraints(space, gbc);
gb.setConstraints(rem, gbc);
east.setLayout(gb);
east.add(add);
east.add(space);
east.add(rem);
// Add listeners
getButton.addActionListener(new GetListener());
areaCodeField.addFocusListener(new PhoneFocusListener());
areaCodeField.getDocument().addDocumentListener(new PhoneDocumentListene
r(areaCodeField, 3));
prefixField.addFocusListener(new PhoneFocusListener());
prefixField.getDocument().addDocumentListener(new PhoneDocumentListener(
prefixField, 3));
suffixField.addFocusListener(new PhoneFocusListener());
suffixField.getDocument().addDocumentListener(new PhoneDocumentListener(
suffixField, 4));
add.addActionListener(new AddListingListener(this));
// delete the highlighted listing from the result set and database
rem.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
try {
int selected = table.getSelectedRow();
ResultSet rset = myDB.getResultSet();
if(selected != -1 && selected < tblModel.getRowCount())
{
rset.absolute(table.getSelectedRow() + 1);
rset.deleteRow();
table.repaint();
table.clearSelection();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
});
// When the application closes, drop the Listings table and close the co
nnection to MySQL
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent wEvent) {
myDB.close(false);
}
});
// when the ui first displays do an empty lookup so the center panel doe
sn't look funny
getButton.doClick();
lNameField.requestFocus(); // set focus to last name field (most comm
on lookup)
}
/* actionPerformed */
/**
* This method builds a select Query and executes it against the Listings ta
ble to retrieve
* records. This method creates a select string based on what the user has e
ntered in the
* fields for Last Name, First Name, Area Code, Prefix, and Extension. The u
ser may look up a
* record in the Listings table based on any combination of data entered in
the text fields.
* The actionPerformed method builds the query string based on the user's in
put, executes the
* query, and displays it in a scrollable cell format. All data entered in t
he text fields
* is converted to upper case and any single quote character is replaced wit
h a space
* character before the query is executed.
* <pre>
* PRE: A connection to the database has been established. All text fields
can be empty.
* POST: A select string is created based on what was entered, the query is
executed and the
* results are displayed.
* </pre>
* @param aEvent an event generated as a result of the "Get" button being cl
icked
*/
public void actionPerformed(ActionEvent aEvent) {
// Get whatever the user entered, trim any white space and change to
upper case
String last = lNameField.getText().trim().toUpperCase();
String first = fNameField.getText().trim().toUpperCase();
String ac = areaCodeField.getText().trim().toUpperCase();
String pre = prefixField.getText().trim().toUpperCase();
String sfx = suffixField.getText().trim().toUpperCase();
// Replace any single quote chars w/ space char or SQL will think th
e ' is the end of the string
last = last.replace('\'', ' ');
first = first.replace('\'', ' ');
ac = ac.replace('\'', ' ');
pre = pre.replace('\'', ' ');
sfx = sfx.replace('\'', ' ');
// Only execute the query if one or more fields have data, else just
display an empty table
if(last.length() > 0 ||
first.length() > 0 ||
ac.length() > 0 ||
pre.length() > 0 ||
sfx.length() > 0) {
// build the query and execute it. Provide the results to the ta
ble model
myDB.doGetQuery(buildQuery(last, first, ac, pre ,sfx));
ResultSet rset = myDB.getResultSet();
tblModel = new ListingsTableModel(rset);
table = new JTable(tblModel);
} else {
table = new JTable();
}
// Add the table with the results to the contentPane and display it.
scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
doLayout();
}
/* buildQuery */
/**
* This method builds a simple select statement for retrieving records from
the Listings table.
* The select statement is returned as a string. The select statement includ
es the last, first, ac,
* pre, and sfx parameters as the search strings in the where clause of the
select statement.
* If more than one parameter has data, buildQuery will combine them with an
"AND" in the where
* clause.
* <pre>
* PRE: One or more parameters has length > 0.
* POST: A SQL select statement is returned that selects records from the Li
stings table.
* </pre>
* @param last create a SQL query that searches Listings where LAST_NAME =
last.
* @param first create a SQL query that searches Listings where FIRST_NAME =
first.
* @param ac create a SQL query that searches Listings where AREA_CODE =
ac.
* @param pre create a SQL query that searches Listings where PREFIX = pre
.
* @param sfx create a SQL query that searches Listings where SUFFIX = sfx
.
* @return a SQL select statement that selects records from the Listings tab
le
*/
public String buildQuery(String last, String first, String ac, String pr
e, String sfx) {
String whereClause = " where";
// Build the where clause
if(last.length() > 0)
whereClause += (" LAST_NAME = '" + last + "'");
if(first.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" FIRST_NAME = '" + first + "'");
}
if(ac.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" AREA_CODE = '" + ac + "'");
}
if(pre.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" PREFIX = '" + pre + "'");
}
if(sfx.length() > 0) {
if(whereClause.length() > 6)
whereClause += " AND";
whereClause += (" SUFFIX = '" + sfx + "'");
}
Save it.
Note We have an Inner class defined in this class. Remember to check it o ut in the Javado c page!
ListingsT ableModel
In java4_Lesso n13, edit List ingsT able Mo de l as sho wn in blue :
CODE TO EDIT: ListingsTableMo del
package greenDB;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.swing.table.AbstractTableModel;
/* class ListingsTableModel */
/**
* This class provides methods for displaying the results returned from the List
ings
* table. The methods are used by a JTable object so the results may displayed i
n a cell format.
*
* @author David Green
* @version 1.0
*/
public class ListingsTableModel extends AbstractTableModel {
/** The result set from the Listings table to be displayed */
private ResultSet rs;
/* ListingsTableModel */
/**
* The ListingsTableModel constructor.
* @param rs the result set from the Listings table to be displayed.
*/
public ListingsTableModel(ResultSet rs) {
this.rs = rs;
}
/* getRowCount */
/**
* Returns the number of rows in the result set.
* <pre>
* PRE: True
* POST: The number of rows in the result set is returned.
* </pre>
* @return the number of rows in the result set.
*/
public int getRowCount() {
try {
rs.last();
return rs.getRow();
} catch (SQLException e) {
e.printStackTrace();
return 0;
}
}
/* getColumnCount */
/**
* Returns the number of columns to be displayed for the result set. Note th
at
* this does not return the number of columns IN the result set. The three p
hone
* number fields (area code, prefix, and extension) are combined together to
form
* a single column for output. This method always returns 3 for Last Name, F
irst
* Name, and Phone Number.
* <pre>
* PRE: True
* POST: The number 3 is returned.
* </pre>
* @return the number 3, for the three output columns Last Name, First Name,
and Phone Number.
*/
public int getColumnCount() {
return 3;
}
/* getColumnName */
/**
* Returns the name of the column specified by the index.
* <pre>
* PRE: Column is assigned and 0 >= column <= 2.
* POST: A column name is returned.
* </pre>
* @param column the index of the column name to be returned.
* @return the column name specified.
*/
public String getColumnName(int column) {
try {
String colName = rs.getMetaData().getColumnName(column + 1);
// Return column names that look better than the database column nam
es.
// Since getColumnCount always returns 3 we only look for first 3 co
lumns in
// the result set.
if(colName.equals("LAST_NAME"))
return "Last Name";
else if(colName.equals("FIRST_NAME"))
return "First Name";
else if(colName.equals("AREA_CODE"))
return "Phone Number";
else return colName; // Should never get here.
} catch (SQLException e) {
e.printStackTrace();
return "";
}
}
/* getValueAt */
/**
* Returns the value in the result set at the location specified by row and
column. If column
* is equal to 2 (the AREA_CODE), combine the AREA_CODE, PREFIX, and SUFFIX
for that row and
* return the combined string.
* <pre>
* PRE: row and column are assigned and 0 >= column <= 2 and row is within
range.
* POST: The value in the result set at row and column is returned, or the c
ombined
* phone number is returned if column = 2.
* </pre>
* @param row the row of the result set whose value is to be returned.
* @param column the column of the result set whose value is to be returned.
* @return the value in the result set at row and column is returned, or the
combined
* phone number is returned if column = 2.
*/
public Object getValueAt(int row, int column) {
try {
rs.absolute(row + 1);
// for the 3rd column in the results, combine all of the phone numbe
r fields for output
if(column == 2)
return "(" + rs.getObject(column + 1) + ") " + rs.getObject(colu
mn + 2) + "-" + rs.getObject(column + 3);
else
return rs.getObject(column + 1);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
Save it.
phew! This is a lo t o f wo rk. It's wo rth do ing tho ugh to make sure that everyo ne who enco unters o ur co de
understands it, appreciates its elegance and efficiency, and can use and mo dify it as needed. That's the
reaso n we do cument. OK, no w get back to wo rk!
AddListingListener
In java4_Lesso n13, edit AddList ingList e ne r as sho wn in blue :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/* class AddListingListener */
/**
* A listener for when the add button is clicked. The add button looks like a pl
us ("+") sign. The
* AddListingListener creates and displays an AddListingDialog box when actionPe
rformed is called.
*
* @author David Green
* @version 1.0
*/
class AddListingListener implements ActionListener {
/** The SimplePhoneBook application frame */
PhoneBookFrame pbf;
/* AddListingListener */
/**
* The AddListingListener constructor.
* @param pbFrame the SimplePhoneBook application frame object.
*/
public AddListingListener(PhoneBookFrame pbFrame) {
pbf = pbFrame;
}
/* actionPerformed */
/**
* Instantiates and displays the Add Listings Dialog Box. This method is
* called when the "+" button is clicked.
* <pre>
* PRE:
* POST: The Add Listings Dialog Box is displayed on screen.
* </pre>
* @param aEvent an event generated as a result of the "+" button being clic
ked.
*/
public void actionPerformed(ActionEvent aEvent) {
AddListingDialog addDialog = new AddListingDialog(pbf);
addDialog.setVisible(true);
}
}// End AddListingListener class
Save it.
AddListingDialog
In java4_Lesso n13, edit AddList ingDialo g as sho wn in blue belo w:
CODE TO EDIT: AddListingDialo g
package greenDB;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/* class AddListingDialog */
/**
* A dialog box for adding a new listing to the Listings table. The AddListingDi
alog has text
* fields for gathering the new listing's last name, first name, and phone numbe
r. All of the text
* fields are assigned an InputListener, which is responsible for enabling the "
Add" button once
* all fields contain data. This dialog box is displayed when the user clicks th
e "+" button on
* the application frame window.
*
* @author David Green
* @version 1.0
*/
public class AddListingDialog extends JDialog {
/** A text field for entering the new phone listing's last name */
private JTextField lNameField = new JTextField(16);
/** A text field for entering the new phone listing's first name */
private JTextField fNameField = new JTextField(16);
/** A text field for entering the new phone listing's area code */
private JTextField areaCodeField = new JTextField(2);
/** A text field for entering the new phone listing's prefix */
private JTextField prefixField = new JTextField(2);
/** A text field for entering the new phone listing's extension */
private JTextField suffixField = new JTextField(3);
/** A button which, when clicked, will add the new listing to the Listings t
able */
private JButton addButton;
/* AddListingDialog */
/**
* The AddListingDialog constructor. Creates a dialog box for adding a new li
sting to the
* Listings table.
* @param owner the Frame from which the dialog is displayed.
*/
public AddListingDialog(final JFrame owner) {
// set the dialog title and size
super(owner, "Add Listing", true);
setSize(280, 150);
// Create the center panel which contains the fields for entering the ne
w listing
JPanel center = new JPanel();
center.setLayout(new GridLayout(3, 2));
center.add(new JLabel(" Last Name:"));
center.add(lNameField);
center.add(new JLabel(" First Name:"));
center.add(fNameField);
// Here we create a panel for the phone number fields and add it to the
center panel.
JPanel pnPanel = new JPanel();
pnPanel.add(new JLabel("("));
pnPanel.add(areaCodeField);
pnPanel.add(new JLabel(") "));
pnPanel.add(prefixField);
pnPanel.add(new JLabel("-"));
pnPanel.add(suffixField);
center.add(new JLabel(" Phone Number:"));
center.add(pnPanel);
areaCodeField.getDocument().addDocumentListener(new PhoneDocumentListene
r(areaCodeField, 3));
prefixField.getDocument().addDocumentListener(new PhoneDocumentListener(
prefixField, 3));
suffixField.getDocument().addDocumentListener(new PhoneDocumentListener(
suffixField, 4));
areaCodeField.addFocusListener(new PhoneFocusListener());
prefixField.addFocusListener(new PhoneFocusListener());
suffixField.addFocusListener(new PhoneFocusListener());
cancelButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent aEvent) {
dispose();
}
});
/* buildQuery */
/**
* This method builds an insert statement for inserting a new record into th
e Listings table.
* The insert statement is returned as a string. The insert statement will i
nclude the last name,
* first name, area code, prefix, and extension that the user entered in the
add listing dialog
* box.
* <pre>
* PRE: All of the fields in the Add Listing Dialog box contain data.
* POST: A SQL insert statement is returned that inserts a new listing into
the Listings table.
* </pre>
* @return a SQL insert statement that will insert a new listing in the List
ings table.
*/
public String buildQuery() {
// Get the data entered by the user, trim the white space and change to
upper case
String query = "";
String last = lNameField.getText().trim().toUpperCase();
String first = fNameField.getText().trim().toUpperCase();
String ac = areaCodeField.getText().trim().toUpperCase();
String pre = prefixField.getText().trim().toUpperCase();
String sfx = suffixField.getText().trim().toUpperCase();
// Replace any single quote chars with a space char so the string will n
ot get truncated by SQL
last = last.replace('\'', ' ');
first = first.replace('\'', ' ');
ac = ac.replace('\'', ' ');
pre = pre.replace('\'', ' ');
sfx = sfx.replace('\'', ' ');
/* insertUpdate */
/**
* This method is called when data is put in the text field, either by typin
g or by a paste operation.
* This method tracks the number of characters entered in the field. If all
fields, last name,
* first name, area code, prefix, and extension have data and the phone numb
er fields contain the correct
* number of characters (that is, 3 characters for area code and prefix and
4 characters for extension),
* then the Add Listing Dialog box "Add" button is enabled.
* <pre>
* PRE:
* POST: Add Listing Dialog Box "Add" button is enabled if all fields have t
he required number of characters
* entered.
* </pre>
* @param dEvent the document event
*/
addButton.setEnabled(true);
if(dEvent.getDocument() == suffixField.getDocument()) {
addButton.requestFocus();
getRootPane().setDefaultButton(addButton);
}
}
}
/* removeUpdate */
/**
* This method is called when data is removed from the text field, either by
backspacing or highlighting and
* deleting. This method will track the number of characters removed from th
e field. If any of the fields
* last name, first name, area code, prefix, and extension contain less than
the required number of characters
* the "Add" button of the Add Listing Dialog box is disabled.
* <pre>
* PRE:
* POST: Add Listing Dialog Box "Add" button is disabled if any of the field
s contain less than the required
* number of characters.
* </pre>
* @param dEvent the document event
*/
public void removeUpdate(DocumentEvent dEvent) {
// If last name or first name don't have data or phone number
// is not complete, disable the Add button.
if(lNameField.getDocument().getLength() == 0 ||
fNameField.getDocument().getLength() == 0 ||
areaCodeField.getDocument().getLength() < 3 ||
prefixField.getDocument().getLength() < 3 ||
suffixField.getDocument().getLength() < 4 )
addButton.setEnabled(false);
}
Save it.
Note Ano ther Inner class--remember to lo o k fo r this o ne o n the Javado c page to o .
PhoneDocumentListener
In java4_Lesso n13, edit Pho ne Do cum e nt List e ne r as sho wn in blue belo w:
CODE TO EDIT: Pho neDo cumentListener
package greenDB;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/* class PhoneDocumentListener */
/**
* A listener that is applied to any of the telephone number fields (area code,
prefix,
* and extension). The purpose of this listener is to prevent more than the expe
cted number
* of characters from being entered in the telephone number fields. That is, the
area code and
* prefix fields might only be allowed to contain 3 characters each while the ex
tension field
* might only be allowed to contain four characters. The PhoneDocumentListener c
lass accomplishes
* this by accepting a 'numbers allowed' parameter during construction. Every ti
me a character is
* entered in the phone number field to which this listener applies, the insertU
pdate method is
* called. The insertUpdate method checks the number of characters in the field
and if the number
* is equal to 'numbers allowed', focus is transferred to the next component.
*
* @author David Green
* @version 1.0
*/
/* PhoneDocumentListener */
/**
* The PhoneDocumentListener constructor.
* @param tf The phone number text field to which this listener applies.
* @param numsAllowed The number of characters that can be entered in this f
ield.
*/
public PhoneDocumentListener(JTextField tf, int numsAllowed) {
txtField = tf;
this.numsAllowed = numsAllowed;
}
/* insertUpdate */
/**
* Called when a character is typed in the field to which this listener is a
pplied.
* The field is examined for number of characters and if the number is equal
to the
* numbers allowed, as specified during construction, focus is transferred t
o the next
* component.
* <pre>
* PRE:
* POST: Focus is transferred if field length equals numsAllowed; else nothi
ng happens.
* </pre>
* @param dEvent An event generated as a result of a character being entered
in the
* telephone number field to which this listener is applied.
*/
public void insertUpdate(DocumentEvent dEvent) {
if(dEvent.getDocument().getLength() == numsAllowed)
txtField.transferFocus();
}
Save it.
PhoneFocusListener
In java4_Lesso n13, edit Pho ne Fo cusList e ne r as sho wn in blue belo w:
CODE TO EDIT: Pho neFo cusListener
package greenDB;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JTextField;
/* class PhoneFocusListener */
/**
* A listener that will delete any data currently in the telephone number fields
(area code, prefix,
* and extension) whenever focus is detected for those fields. This listener is
used in conjunction with
* the PhoneDocumentListener to prevent more than the expected number of charact
ers from being entered
* in the telephone number fields. That is, the area code and prefix fields will
only be allowed to
* contain three characters each while the extension field will only be allowed
to contain four characters.
*
* @author David Green
* @version 1.0
*/
class PhoneFocusListener implements FocusListener {
/* focusGained */
/**
* Called when the field to which this listener applies gains focus. This me
thod will delete
* any data currently contained in the field.
* <pre>
* PRE: True.
* POST: Any data in the telephone number field to which this listener appli
es is deleted.
* </pre>
* @param fEvent An event generated as a result of focus being gained on thi
s telephone number field.
*/
public void focusGained(FocusEvent fEvent) {
JTextField tf = (JTextField)fEvent.getSource();
tf.setText("");
}
Save it.
T he Package Documentation
All classes sho uld be fine and erro r-free. Remember that the class to start it all was Sim ple Pho ne Bo o k. Select
Sim ple Pho ne Bo o k and run it to verify that all is well. Everything sho uld wo rk the same as befo re; all that we changed
was do cumentatio n.
Select the java4 _Le sso n13 Pro ject so that it is highlighted. In the to p Eclipse Menu Bar, select Pro je ct | Ge ne rat e
J avado c.... In the Ge ne rat e J avado c windo w that o pens, click the Co nf igure ... butto n to get to the directo ry
C:\java\bin. Select javado c.e xe to get the javado c executable co de. Keep the default o f Privat e as it is. This will let
us see all members (private, package, pro tected, and public). Keep the Destinatio n as it is so the do cumentatio n will be
lo cated with the Pro ject. Click Finish.
It's the same pro cess we perfo rmed earlier--we are simply no w making the API html pages fo r all o f the classes. This
time we want to see a listing with links to all o f the classes, so o pen do c | inde x.ht m l.
On your generated do cs index page, click o n the links as yo u wo uld any html page to see yo ur class do cumentatio n. In
fact, lo o k at these pages until yo u see all that is o ffered, and ho w it all relates to the co mments we wro te. Fo r example,
check o ut Pho ne Bo o kFram e .ht m l and AddList ingDialo g.ht m l and lo o k fo r a Ne st e d Class Sum m ary to see
their inner classes. Go o d do cumentatio n makes yo ur wo rk mo re refined and finished.
Additional Resources
We go ne o ver many JDBC elements, but lo ts o f additio nal techniques are available. Fo r example, yo u might want to :
Here are additio nal links to assist yo u with yo ur database applicatio ns:
SQL
Or just go to Go o gle and do a search o n SQL t ut o rial. Our last search go t 149 ,0 0 0 hits--there are LOTS o f tuto rials
o n SQL o ut there! And, o f co urse, fo r tho se who like so mething in their hands, there are lo t s o f bo o ks o n SQL!
J avado c
Oracle's page o n Javado c Techno lo gy, with the Javado c To o l Reference Page
Oracle Develo per Netwo rk Javado c to o l page
Oracle Develo per Netwo rk Ho w to Write Do c Co mments fo r the Javado c To o l page, with a list o f tags
Anno t at io ns
Anno tatio ns lo o k similar to Javado c tags (use o f @) but they are actually a fo rm o f metadata that can be added to Java
so urce co de. Anno tatio ns co mplement Javado c tags. In general, if the markup is intended to affect o r pro duce
do cumentatio n, it sho uld pro bably be a Javado c tag; o therwise, it sho uld be an anno tatio n.
The use o f the "@" symbo l in bo th Javado c co mments and in anno tatio ns is no t co incidental-—they are related
co nceptually. But no te that the Javado c deprecated tag starts with a lo wercase d and the anno tatio n starts with an
uppercase D. We will see them mo re when we lo o k at enterprise applicatio ns. Fo r no w, here are a few reso urces fo r
yo u:
Oracle's Anno tatio n Tuto rial
Anno tatio ns (fro m The Java Programming Language (fro m Enhancements in JDK 5)
If yo u are re ally into it, lo o k up the Anno tatio n Pro cessing To o l.
What's Next?
In the next co urse we will co ntinue o ur wo rk with applicatio ns, but delve into distributed co mputing as well. Everything
yo u learned in this co urse--GUIs, Exceptio ns, Threads, Database Co nnectivity, Do cumentatio n--yo u'll use again.
Yo u're cultivating so me great skills!
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.