An Introduction to Java for PL/SQL Programmers

Dr. Paul Dorsey, Dulcian Inc.

Both Java and PL/SQL are ALGOL based languages with the standard structures of many programming languages including BEGIN and END, control structures, loops, etc. But Java and most third generation languages (3GLs) differ in some significant ways. Java is very much a modern programming language for several reasons:

          Support for object-orientation

          Full support for multi-tasking.

          Platform independence

          Enhanced memory management and garbage collection.

Although many comparisons will be made to PL/SQL, which has traditionally been Oracle’s primary programming language, the points discussed in this paper will be equally applicable to any standard 3GL language.

 

Java and PL/SQL – A Comparison

It is easy to try to treat Java as just another programming language. From this viewpoint, it might seem that you simply need to learn a new syntax and notation differences such as using curly brackets { } instead of BEGIN/END statements. Approaching Java in the same way as other non-object-oriented languages will result in much more code than would be necessary with a true object-oriented approach.  However, object orientation isn't necessarily more efficient from a performance point of view.  In fact, it is common to make object-oriented design concessions in the name of performance.

In writing early programs, you probably copied and pasted a lot of code in various places until you learned how to use local functions and procedures, explicit exception handling and anonymous blocks of code. In comparing a novice programmer with someone having several years of experience, the quality of the algorithms will vary greatly. This is true even if the novice programmer is skilled in another programming language.

For each language, there is an optimal style. This paper does not substitute for really learning Java. The goal is to discuss a few basic things that are different about Java and point out elements of Java that require more careful attention.

Using  Objects

The fundamental building block of an object-oriented language like Java is a user-defined datatype called a class. In its simplest form, a class acts similar to the datatypes used in most other procedural languages. Java has both primitive (sometimes called either simple or built-in) and user-defined datatypes. The primitive datatypes were implemented for performance reasons and each has a sister class available when a fully functional class is required. (i.e. Integer is a class, whereas int is a primitive datatype).

The instantiation of a Java primitive datatype is called a variable.

          The Java primitive types consist of: byte, short, int, long, char, float, double, boolean
An example for an instance of the variable age:   int age = 38 ;

          Primitive types in Java can only hold a single-value and they cannot be passed by reference, or by using explicit pointers as in C or C++.

The architecture of procedural languages like C and PL/SQL diverge from Java at this point. Procedural languages rely on functions as their basic programming unit, whereas Java and other object-oriented languages build upon user-defined datatypes (classes) as their basic programming structure. Java shifts the programmer’s attention from function-like behavior, to object behavior by basing its code on classes.

An instance of a user-defined datatype (Class) is called an object.

          An object is passed by reference, and may process as much data as is needed.

          To use a class, you must declare an instance of it just as you would with any other datatype.
(i.e.   Integer  age = 38;   Where Integer is the class and age is the object)

          Each public class definition is stored in its own source file, which has exactly the same name as the class with (.java) added as the file extension.

          Related class files are stored in libraries of packages. These libraries are stored in zipped files with the extension (.jar).

Although the terminology may differ in places, the underlying concepts of Java programming reflect those in other languages. For example, procedural language functions and procedures are called methods in Java.  Methods are defined within classes. Just as you can define variables within a procedural language package, you can also define them in a Java class.  Functions and procedures within a package act in the same way as methods in a class. 


The basic parts of Java

Java, like most programming languages, is composed of comments, executable blocks, variable declarations, control logic and  error handling.

Recognizing Comments

/* This is a long comment or
     multi-line comment in Java. */
// This is a single line or short comment.
-- THIS IS NOT A LEGAL COMMENT IN JAVA, double dashes won’t work.

/**  ß Notice this special comment starts with a double asterisk and each
 * additional line is started with a single asterisk. This type of comment
 * is used in the creation of a special type document called Javadoc. A Javadoc
 * is a Class Reference document that you can generate dynamically in JDeveloper.
 * The Javadoc wizard parses the packages and/or source files that you
 * designate, to automatically produce HTML pages describing the basic elements
 * in the source code for your Classes.
 * To create or update a Javadoc for a class, click on Wizards | Generate Javadoc
 * after you have created and commented your source code.
 */

 

