09 Apr 2012 [ 201 week13 ]

Exceptions

Kent Beck, a superstar as far as programmers go, has this to say about exceptions:

I use exception handling as sparingly as possible, generally only around the highest level invocation of objects from the user interface. Lots of handlers make debugging difficult, because the code just runs to completion but provides the wrong answer. When you use exception handling, you have to think like the writer of a new programming language, not just an application developer.

We'll discuss why exception handling requires such caution, why it's still often convenient, and why Java often requires you to design your programs to make use of it.

Key concepts we'll cover this week:

Input/output

We'll cover the basics of I/O in Java.

We'll look at examples in the exception-examples project.

File input example. Useful classes include:

package org.ilzd.exceptionexamples;

import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Program to display file sizes (in both bytes and characters)
 * of all files specified on command line.
 * @author jlepak
 */
public class FileSizer {
    
    public static void printByteCount(String filename) {
        InputStream bytes = null;
        try {
            bytes = new FileInputStream(filename);
        } catch (FileNotFoundException ex) {
            System.out.println(filename + ": not found");
        }
        if (bytes != null) {
            int size = 0;
            try {
                while (bytes.read() != -1)
                    size++;
                System.out.println(filename + ": " + size + " bytes");
            } catch (IOException e) {
                System.out.println(filename + ": IO error");
            } finally {
                try {
                    bytes.close();
                } catch (IOException ex) {
                    System.out.println(filename + ": error closing");
                }
            }
        }
    }
    
    public static void printCharCount(String filename) {
        InputStreamReader chars = null;
        try {
            chars = new FileReader(filename);
        } catch (FileNotFoundException ex) {
            System.out.println(filename + ": not found");
        }
        if (chars != null) {
            int size = 0;
            try {
                while (chars.read() != -1)
                    size++;
                System.out.println(filename + ": " + size + " bytes");
            } catch (IOException e) {
                System.out.println(filename + ": IO error");
            } finally {
                try {
                    chars.close();
                } catch (IOException ex) {
                    System.out.println(filename + ": error closing");
                }
            }
        }
    }
    
    public static void main(String[] args) {
        for (String filename : args) {
            printByteCount(filename);
            printCharCount(filename);
        }
    }
}

For an example input file, you can save this page, which should have a different count for bytes versus characters thanks to these guys: ☠☠☠☠☠☠☠

File output example. Useful classes include:

/*
 * 
 */
package org.ilzd.exceptionexamples;

import java.awt.Dimension;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

/**
 * Simple text editor example.
 * 
 * @author jlepak
 */
public class Editor extends JFrame implements ActionListener {

    // Editor widget.
    private JTextArea text;

    public Editor(String title) {
        super(title);
        text = new JTextArea();
        getContentPane().add(text);

        // Build menu.
        Menu fileMenu = new Menu("File");
        MenuItem saveItem = new MenuItem("Save");
        MenuItem openItem = new MenuItem("Open");
        saveItem.addActionListener(this);
        openItem.addActionListener(this);
        fileMenu.add(saveItem);
        fileMenu.add(openItem);
        setMenuBar(new MenuBar());
        getMenuBar().add(fileMenu);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand() == "Save") {
            save();
        } else if (e.getActionCommand() == "Open") {
            open();
        }
    }

    private void showError(String message) {
        JOptionPane.showMessageDialog(this, message,
                "Error", JOptionPane.ERROR_MESSAGE);
    }

    private void open() {
        JFileChooser chooser = new JFileChooser();
        int flag = chooser.showOpenDialog(this);

        if (flag == JFileChooser.APPROVE_OPTION) {
            InputStreamReader reader = null;
            try {
                reader = new FileReader(chooser.getSelectedFile());
            } catch (FileNotFoundException ex) {
                showError("Error opening file");
                return;
            }
            char[] buffer = new char[1024];
            int size;
            text.setText("");
            try { 
                while ( (size = reader.read(buffer)) != -1) {
                    String s = String.valueOf(buffer, 0, size);
                    text.append(s);
                }
            } catch (IOException ex) {
                showError("Error reading file");
                return;
            } finally {
                try {
                    reader.close();
                } catch (IOException ex) {
                    showError("Error closing file");
                }
            }
        }
    }

    private void save() {
        JFileChooser chooser = new JFileChooser();
        int flag = chooser.showSaveDialog(this);

        if (flag == JFileChooser.APPROVE_OPTION) {
            OutputStreamWriter writer = null;
            try {
                writer = new FileWriter(chooser.getSelectedFile());
            } catch (IOException ex) {
                showError("Error opening file");
                return;
            }
            try {
                writer.write(text.getText());
            } catch (IOException ex) {
                showError("Error writing to file");
                return;
            } finally {
                try {
                    writer.close();
                } catch (IOException ex) {
                    showError("Error closing file");
                    return;
                }
            }
        }
    }

    public static void buildGUI() {
        //Create and set up the window.
        JFrame frame = new Editor("Editor example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(500, 500));

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                buildGUI();
            }
        });
    }
}

Network input example. Useful classes include:

package org.ilzd.exceptionexamples;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Program that repeatedly prompts for a URL to read and prints the size 
 * (in bytes) of the download.
 * 
 * @author jlepak
 */
public class UrlSizer {
    // Shell to start with that completely ignores error handling.
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        URL u = null;
        try {
            u = new URL("http://google.com/efeoijfeoifefoe");
        } catch (MalformedURLException ex) {
            System.err.println(ex);
            return;
        }
        InputStream s;
        try {
            s = u.openConnection().getInputStream();
        } catch (UnknownHostException ex) {
            System.err.println("Uknown host:" + ex);
            return;
        } catch (IOException ex) {
            System.err.println(ex);
            return;
        }
        byte[] buffer = new byte[1024];
        int count = 0;
        int total = 0;
        try {
            while ( (count = s.read(buffer)) != -1 )
                total += count;
        } catch (IOException ex) {
            System.err.println(ex);
            return;
        } finally {
            try {
                s.close();
            } catch (IOException ex) {
                System.err.println(ex);
                return;
            }
        }
        System.out.println(total);
        
    }
}