Into Java - Part IV

From EDM2
Revision as of 15:39, 17 October 2017 by Ak120 (Talk | contribs)

Jump to: navigation, search
Into Java / Part
I II III IV V VI VII VIII IX X XI XII
XIII IV XV XVI XVII XVIII XIX XX XXI XXII XXIII

By Simon Gronlund

Welcome to the first OS/2 e-Zine! Java column of this millennium! Today we will leave the most basic building bricks behind us, the data types from the December 1999 issue, and finish with some of the more powerful classes of the Java Development Toolkit. These classes are designed and developed to be robust, powerful and yet easy to use. And you cannot beat the price, they are free.

Today we will find out how to do some file handling and present the result in a window, a graphical user interface well-known to you. I presume you have installed Swing, since every graphical example from now on will make use of Swing. But first we will start looking into the more useful parts of Object-Oriented Programming (OOP), a topic that continues a few issues since it is such comprehensive.

Object-Oriented Programming

Let us recall that a class is the blue print out of which any object is instantiated. A class can have many class variables holding values and states, and many methods doing the workload. A primary object is to make a class as clean as possible, that is, do not merge to many functions into it. Let a class be as pure as possible, such as a screw-driver, as a knife, or as scissors, not as a Swiss army knife. On the contrary a Swiss army knife is built out of several classes, but is itself only a container of the other classes. Got the idea?

How classes interact

There are some main relationships between classes:

  • a class may use other classes
  • a class may contain one or many other classes
  • a class may inherit from another class

These relationships are not disjoint, they often work in union with each other.

You have seen the first relation in use already. The HelloWorld class uses System, a class placed in the java.lang package, and the String class from the same source...

System.out.println("Hello World!");
static
In Java anything static is a class variable or method that exist though no object needs to be instantiated from that class. Any static variable or method might be used at any time, they stick around but do not belong to any particular object but to the class.

that is a valid use of the System class.

Take your time and look up your Java API (preferably the framed version of 1.2). Chose Package : lava.lang and then System. In the class description you will not find any method named println(), but a variable out. First you may notice that this variable is static, and second you see it is a holder of another class, PrintStream. This class, in turn, holds the println() as is seen under the "See also" block.

Hence, you use the class System, that in turn uses the class PrintStream.

Whenever a class, or a method, is static we do not have to instantiate new objects from classes.

But recall, we made ourselves a MyBank class that in turn made a number of BankAccount objects, named john, chris, et cetera. The class was instantiated and then we could access the class methods from the objects. Since we did not make these methods static they doesn't exist if no object is made.