basic executable program block

The basic executable program block is a collection of declarations, specifiers, and methods. Specifiers are added to the class declaration (the first line of code), to modify the class’s visibility and functionality. Consider the following code:

public class myFirstExample {
  public static void main ( String args[] ) {
    System.out.println(“Hello World”);
  }
}

 

The first line of code “public class myFirstExample” represents the declaration of a new class given the name myFirstExample. The access specifier public indicates that this code can be used anywhere within a program that calls it. The other two choices for access specifiers are private and protected, which limit external access to the object. If you do not specify an access modifier, will only have access to your objects in the same package. Notice the sets of curly brackets {}. They represent the start and end of each code block. The code within each block has its own scope. As shown in the example, code blocks can be nested within each other.
The second line, “public static void main ( String args[ ])” declares a method called main.

 

The main method will handle the code when the class myFirstExample is executed. The Java Virtual Machine (JVM) specifically looks for a method called main when any application starts. To meet the basic requirements for the JVM to call the main method from outside of the myFirstExample class, main must have an access specifier of public. Also main must be declared static, which means that the method can be run without instantiating the class defining it. The static declaration is necessary because the Java interpreter calls the main method before any objects are made. The third term, void, is a declaration of the return-type since main does not return any values. As you build methods that return values, you can use any valid datatype or class as a return type. 

 

The remainder of the line is used to pass parameters to the main method. The set of parentheses ( ) that follow the method’s name is used to hold these parameters. As you view the parameter declaration for main, you will see that only one parameter is used. Its datatype is String, and its name is arg. The square brackets [ ] after arg indicate that arg is being declared as a String array. (Arrays are collections of similar objects.) The String array “arg” is used to pass any command-line arguments that exist when the class is executed.

 

The third line System.out.println(“Hello World”); is a call to a library that is distributed by default with all JVMs. The method println will generate the line “Hello World” with a carriage return and send it to the console. A similar method print would produce the same text but without the carriage return.

 

Inheritance and Polymorphism

Additional keywords can be added to class definitions that give them specific capabilities in an object-oriented structure. When you use the key word extends in the declaration of a class, it allows you to inherit methods and variables from a parent class. This gives you the opportunity to reuse, extend, or modify the existing code without the need of rewriting it. The parent class is referred to as a superclass and the child is known as a subclass. A Superclass can have any number of subclasses, but a subclass may only extend a single surperclass (no multiple inheritance). If you reuse the same name for a variable in both the parent and child classes, the child definition will override the parent definition. When you use the same name for multiple methods, with different kinds or numbers of datatypes, you effectively overload the functionality of a given name. Overriding and overloading are known as forms of Polymorphism.

 

// A parent class for a 2-Dimensional object
public class box {
  int width  = 2;
  int length = 3;
}

// A child class for a 3-Dimensional object, which inherits a parent class
public class cube extends box {
    int height = 4;
    int width  = 1; //polymorphism - this variable(width) is set to 1.
    int volume = super.width * length * height;
  public cube() {
    System.out.println("The volume of the cube is: " + volume);
  }

  public static void main(String[] args) {
    new cube();
  }
}    /* This cube will have a volume of 24, because super.width
      references the width defined in the superclass box. If you
      change 'super.width' to just 'width' in the volume calculation
      for the cube, you will have a new volume of 12. */

 

 

 Variable and Object Declarations

The creation of an object or variable in Java is an inherently dynamic process and can take place anywhere in your program. In some programming languages, there is a formal declaration section with a separate section where you manipulate these variables. In most programming languages, this is considered good coding style since this makes the code easy to read and maintain.

