We've seen everything we need to build simple interactive applications with Java, now we just need to tie a few things together and make it prettier.
A typical .java file looks something like this:
import packagename.blah.ClassName;
import another.silly.name.Another;
public class NameOfClass implements SomethingListener
{
public SomeClass variable;
public SomeClass another;
public void someMethod(SomeType parameter)
{
Some C-like code.
}
}
It is possible to have a class within a class. It is possible to have a class within a method. However, there are effects of those that are not obvious and can cause strange compile errors, so let's avoid:
public class Thing
{
class Thang
{
}
}
When you're more comfortable with Java, you might find that useful in some situations, but it's very easy to get completely wrong.
So the simplest approach is one class per .java file.
When you create a new project in JCreator, create it as an Empty Project
When you create a new project in JCreator, create it as an Empty Project
When you create a new project in JCreator, create it as an Empty Project
Ok, after that, I have full licence to laugh at anyone who doesn't follow this basic instruction. ;)
When you use JCreator, make sure you view the Build Output as well as the Task List, as it gives more information, but don't be scared.
This is the most common kind of exception, and it is very easy to demonstrate:
public class Main
{
public static void main(String[] args)
{
String s=null;
System.out.println(s.length());
}
}
It's the age-old problem.. how long is a piece of string? You don't know unless you know which String you're talking about. In this case, s holds the value null, which is a special value meaning 'no object'. It would seem that the easiest solution would be to not use the word 'null' in your code. This helps, but it makes the example a bit harder to write:
public class Main
{
public static void main(String[] args)
{
Student student=new Student();
System.out.println(student.name.length());
}
}
And, in a separate file:
public class Student
{
public String name;
}
This still gives a NullPointerException, because name is null. But wait! We haven't used the word null, so why is name null?
All fields (variables declared outside methods) are initialised to some default value before we set them to a valid value. Try this to see what the values are:
public class Main
{
public static void main(String[] args)
{
Dummy dummy=new Dummy();
System.out.println(dummy.object);
System.out.println(dummy.string);
System.out.println(dummy.aBoolean);
System.out.println(dummy.anInt);
System.out.println(dummy.aFloat);
System.out.println(dummy.aDouble);
System.out.println(dummy.aChar);
}
}
And, in a separate file
public class Dummy
{
public Object object;
public String string;
public boolean aBoolean;
public int anInt;
public float aFloat;
public double aDouble;
public char aChar;
}
The important ones, where NullPointerExceptions are concerned, are the null values that you get from object and string above. All non-primitive fields are initialised to null, which can cause you problems when you forget to initialise them.
Here is some sample code from last week (it might not be exact, I didn't copy and paste it):
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
public class Main
{
public static void main(String[] args)
{
JFrame frame=new JFrame();
frame.setSize(400,400);
frame.setLayout(new FlowLayout());
JButton button=new JButton("Click Me!");
frame.add(button);
JLabel label=new JLabel(" ");
frame.add(label);
ButtonListener listener=new ButtonListener();
listener.label=label;
button.addActionListener(listener);
frame.setVisible(true);
}
}
And, in a separate file:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
public class ButtonListener implements ActionListener
{
public JLabel label;
public void actionPerformed(ActionEvent event)
{
label.setText("Clicked!");
}
}
When I enter this code, I might forget the line:
listener.label=label;
If I do, then label, in the class ButtonListener, will be null, and I'll get a NullPointerException when I try to do something to it.
Java is a statically type-checked language, which means that it, at least in theory, can catch problems like this, but only if we use it well.
To make sure that, when an object is constructed, it has all the information it needs, we can provide a constructor. A constructor is like a method, but it is run once when an object is created.
Here is a simple idea of what a constructor could do:
public class Student
{
public String name;
Here be the constructor:
public Student()
{
name="John Smith";
}
Here endeth the constructor
}
So then any Student created will have a default name of John Smith. This is useful for some situations, but more usually we want an initial value rather than a default value, otherwise there would be many fake John Smiths around, which would be wrong. So, like with a method, we can give a constructor inputs, or parameters:
public class Student
{
public String name;
public Student(String initialName)
{
name=initialName;
}
}
Now we create a Student like this:
Student aStudent=new Student("Phil Jones");
Student another=new Student("Arshad Mohammed");
So each Student that we create will have an initial,
not a default, name. The only way this can cause a
NullPointerException is if you pass a null value to
the constructor, e.g.:
Student headlessHorseman=new Student(null);
It's important to look at the exception output from a NullPointerException, and not to be dazzled by it.
Here's an example:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at SimpleActionListener.actionPerformed(SimpleActionListener.java:9)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:18
49)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.jav
a:2169)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel
.java:420)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258
)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonL
istener.java:234)
at java.awt.Component.processMouseEvent(Component.java:5488)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3093)
at java.awt.Component.processEvent(Component.java:5253)
at java.awt.Container.processEvent(Container.java:1966)
at java.awt.Component.dispatchEventImpl(Component.java:3955)
at java.awt.Container.dispatchEventImpl(Container.java:2024)
at java.awt.Component.dispatchEvent(Component.java:3803)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212
)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3892)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
at java.awt.Container.dispatchEventImpl(Container.java:2010)
at java.awt.Window.dispatchEventImpl(Window.java:1766)
at java.awt.Component.dispatchEvent(Component.java:3803)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchTh
read.java:234)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThre
ad.java:163)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
I highlighted the top two lines because those are the most useful. The first line tells you what the problem is (NullPointerException), and the second line tells you where it happened (line 9 of SimpleActionListener.java).
The rest of it is useful detail, but normally we don't need to look at it. It's like an address. Suppose there was an emergency and we wanted to tell somebody.
Exception ocurred in lecture "Programming on the Internet": LotsOfSmokeAndFireEx
ception
at very expensive data projector
at ceiling of room
at room 141
at 1st floor
at Newton Building
at Peel Park Campus
at University of Salford
at The Crescent
at Salford
at Greater Manchester
at England
at United Kingdom
at Earth
at Sol Star System
at Milky Way
at Universe
In the above example, different levels of detail are important to various people. It's pretty important where in the room the fire is for us trying to get out. It's pretty important to tell the emergency services which building, room and university it is, but they probably don't need to know that it's on Earth or in the Universe. It won't help their driving directions.
Java doesn't really care how much information you'll need, it just gives you everything, and you have to make sure you don't panic!
So, in this case, I saw that the problem was at line 9
of SimpleActionListener, which I'll paste here:
System.out.println(s.length());
There are two possible things that are null in that line, System.out and s.
System.out is the field called out in the System class, see its documentation. It is possible, via some lazily written code that's part of Java already, to set System.out to null (not as simple as just System.out=null, but feel free to try that!). However, that's such a silly state to be in that I'll just assume it is 's' that is null.
Just to make sure, I can insert a line:
System.out.println(s);
before the erroneous line, and see what I get.
As it happens, in this case, the problem in my code
is really obvious. Line 8 is:
String s=null;
You might wonder why System, println(), or length() might not have been null.
System is a class, classes are never null. If a class isn't available, you'll get a compile error. Simple.
println() is a method, it can't be null. It's not a variable.
length(), likewise, is a method, so it can't be null.
Here we'll write a simple converter between time and bananas. What?!
In some organisations (Sun, IBM), something that takes less than 10 minutes is called a one-banana job, as in: "A monkey would need one banana for the brainpower required to do this". Something that takes less than 20 minutes is a two-banana job. Etc.
So, we'll write an application that asks the user how long a job will take, and converts it to bananas.
This might seem fairly lame, but at least it isn't Yet Another Fahrenheit to Celsius Converter. Google is already excellent at doing that conversion, let's stop writing that. A google query converting 32 Celsius to Fahrenheit. Google, so far, cannot convert minutes to bananas, but if this page about Britney Spears is anything to go by, it's just a matter of time.
So we'll start with a frame that looks like this:

Once you have that, create an ActionListener for the button. You could call it ConvertListener or something.
You'll need the ConvertListener to have a field for the JTextField from the screenshot, as in last week's.
For now, just make the listener alter the text in the JTextField, and make sure that works.
Ok, now we need to take the number of minutes from the
JTextField. We can get the value from JTextField,
as a String, like this:
String value=field.getText();
To convert that to an int so that we can do some maths (all we're doing is dividing by 10!), google for convert String int java. Once you have an int, divide it by 10, e.g., x=x/10; (x/=10 works too).
Then we want to convert the int back to a String, so google convert int String java, and then pass it to the JTextField as so: field.setText(someString);
Experiment with better ways of outputting this, e.g., having another textfield for output, using JOptionPane, etc.
Take a look at SwingSet2, which is a (slightly out of date) demo of a lot of Java's components: here.
Experiment with some of these, see if you can make something a little more useful, possibly related to your daily life, e.g., pounds to dollars, odds to fractions, lottery number pickers, etc.