public class MyBank {
public static void main (String [] args) {
        BankAccount john = new BankAccount("John");
        BankAccount chris = new BankAccount("Chris", 1000);
        System.out.print(john.toString() + ", balance: ");
        System.out.println(john.balance());
        ...

Still we use the class BankAccount from the driver class MyBank. To use is to manage and/or manipulate other classes or objects.

A class "has-a" class

That is, a class contains one or many other class(es). An example could be a menu of an application, the menu itself is only a container of menu items. Hence, you create yourself a new menu, then add to it a few menu items that is the real objects you like to use.

Another example is the Swiss army knife that contains other objects.

The distinction between use and contain is somewhat fuzzy since many times an object of a class may both use and contain objects of other classes.

Inheritance
An illustration of inheritance

Inheritance

The most known buzz word from OOP is inheritance, and it is exactly what it says. A class (called sub-class) inherits variables and/or methods from a parent class (the super class).

Think of our BankAccount as an example. It is quite basic, don't you think? For example, there is no interest. Let us create such a class then.

Then we start sketch a class with exactly the same methods and variables, but we see that we only added two methods to compute the interest and set the rate of interest, further one variable holding the rate of interest. Here inheritance comes to play.

So, design a class that only has these new features but first states that "I am a BankAccount, but I can do this stuff too."

Inheritance is simply to add more specified properties to an old class, as the illustration shows. We have the BankAccount class (from Into Java 2) and we add a new class that will have every variable and method from that one (since we made them protected and not private), but adds one data field and two methods.

How do we do that in real life? We simply make a new class as we are used to, but tell the compiler that we would like to make this class an extension to another class:

public class InterestAccount extends BankAccount

Obviously the magic word is extends that lets you inherit from one super class. (See no bad in that, please, it really makes the code less error prone.) Now we have class that is-a sub class of a super class, and the is-a phrase is the essence of inheritance.

Now it is no pain to simply add the variable and the methods:

public class InterestAccount extends BankAccount {

    protected double interest = 0; // rate of interest in percent

    /*
     * A method that will compute the annual interest,
     * assumed the balance is not changed during the year.
     */
    public void interest() {
        balance *= (1 + interest / 100);
    }

    /* Sets a new rate of interest */
    public void setRate(double newRate) {
        interest = newRate;
    }
}

And we are done. Interesting points are that we now can choose whether we like to use the basic account or the account with an interest as we like to. Further, both of them are treated as BankAccounts by Java if you do not explicitly set a new reference variable to InterestAccount, but why should you?

Operators
Java supports the operators in a mathematical correct way, that is:

* / % precedes + - Of course, parentheses forces the compiler to give encompassed blocks priority. Still, do not use parentheses if not needed since that may cause the compiler not to find the most efficient algorithm.

Shortcuts
There are a number of shortcuts such as *= used here. They convey this meaning:

x *= y equals x = x * y

These shortcuts are at hand: += -= *= /= %= and some more.

Beyond that we can have other sub classes, in parallel with InterestAccount or derived from that class etcetera. But we cannot inherit from more than one class at a time, which encourages us to design well and to think more than twice. Maybe we would like to add classes that we know will never be used, only to have them carry some property we'd like to add to a number of other sub classes. But that is a chapter of its own.

All these three relationships between classes - use, "has-a" and "is-a"--is extensively used in any OOP language, Java is no exception.

Put the Theory into Practice

Last time I did something that most teachers and journalists have avoided for years, I made use of a feature that I did not introduce to you. I am afraid that I will continue this bad habit, since if I do not, this column will never end. And, above all, Java really invites everyone to do that.

In fact, Java has so many classes and features that it is almost impossible to get to know them all at start, and you really don't have to know the exact inner workings of everything.

File handling

File handling is such an area, Java offers you a plethora of ways to handle files, whether they are located on your hard disk or on a network, LAN, WAN or whatever.

Taking in information from the keyboard is no difference to that, and last time we made use of System.in, InputStreamReader and BufferedReader. Everyone of them is extensively used by developers, and I suggest you surf around the Java API to find some more information on them, since I will not dig deeper than this for a long time to be. Anyway, you can see how the latter makes use of and contains the intermediate, that uses the first one.

Today I will make use of File and FileReader, as well as BufferedReader.

File

File is a class in the java.io package that is most convenient to use whenever handling files and file names. Yes, most readers can be instantiated from the string representation of the file name, but having File you never need worry, and there are several useful methods and variables at your service.

FileReader

This is an intermediate class that is instantiated with File as an argument and provide a body to more convenient classes, as BufferedReader. Using such classes as FileReader is a great help to beginners, but when time passes you will explore other classes as well.

Anything Visible

To make a window there are several objects we are in need of. Remember, classes should not be Swiss army knifes but slim and neat. The result is a suite of objects linked together, in the beginning it seems unbearable to some, but do not hesitate, it will not be much worse than today <grin>.

Frame

We always need a frame to the window, but since we will use Swing it is called JFrame (most classes in Swing have counterparts in the older AWT, the difference is in the "J"). A JFrame is (almost) nothing more than an empty window with the upper title bar with system dependent buttons.

Title bar from a lab work

Hence it is convenient to add one little feature to this otherwise empty class of ours, a way to close the window with the cross faced button, Alt+4 and Close from the upper left system menu. Therefore we inherit from JFrame and add that feature. This is the result:

import javax.swing.*;
import java.awt.event.*; // for the window closing event

public class MyFirstFrame extends JFrame {
    /* Constructor */
    public MyFirstFrame() {
        setTitle("My First GUI App");
        setSize(400, 300); // width and height
        setLocation(100, 100);
        /* The magic window terminator */
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                System.exit(0);
            }
        });
    }
}