This presents an interesting challenge in setting coding standards. There is a temptation to be lax about declaring objects. Experience has shown that declaring objects and variables in the same way as in a traditional programming language, provides an appropriate natural structuring for your Java code. This is not to say that you will not also create objects elsewhere in the program.

If you embrace the philosophy of creating objects in a pseudo-declaration section as in the past, the code will be more consistent. Using this approach will also support situations where objects are created on the fly embedded in program logic, this code will stand out and make programs easier to maintain.

CAUTION: When identifying objects in Java, you may use a combination of uppercase and lowercase letters, numbers, the underscore and the dollar sign. However, you may not begin them with a number.

 

Variable Types

Java is usually a strongly typed language. Every variable has a type and every type is strictly defined. All parameters passed to classes are checked for type consistency. There is no automatic modification of one variable type to another. However, in practice, Java is not as restrictive as you might think since most built-in methods are heavily overloaded. For example, you can concatenate strings, numbers and dates together using a concatenation operator (+) without formal variable type conversion. This is similar in philosophy to the way that PL/SQL works but is much more restrictive than languages like C or C++.

In PL/SQL, you are limited to a few datatypes for variables. Java has a much richer and more varied set available to developers. Each of these will be discussed separately.

boolean

There are only two logical values for boolean operators in Java: true and false. The boolean operators do not have any numerical counterparts such as (0 or 1), as other programming languages have. 

//Java Example:  boolean operators are either 'true' or 'false'

class MyBooleanOperators {
   public static void main (String args[]) {
      boolean  myTestCondition = true;
      if (myTestCondition)  System.out.println("My condition was TRUE");
      myTestCondition = false;   //Now reset test condition to FALSE
      if (myTestCondition)  System.out.println("This line Never prints");
   }
}   

 

/* PL/SQL Example: Boolean operators may be TRUE, FALSE or NULL. */
 myTestCondition Boolean := TRUE;

Character 

The Java datatype char consists of a single byte (16-bit number with a value between 0-65,000), representing the Unicode International Character set. Char variables can be treated transparently as numeric or as characters.  You should not try to directly compare the term char in Java and PL/SQL.  A char datatype in PL/SQL is closer to a Java String than a PL/SQL char as shown in the following example. 

/* Java Example: The char DataType can only represent a single character or symbol, and may be initialized as follows: */

 char myFirstChar = 97 ;       // decimal equivalent of letter 'a'
 char mySecondChar = 'a' ;     // using a character
 char myThirdChar = '\141' ;   // octal equivalent of letter 'a'
 char myFourthChar = '\u0061' ; // Unicode (Hex) value for letter 'a'

 

--PL/SQL Example:  In PL/SQL the CHAR DataType is a fixed length String.

 myStringChar CHAR(45):= 'Datatype CHAR is a Fixed Length String in PL/SQL';

 

Note: You can find more information about the Unicode character sets at www.unicode.org.

Strings

The String type in Java defines an object.  In its simplest form, the String type can be used to declare string variables, which can be assigned a quoted string constant.  In this respect, the String type can handle string literals in the same way that a VARCHAR2 does in PL/SQL.

//The Java String type:

  String myString = "This is a Java test string";
  System.out.println(myString);

//A PL/SQL VARCHAR2 example:

  myString VARCHAR2(200) := 'This is a PL/SQL test string';
  DBMS_output.put_line(myString);

 

Java implements a string as an object instead of just a character array. The String class includes a full complement of features to support string construction and manipulation. These features include methods to create strings from literals, chars, char arrays, and other string reference objects.

// The following Java Strings all store the value "Java":
   char mychars[] = {'J', 'a', 'v', 'a'};
   String mystring = new String(mychars);

// or a string literal
   String myString = "Java";

// or decimal values for the ascii characters
   byte myASCII [] = {74,97,118,97};
   String mystring = new String(myASCII);

// or using the concatenation operator (+)
   String myLetter = "v";
   String mystring = new String("Ja" + myLetter + "a");

// or using method concat
   String myLetters = "Ja";
   String mystring = myLetters.concat("va");

 

