Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Exceptions to the programming rules, Part 1

Learn how exception handling has evolved from C to Java

  • Print
  • Feedback

Page 2 of 7

C developers build programs from function libraries. Think of a function as a method absent from any class. Resource-related functions (such as C's fopen() -- file open -- function) return values to indicate success or failure. Failure values are known as error codes, and the use of program instructions (such as if statements) to examine return values (to see if they represent error codes) is known as error code testing. For example, C's fopen() function returns a FILE structure's address upon successfully opening a file or a NULL error code if it fails to open the file. A C program that calls fopen() typically uses an if statement to determine if that function failed, as the following C-based code fragment indicates:

FILE *fp = fopen ("myfile.dat", "rt"); // Attempt to open file myfile.dat in the read-only and text modes.
if (fp == NULL) // Detect an exception. If fopen() fails, error code testing reveals an exception.
{
    // Handle the exception.
}


Although error code testing is not difficult, it features three problems:

  • Error codes are easy to ignore: Large programs require developers to introduce error code testing in many places. Forgetting to test a function's return value in one place can affect other functions later in the code, leading to difficult-to-find bugs. For example, if a C developer chooses not to test fopen()'s return value for an error code, subsequent calls to the fread() or the fwrite() functions (to read or write to the file, respectively) could also fail -- if fopen() returns an error code.
  • Error code testing often hides the natural execution flow (in source code): When a code sequence contains many calls to resource-related functions, the code needs to test each function call's return value. While reading through the code sequence, a developer can get stuck in an examination of error code testing and miss the natural execution flow.
  • Error code testing can significantly increase a program's size: Duplication of testing and recovery code in multiple places increases program size.


If you are unfamiliar with the concepts of error codes and error code testing, and the aforementioned problems, examine Listing 1's mfc1.c -- Multiple File Copy, Version 1 -- C source code:

Listing 1. mfc1.c

// ==============================
// mfc1.c
//
// Multiple File Copy #1
//
// Created with: Borland C++ 4.52
// ==============================
#include <stdio.h>
void main (int argc, char *argv [])
{
   FILE *fpSrc, *fpDst;
   int byte, i;
   if (argc < 3)
   {
       printf ("usage: mfc1 srcfile [ srcfile ...] dstfile");
       return;
   }
   fpDst = fopen (argv [argc-1], "wb");
   for (i = 1; i < argc-1; i++)
   {
        fpSrc = fopen (argv [i], "rb");
        if (fpSrc == NULL)
        {
            printf ("Could not open %s\n", argv [i]);
            fclose (fpDst);
            return;
        }
        do
        {
           byte = fgetc (fpSrc);
           if (byte == EOF)
               break;
           if (fputc (byte, fpDst) == EOF)
           {
               printf ("Could not write byte\n");
               fclose (fpDst);
               fclose (fpSrc);
               return;
           }
        }
        while (1);
        fclose (fpSrc);
   }
   fclose (fpDst);
}


The mfc1 program copies the contents of one or more source files to a single destination file. After checking for at least three command-line arguments, mfc1 attempts to create the destination file. mfc1 next enters a loop. For each loop iteration, mfc1 attempts to open a source file and copy its contents to the destination file. If all goes well, mfc1 closes the source file and continues with the next iteration. Once mfc1 finishes copying the last source file, mfc1 exits the loop, closes the destination file, and terminates.

  • Print
  • Feedback

Resources