So far we can view the window by this little driver class:

public class MyFirstFrameDriver {
    public static void main(String[] args) {
        MyFirstFrame frame = new MyFirstFrame();
        frame.show();
    }
}

And, yes, it worked!

At this point most people used to the old styled sequential programming raises one's eyebrows. In spite of the main method really exiting since it is done, the window do not disappear. That is because now the more powerful features of Java are in action. But click the cross once and it is disposed.

JFrame is in fact a sub sub sub class to Container, a class with a descriptive name. From that we understand that we have to fill this frame with other stuff, that we first have to implement, so off we go.

getContentPane()

The inner structure of a JFrame is not that simple as one might think. Normally developers use some kind of pane to add other objects into. JFrame is no exception to that, but there is actually only one thing that is of interest to us, the content pane. The content pane is the place to add stuff into, it is a "has-a" object, we really don't use it but stuff it with valuable objects.

Our goal is to create a window with one big text area showing the contents of the files you give to the program. Since we add no intelligence to this little app it can only show text files, but that will do. Let us add some new lines to MyFirstFrame.java.

import java.io.*; // to get the file handling support
import javax.swing.*;
import java.awt.event.*;

public class MyFirstFrame extends JFrame {
    /* Variables */
    protected JTextArea text;
    protected JScrollPane scrPane;

    /* Constructor */
    public MyFirstFrame() {
        setTitle("My First GUI App");
        setSize(400, 300);
        setLocation(100, 100);
        text = new JTextArea("Some text ... ");
        text.setLineWrap(true);      // wrap long lines
        text.setWrapStyleWord(true); // wrap at spaces

        /*
         * But since text is long we add the text area
         * into a JScrollPane
         */
        scrPane = new JScrollPane(text);

        /*
         * Here we get the content pane and then add our
         * only object into that, recall the text area is
         * wrapped into the JScrollPane.
         */
        getContentPane().add(scrPane);

        /* The magic window terminator */
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                System.exit(0);
            }
        });
    }

    /*
     * Reads the specified file and adds the text to the
     * text area
     */
    public void readFile(String file) {
        BufferedReader bf;
        String line = "";
        try { // tries if it is possible to handle that file
            bf = new BufferedReader(new FileReader(
                                    new File(file)));
            text.setText(""); // empties the text area
            /* Reads and tests at the same line */
            while ((line = bf.readLine()) != null) {
                text.append(line + "\n"); // line and line feed
            }
        } catch (Exception e) {} // Any error is ignored
    }
}

You can try it with the driver used a moment ago, and you'll see a window with the text we set at initialization. Since we did not add any way to specify a file name we never invoked readFile() this time. Then let us add that feature, we can make it interactive through the terminal window.

Last time we used a while loop to get user input and this time we can copy that idea. Hence add to MyFirstFrameDriver.java a few lines.

import java.io.*;

public class MyFirstFrameDriver {
    public static void main(String[] args) {
        MyFirstFrame frame = new MyFirstFrame();
        frame.show();

        BufferedReader in = new BufferedReader(
                new InputStreamReader(System.in));

        do {
            try {
                System.out.println("Specify a valid file name");
                /* send user input to readFile */
                frame.readFile(in.readLine());
            } catch (IOException e) {} // some IO error is ignored
        } while(true); // loops until the window is closed
    }
}

With this little effort we have now made ourselves a graphical app that may show any text file of our wish. That is possible since OOP gives us the strength of using, having and inherit any class. And since Java have so many prebuilt classes of such quality.

Further we have discussed the three relationships that make OOP that strong, using other classes, containing other classes and inheriting other classes. I hope I have wet your appetite that much you will continue following this column.

As an extra homework, please surf through the Java 1.2 API and look up the classes we have used, the methods available, even though we haven't used them today. Have a nice time.