In addition, you can compare, concatenate, change case, find length, extract characters, search strings, and modify strings. Although Strings are immutable in Java (cannot be changed), this does not present a real problem. Whenever you alter a string through a string operation, you simply get a new string that contains the modifications. The language was constructed this way to increase its overall performance through the efficiency gained by this type of implementation. When you need a string to be implemented as a modifiable object with its associated overhead, you can use a sister class for strings called StringBuffer. Actual performance differences between these classes will depend upon the implementation and tasks that are being performed.

//Java performs auto datatype conversions in String methods.
   String myAge = ("My age is " + 2 + 35);  //This produces "My age is 235"

//If you wish to add 2+35 to indicate an age of 37, then use:
   String myAge = "My age is " + (2 + 35);  //This produces "My age is 37"

 

/* In Java the method substring(int startIndex, int endIndex) returns a portion of a string from the startIndex to the (endIndex –1)  */

   String s = "This is a Java xxx string.";
   s = s.substring(0,15) + s.substring(19, 26);
   System.out.println(s); //This will print "This is a Java string"

    

/* In PL/SQL the sbstr function returns characters from a start position, for a given length. */

  s VARCHAR2(50) := 'This is a PL/SQL xxx string.'; 
  s := SUBSTR(s, 1,17)||SUBSTR(s,22,7);
  Dbms_out.put_line(s); //This will print "This is a PL/SQL string"

 

The String class uses two overloaded methods for locating chars and substrings within a string. The first method indexOf will search for the first occurrence of a character or substring, by searching from a given index and working towards the string’s end. The second method lastIndexOf performs a similar search in the reverse direction, beginning at an index and searching backwards until it reaches the beginning of the string. Both methods will return the index where a given character or substring was found, or (–1) if no match is located.

CAUTION: Java strings and arrays have indexes that start with zero (0). This is different from PL/SQL where they start with one (1).

//The Java search methods for strings

class myStringSearch {
  public static void main (String args[ ]) {
  String sourceString = "This a Java string to be searched";
  System.out.println( sourceString.indexOf("Java", 0) +
          " is the starting position for the word (Java)" );
  }  // This search reports that Java starts at position 7
}

 

//In PL/SQL a string search can be performed with the INSTR function.

  myindex INTEGER;
  SourceString VARCHAR2(200) := 'This a PL/SQL string to be searched';
  myindex := INSTR( SourceString, 'PL/SQL' );
  //This PL/SQL code fragment shows PL/SQL started at position 8

 

StringBuffer

StringBuffer is a sister class to String and represents character sequences that can change size and/or be modified.  What this means to the developer is that methods like append() and insert() are available to modify a StringBuffer whereas in String you are limited to the concatenation operator (+).  Thus, the StringBuffer class may be used when the character sequences being stored need to have substrings inserted or appended .

//The Java StringBuffer append()

class myAppend {
  public static void main (String args[ ]) {
    String myString = "This is my string";
    StringBuffer buff = new StringBuffer(50);
    myString = buff.append(myString).append(", my append.").toString();
    System.out.println(myString);
  }  //This produces "This is my string, my append."
}

 

//The java String concatenation operator (+) can also be used to append.

class myAppend {
  public static void main (String args[ ]) {
    String myString = "This is my string";
    myString = myString + ", my append.";
    System.out.println(myString);
  }  //This also produces "This is my string, my append."
}

 

//In PL/SQL an append is performed using the concatenation operator

  myString VARCHAR2(50) := 'This is my PL/SQL string';
 
  myString := myString||', and append.';
  //This will produce "This is my PL/SQL string, and append."

 

Numeric

There are several subtypes of numeric datatypes. For whole numbers, these include:

          long (+ ~ 9 * 1018)

          int (+ ~ 2,000,000,000)

          short (+ ~ 32,000)

          byte (-128 to 127)

For numbers with fractional precision, the datatypes include:

          float (+ ~ 3.4 * 1038)  (~# of significant digits)

          double (+ ~ 1.7 * 10308) (~# of significant digits)

Note: Floating-point literals (i.e. 34.5) default to DataType double.  If you wish them to be DataType float you must add an ‘f’ suffix (i.e. 34.5f) or you may cast them to float explicitly.

//Java Example: longs end with 'L' and floats end with 'f'

  long population = 1234567890123456789L ;
  int age = 38 ;
  float price = 460.95f ; //or float price = (float) 460.95
 
  double area, length = 3.15, width = 4.2 ;
       area = length * width ;

 

//A PL/SQL Example:

  population DOUBLE PRECISION := 1234567890123456789 ;
  age INTEGER := 38 ;
  price NUMBER := 460.95 ;

 

CAUTION: Java is case sensitive.  PL/SQL programmers are not accustomed to being concerned about case. Java programmers must be extremely careful about the use of capitalization in the naming of objects as well as keywords.

As mentioned earlier, although Java is strongly typed, you do not need to perform your data conversion manually in all cases. Frequently, you can be a bit “sloppy.” With numeric variables, you can always assign a narrower variable type (e.g. byte) to an int variable or anything to a double datatype. The opposite situation does not work. You cannot assign a broader (takes up more memory) variable type to a narrower one. The reason that this works in Java is that Java automatically promotes datatypes based upon the operation being performed. This can often lead to very confusing behavior as shown in the following code:

 byte b = 10;
 byte c = 2 * b;

This code will fail because (2 * b) is automatically assigned to an internal int variable. In this example, you would have to explicitly cast the resulting expression back into a variable of type “byte” as shown next:

 byte b = 10;
 byte c = (byte) (2 * b);

Note: Java has a number of wrapper classes such as Boolean, Byte, Character, Double, Float, Integer, Long, and Number that provide full object-oriented support for simple types like byte, char and int. These classes provide the ability for the simple types to be passed as objects. 

Arrays

Arrays in Java are rich and relatively straightforward. They are collections of similar type objects and may have one or more dimensions. Elements within an array are accessed by indexes, which always start at zero [0]. To create an array, you must declare a variable, allocate memory and initialize the elements.  These operations can all be performed in two basic steps:

First you must create an array variable, by adding a pair of square brackets [ ] to the end of a type declaration. For example, the following line declares a string array named myAnimals.

  String myAnimals[];

Second,  you need to set the size of the array, which allocates memory and initializes the elements. To create a string array with enough room to store 10 names in myAnimals you would use the following:

 myAnimals = new String[10];

// Or we could declare and allocate in one line
 String myAnimals[] = new String[10];

In the string array myAnimals[ ], you can now access 10 elements numbered 0 to 9. To store the name of an animal in a given element, include the index number within the square brackets. For example, to store “Cat” in element 3:

 myAnimals[3] = "Cat";

In Java, you can create arrays of arrays…of arrays, more commonly known as multidimensional arrays. Since each array can be independently created, you can even create irregular combinations where array sizes vary within a given dimension. However, keep in mind that most small arrays are coded as rectangular objects for ease of implementation. Thus, extra care must be taken with irregular arrays to prevent problems with out-of-range index values.  In practice, you may not wish to implement this type of structure as part of your regular coding style.

Here is an example if a two-dimensional irregular array.  The first dimension will store owner names and the second will store the type of pet.

// A Java 2-dimensional irregular array.
// The 1st dimension has 4 pet owners.
// The 2nd dimension stores the type of pets they own.

class myTwoDimensionArray {
  public static main (String args[]) {
   String myPetFriends[ ][ ] ={  //This declares, allocates and initializes
      {"Arlette", "Cat", "Alligator" },
      {"Paul",    "Dog"},
      {"Eddie",   "Goldfish"},
      {"Yalim",   "Camel", "Dolphin", "Parrot"}  };
  }
}

Collections

Java provides a framework to handle groups of objects, known as collections. The powerful classes in this framework provide functionality for grouped-objects such as dynamic arrays, vectors, linked lists, trees, and hash tables. In addition, Java2 has implemented maps that associate key/value pairs. The enhanced interface provided by these tools brings a rich assortment of methods for handling object groups in Java. A full discussion of these complex objects is beyond the scope of this paper. Since you will need to understand these collection classes in order to build production applications using JDeveloper, refer to one of the many available books on the Java language for more information about these topics.

 Control Statements

Java uses traditional if-else, switch, loop, and three jump statements: break, continue, and return to control program flow during run-time. 

//Java program control using if-elseif-else

class WhichTaxQuarter {
  public static main (String args[]) {
     int taxMonth = 10;  //October or 4th Quarter
     String taxQuarter;
    if (taxMonth==1|| taxMonth==2|| taxMonth==3)
     taxQuarter = "1st Quarter";
    else if (taxMonth==4|| taxMonth==5|| taxMonth==6)
     taxQuarter = "2nd Quarter";
    if (taxMonth==7|| taxMonth==8|| taxMonth==9)
     taxQuarter = "3rd  Quarter";
    else if (taxMonth==10|| taxMonth==11|| taxMonth==12)
     taxQuarter = "4th  Quarter";
    else
     taxQuarter = "Not Vaild";
    System.out.println("Your current Tax Quarter is: " + taxQuarter );
  }
}

 

// The same business logic can be programmed using a switch statement.

class WhichTaxQuarter {
  public static main (String args[]) {
     int taxMonth = 10;  //October or 4th Quarter
     String taxQuarter;
    switch (taxMonth) {
      case 1:    case 2:    case 3:
        taxQuarter = "1st Quarter";
        break;
      case 4:    case 5:    case 6:
        taxQuarter = "2nd Quarter";
        break;
      case 7:    case 8:    case 9:
        taxQuarter = "3rd  Quarter";
        break;
      case 10:   case 11:   case 12:
        taxQuarter = "4th  Quarter";
        break;
      default:
        taxQuarter = "Not Vaild";
    }
    System.out.print("Your current Tax Quarter is: ");
    System.out.println(taxQuarter);
  }
}

 

Loop Controls

The iterative control structures for Java are known as loops. They provide control for repeated execution of specific code segments. The extensive set of loop controls is very effective for implementing almost any type of loop structure. The basic loops include for, while, and do-while. Their functionality can be extended using Java’s three jump statements: break, continue, and return. In addition, you can modify the various portions of the loop to handle almost any legal Java expression.

//The basic Java for loop:

class MyLittleCounter {
   public static main (String args[]) {
     int n;
     for ( n=1; n<=10; n++ )
       System.out.println("My count is: " + n);
   }
}

 

//The basic PL/SQL for loop:

PROCEDURE MyLittleCounter
IS
BEGIN
  FOR n IN 1..10
  LOOP
     DBMS_OUTPUT.PUT_LINE('My count is: '|| n );
  END LOOP;
END;

 

//Variation of the Java for loop.
// (Most coders would use a "while" loop in this situation but this example was
// used to show this type of variation on a Java for loop.)

class MySimpleLoop {
  public static main (String args[]) {
    int i = 1;
    boolean isCounting = true;
    for ( ; isCounting ; ) {   //Only the Boolean condition test is used
       System.out.println("My count is: " + i);
       if( i = = 10 ) isCounting = false;
       i++;  //This increments the variable used for counting.
    }
  }
}

 

//Variation of the PL/SQL for loop:

PROCEDURE MySimpleLoop
IS
 i INTEGER := 1;
BEGIN
  FOR
  LOOP
      DBMS_OUTPUT.PUT_LINE('My count is: '|| i );
      EXIT WHEN i = 10;
      i := i + 1;
   END LOOP;
END;

 

Skeleton of a Class file

JDeveloper has adopted a common style and skeleton for generating code. You will find that the classes generated by the Wizards, all have the same look-and-feel. Understanding this implied coding standard is very helpful if you wish to find a particular piece of code. There is a great deal of latitude when using the code editors, but if you can adopt a similar coding style to the one the Wizard uses, you will find your code easier to extend, edit and maintain. The generated code is structured using the following skeleton:

package xxxx  //first line of the file (giving the storage location of the class file)

import yyyy    //several import statements (adding stored classes  called libraries)

class zzzz        //assigns class name, interfaces and inheritance

          Variables and Objects instances   //declare instances of other classes and variables

          Constructor - executes automatically each time an instance of the class is declared

          Provides automatic initialization of selected class variables

          May be overloaded

          Is named the same as the class

          Methods //add various methods as necessary, to complete the class definition

          main & init (only needed for executable classes: Application or Applet)

         Applications start execution with the main( ) method.
Applications run on a client machine, under the operating system of that machine.

         Applets start execution using the init( ) method.
Applets that run stand-alone will begin by using main to call init.
Applets run under a browser via the internet/intranet.

          Add other user-defined methods as necessary…

Exception handling - Try { }   Catch { }

Exceptions can occur in the Java environment when undefined conditions are encountered. You may also generate an exception, by using the keyword throw anywhere in your code. The five terms associated with Java exception handling are: try, catch, throw, throws, and finally. The first two terms try and catch, define the block of code that is in focus and the block of code to execute when a given exception occurs. The term finally is used to identify an additional block of code to execute after the try/catch blocks, whether or not an error occurs. This is useful for closing file handles etc. in the event of an error.

 

When defining a method, you must use the term throws to identify the exceptions that cannot be handled by the standard libraries. Exceptions types for RuntimeException, Error, and their subclasses are included in the libraries and do not need to be identified. If you attempt to compile a method in which you have not listed all of the exceptions that need to be handled, you will receive a compile-time error.

 

//A Java divide-by-zero class, using try/catch exception handling
public class MyRatio extends Object {
  public MyRatio() {          //this is the start of the class constructor
    int numerator = 5;
    int demoninator = 0;
    int ratio;
   try {                      //This is the beginning of a try block

     ratio = numerator / demoninator ;
   }
   catch (Exception e)  {        //This is the start of the catch block
     e.printStackTrace();        //This sends the error msg to the screen
   }
  System.out.println("This is printed because the error is handled correctly");
  }
  public static void main(String[] args) {     //This is the main method
   new MyRatio();                              //This calls the constructor
  }
}

 

//A PL/SQL exception handler for a divide-by-zero error
Declare
 numerator   integer = 5;
 denominator integer = 0;
 ratio       integer;
Begin
   BEGIN                          //This is the start of the (try) block
    ratio := numerator / denominator ;
   EXCEPTION                      //This is like the catch block
     WHEN OTHERS
     THEN
       Dbms_output.put_line ('Exeception: ' ||SQLCODE||', '||SQLTERM);
   END;
 Dbms_output.put_line('This is printed because the error is handled correctly');
End;

 

Access Control

Access-control to Java objects, is controlled through the use of the keywords public, private, protected and a default-value when no specifier is given. Access-control is built around three levels of encapsulation: method, class, and package.  The specifier public provides the widest access. Public allows a class member to be accessed from anywhere in the program. The most limiting access occurs when the keyword private is used. In this case, access for a class member is limited to other members of the same class. The specifier protected, is just slightly less open than public. When the keyword protected is used, you can access a class member anywhere except from a non-subclass that is in a different-package. The final possibility is to use the default-access, which is granted when no specifier is used. Then default access limits use of a class member to within the same package.

 

Global Variables

Since Java is an object-oriented language, you usually instantiate a class before it or anything it contains can be used. However, in the case of global variables, you may want to have some methods or variables that are independent of the instantiations of the class. This is accomplished by the use of the keyword static. When static is used with a class member, it gets instantiated when the class is referenced for the first time. Since these members are already in existence when you create new instantiations of the class, they remain intact and are in essence global variables that can be accessed by all instances of the class. Static is also used with the main method in the case of an Application class. This is necessary because the main method must be instantiated when the class is loaded so that the class can be executed at runtime.

//Demonstration of a global variable using get and set methods

public class MyGlobals  {   //The setx and getx methods are public Globals
  private static int x = 3;
   public static void setx (int y){
   x = y;
   }
   public static int getx (){
   return x;
   }
}

 

Constants

At times it is desirable to have constants within your program. The concept of having something that cannot change is meaningful at the variable, method and class levels. In the case of variables, using the keyword final is similar to using the constant keyword in PL/SQL. Variables declared with final must be initialized in the same statement. It is a common coding practice in Java to use UPPERCASE when naming a constant.

When a method has the specifier final in its declaration, this means that you cannot override the method in a subclass. Thus, if class A has a final method B, and if class C extends A, then C cannot override the inherited method named B.

When a class has the specifier final in its declaration, it cannot be inherited. Since inheritance is used to extend or modify an object, this limitation makes sense. In addition, all of the methods associated with a class are implicitly final as well.

//Using final in the declaration of constants
class myConstants(){
  final int feetInMile = 5280;
  final int feetInYard = 3;

  final void printMe() {
    System.out.println(“You CANNOT override this method”);
  }
}

 

Caution: When considering inheritance, the keyword final only applies to method and class declarations. If you declare a variable as final, you CAN OVERRIDE it in a subclass. This is contrary to what you might assume from the way inheritance is blocked, with methods and classes that are declared as final.

 

Garbage Collection

Java automatically handles the de-allocation of memory for objects that are no longer referenced by a variable. This is performed by the garbage collector. In some instances you may wish to perform some explicit activities, such as releasing a file-handle as part of the garbage collection for a given object. This can be accomplished through the finalize method. You should remember that the finalize method is only called just before the garbage collector destroys an object. Since you have no control over the garbage collector, there is no guarantee as to when the finalize method may be executed. If you need to have an action performed at a precise point in your program, you should not rely on finalize to execute it.

 

Interfaces

An interface is like a skeleton for a class. You can use an interface to specify what a class will do, without defining how it will accomplish the task(s). The interface must include a declaration statement for each of the class methods you wish to implement, but the method-bodies and instance variables for the class are not included. Thus each of the methods defined in an interface are abstract by definition, meaning that the developer must provide a definition for the method when the subclass references an abstract object. Creating an interface allows you to compile code that depends on a class while deferring the writing of the method-bodies until you implement the interface. Having abstract methods defined in an interface instead of a class, gives you the freedom to combine as many interfaces as necessary when defining a new class, whereas, with direct inheritance, you are limited to single class. If you are an experienced Java coder, you will understand the implication that interfaces provide a workaround for Java’s lack of support for multiple inheritance. 

If you include variable declarations in an interface, they are final and static by definition. Variables defined in an interface act as constants that can be shared by all classes that implement the interface.

// An example of an interface
 interface myArea {
  int length = 3;
  int width  = 2;
  double area();
}

class myBox implements myArea{
  public myBox() { }
  double area(){ return (length * width); }
}

class myTest {
  public static void main (String args[]) {
    myArea boxArea = new myBox();
    System.out.println("Test box area is: " + boxArea.area() );
  }
}

 

About the Author

Dr. Paul Dorsey (pdorsey@dulcian.com) is the founder and President of Dulcian, Inc., (www.dulcian.com) an Oracle consulting firm that specializes in data warehousing, web and client-server systems development and products that support the Oracle environment. Paul is co-author with Peter Koletzke of Oracle Press’ Oracle Designer Handbook, Oracle Developer Forms and Reports: Advanced Techniques and Development Standards and with Joseph Hudicka of Oracle Press’ Oracle8 Design Using UML Object Modeling. Paul is the Executive Editor of SELECT Magazine and is President of the NY Oracle Users’ Group. Paul has given presentations at all of the major US Oracle conferences over the last seven years.