This chapter examines Java in more detail, focusing on the language's core syntax. It introduces you to the basics of the Java language, including the syntax of comments, statements, expressions, and operators. Subsequent chapters build on this by moving into other core areas of the language.
Unlike RPG, which is column-oriented, Java is a free-form language. All redundant white space is ignored by the compiler, including line breaks. For example, this:
void myMethod(int parameter1) { return; }
is equivalent to this:
void myMethod(int parameter1) { return; }
Freedom in Java, as in other realms, is best enjoyed by observing a few rules. To aid in programmer readability, you'll probably want to set some standards in your shop regarding indentation and style. The rules themselves are not as important as using them consistently, so everyone can effectively read everyone else's code. We try to write code with a consistent style in this book, so you will get a good base, although occasionally we show some code in a compressed format, in the interest of space. Here are the loose style guidelines we "mostly" follow:
Even RPG IV code, with its increasingly free-format syntax, benefits from style conventions. A good one can be found at the News/400 Web site, www.news400.com.
All statements in Java end in a semicolon. This is a result of the free-form style of the language—the compiler needs a definitive way to determine the end of one statement and the start of another. Thus, in the previous examples, the return statement ends in a semicolon. Again, white space is not important, so the following are equivalent:
return; return ; return. ;
The next pervasive syntactical note to keep in mind about Java is that curly braces are used to delimit the beginning and end of blocks. In the previous example, notice that the body of the method myMethod starts with an opening brace, {, and ends with a closing brace, }. These braces are used to delimit classes, methods, and bodies of statement blocks. Every opening brace must eventually be followed by a closing brace.
So, "brace yourself" to see many semicolons and a lot of free space.
As a responsible programmer, you always document your code with meaningful comments. (Don't you?) The process of specifying comments in RPG IV has not really changed from RPG III. To specify a comment, you put an asterisk in column 7 of any RPG specification. The spec type itself in column 6 is optional for comment lines, as shown here:
1234567 C* This is one style of comments in RPG IV ****************************************************** * This is another one * ****************************************************** D* More comments
In RPG IV, you can also place line comments after column 80 (the RPG IV source member length minimum is 100, compared to 80 for RPG III). Further, as the example above shows, blank lines are legal and encouraged for readability in RPG IV, versus RPG III, where the compiler complained about them. In Java, you have three types of comments at your disposal, shown in Table 3.1.
Comment |
Type Description |
---|---|
/* comment */ |
Multi-line comments surrounded by /* and */ |
// comment |
Single-line comments using the double-slashes |
/** comment */ |
JavaDoc comments surrounded by /** and */ |
Like C and C++, Java uses /* (a forward slash immediately followed by an asterisk, with no intermediate blank allowed) to indicate the start of multi-line comments and */ (an asterisk immediately followed by a backward slash) to end them:
/* this is a multiple line comment */
Everything between the comment delimiters is commented out, no matter how many lines it crosses. This form of markup is often used for comment blocks, like this:
/*—————————————————————————————* * Please read these comments * * as they are very important! * *—————————————————————————————*/
You cannot nest these block comments inside each other, as in /* puter /* inner */ outer */. Also, because it is easy to forget the ending delimiter, even the best of us have been known to accidentally comment out large chunks of code in Java. A good editor (such as those in VisualAge for Java, VisualAge for RPG, or CODE/400 on Windows) will eliminate this problem. These editors show comments in a different color than the rest of the code, so you can see at a glance when lines have been inadvertently commented out.
Two slashes, //, indicate a single-line comment. All text after // is ignored to the end of line, as in:
// show comment example int myVariable = 10; // define and initialize variable
The final kind of Java comment is a refinement of the multi-line comment. These are called JavaDoc comments, and they use a double asterisk to start the multi-line comment, like this:
/** Hey you, * * read this! */
This comment is identical to the multi-line type with two exceptions: it can also be used by the javadoc command to generate API documentation from the code, and it recognizes special "tags" within the code to aid the generated output. The following section describes this comment style in more detail.
We all know the importance of documenting our code, both internally and externally. Typically, it's done as a benefit to the poor followers who have to maintain the brilliant (yet indecipherable) code we leave behind. In Java, the need is even more pressing, because Java is all about reuse of code, and such reuse is accomplished by supplying compiled classes to others for their benefit. Since the code you supply is compiled, these users have no access to the internal comments. Therefore, they must rely on some form of external documentation to tell them how to use the classes and, most importantly, what the methods are and exactly what parameters they expect. What the methods do and what they return is also of vital importance to other programmers; otherwise, how will they know when and how to call the methods. RPG IV service programs have a similar need. However, for these, we have at least the copy member that contains the exported procedure prototypes as a form of documentation. Java has no concept of copy members or included files.
With this in mind, Java supplies an easy way to embed important API informational comments right in your code where they belong, and yet extract those comments out to produce external HTML documentation. This is a very good thing! It means that these comments can double as both internal and external documentation, and that a consistent format for the information can be achieved.
The JDK includes a utility command called javadoc that generates API documentation from source code containing JavaDoc comments. For example, to generate documentation for a class called Extract, you would type the following:
c:> javadoc Extract.java
The argument passed to javadoc is a series of Java package names or source files. The javadoc command parses the JavaDoc-style comments contained in the source files and produces a set of HTML pages describing the classes, interfaces, constructors, methods, and class-level variables. The output of javadoc depends on whether you are using JDK 1.1.x or JDK 1.2.0 or higher, since the output files changed for JDK 1.2.0. Specifically, it produces the files shown in Table 3.2 for JDK 1.1.X, all in one directory.
File Type |
Description |
---|---|
Main entry point |
The main starting point for readers is a file named index.html. |
Package list |
An index list of all packages is put in a file named packages.html. |
Index |
An index of all classes and members found is put in a file named AllNames.html. |
Class hierarchy |
A list of all classes found and their hierarchy is put in a file named tree.html. |
List of methods |
One file per class (ClassName.html) lists the class and its methods. |
For JDK 1.2.0 (which was branded "Java 2" by Sun) or higher, the output is now the files listed in Table 3.3, in multiple subdirectories (one subdirectory tree per unique package name, so javax.swing becomes subdirectory tree javaxswing).
File Type |
Description |
---|---|
Main entry point |
The file index.html now uses HTML frames. |
Package list |
An index list of all packages is put in package-list.html. |
Index |
An index of all package, classes, and members is in index-all.html. |
Class hierarchy |
A list of all classes found and their hierarchy is put in overview-tree.html. |
List of methods |
One file per class (ClassName.html) lists the class and its methods. This is found in a subdirectory tree that matches the name of the package containing the class. Each dot-separated part of the package name becomes a subdirectory, so my.package becomes mypackage. |
When javadoc parses a documentation comment, leading asterisk characters on each line are discarded. For lines other than the first, blanks and tabs preceding the initial asterisk characters are also discarded. This illustrates JavaDoc comments in Java source:
/** This is class MyClassU> * and we sure hope you like it * @author George & Phil * @version 1.0 */
Comments can include embedded HTML tags. In this example, the HTML text MyClass produces underlined text for MyClass. The first sentence of each comment should provide a concise, yet complete, description of the declared entity. This sentence ends at the first period. It is important to be concise and describe the complete entity, because javadoc copies this to the member summary at the top of the HTML file. (Recall that the term member refers collectively to methods and class-level variables.) By default, javadoc only produces documentation for public classes and public or protected members, but this can be overridden with the -public, -package, or -private options to the command.
Besides parsing HTML tags, javadoc recognizes a special set of tags, called keywords, that starts with the at-sign (@). These tags provide additional information such as "See Also" references, an author name, or a version number for the text. The preceding used two tags: @author describes the author name, and @version identifies the version of the files. Table 3.4 summarizes the tags that javadoc recognizes.
Tag Name |
Description |
---|---|
@author |
Formats the given author name. A comment may contain multiple @author tags. This tag can only be used in a class or interface comment, not for a method or variable. |
@see |
Adds a hyperlinked "See Also" entry. The class name can be qualified by the package name. To reference a method or variable's javadoc documentation, use a pound sign (#) after the class name, as in @see package.class#method. |
@version |
Formats the given "Version" information. A comment may contain at most one @version tag. This tag can only be used in a class or interface documentation comment, not for a method or variable. |
@since |
Adds a "Since" entry. This tag means that this change or feature has existed since the specified release number. |
@deprecated |
Identifies this as an obsolete method. You should list the replacement. If the member is obsolete and there is no replacement, the argument to @deprecated should be "No replacement." |
@return |
Adds a "Returns" section, which contains the description of the return value. |
@param |
Formats the given parameter name and its description in the parameters section of a method description. The description may be continued on the next line. Only one tag is allowed per parameter. |
@throws |
New in JDK 1.2, describes an exception thrown by this method, |
@throws |
class-name description. Only one tag is allowed per exception. (Exceptions are covered in Chapter 10.) |
@serial, @serialData, @serialField |
New in JDK 1.2, describes information related to "serializing" this class to disk, an advanced topic covered in Chapter 14. |
{@link xxx} |
New in JDK 1.2, identical to @see, but generates inline hypertext links versus a separate "See also" section. |
Each tag except @link must start at the beginning of a line. Try to keep tags that have the same name together within a comment. For example, put all @author tags together, so that javadoc can tell where the list ends. Listing 3.1 is an example of a documented class.
Listing 3.1: JavaDoc Comments in a Class
/** * A cool class. * * @author Phil Coulthard and George Farr * @version 1.0 * @see YourClass */ public class MyClass { /** * Constructor */ Public MyClass() { } // empty for now /** * Shows a message * @param message The message string to show * @return void * @see MyClass#MyMethod2(String message) */ public void myMethod(String message) { System.out.println(message); } /** * Shows a message in quotes * @param message The message string to show * @return String object containing quotes * @see MyClass#MyMethod(String message) */ public String myMethod2(String message) { String newMessage = "'" + message + "'"; System.out.println(newMessage); return newMessage; } } // end class MyClass
You create a new subdirectory to hold the results of javadoc, and run javadoc against your class source file, using the directory option (-d) to put the output in the new subdirectory:
C:JAVA> md html C:JAVA> javadoc -d html MyClass.java
Then, only for JDK 1.1.x, you need to copy the image files that the generated HTML uses to an images subdirectory off the new html subdirectory:
C:JAVA> cd html C:JAVAhtml> md images C:JAVAhtml> copy c:jdk1.1.8docsapiimages*.* images
JDK 1.2.0 or higher does not use image files in its generated JavaDoc HTML, so this step is not needed.
Finally, you can open one of the generated HTML files by typing start MyClass.html. This causes your Web browser to open the file. Part of the result (for JDK 1.2.2) is shown in Internet Explorer in Figure 3.1.
Figure 3.1: The first screen of output from JavaDoc
Due to space constraints, we can't show the whole result, but Figure 3.2 shows another part—what you see when you click the myMethod link in Figure 3.1.
Figure 3.2: Another section of documentation produced by JavaDoc
For more information about JavaDoc, consult the JDK documentation. Specifically, look for the file docs ooldocsjavadocindex.html off your JDK directory.
An important feature shared by RPG and Java is the ability to reference data that is stored in memory by using descriptive symbolic names (called fields or variables) rather than numeric memory-cell addresses. Each field in your program must have a unique name. RPG IV limits field names to 4,096 characters (as of V3R7) and ignores case for field names. Java, on the other hand, allows variable names to have unlimited length, and Java names are very case-sensitive.
Case-sensitivity is a key point that the RPG programmer must consider. Its importance cannot be overemphasized. All referenced and declared names must match letter-for-letter. Furthermore, the source file name must match verbatim the defined class name inside the source file, including the case. Otherwise, the compiler will generate errors that you might not be able to diagnose easily. It bears repeating that, as a Java programmer, you must be especially sensitive!
For RPG IV names, the first character must be alphabetic. It can include the special characters $, #, and @; the remaining characters can be alphabetic or numeric, including the underscore _ character. For Java names, the first character can be any valid letter, the underscore, or the dollar sign. Remaining characters can contain both letters and digits. Furthermore, Java names can actually include Unicode characters as well, if you desire. Go ahead, give that variable a nice Arabic name!
Keywords are identifiers or names that are reserved by the language, and that carry special meaning within it. For example, in RPG IV, the CONST and INZ keywords on the D-spec tell the compiler that the field you are defining is a constant or that its initial value is supplied by the parameter. The RPG IV reference manual describes all of the keywords you can use on the H, F, and D specifications. Further, all of the op-codes are keywords. RPG IV also has other special words called figurative constants. You have used these since the inception of the RPG language. They include *ZERO/*ZEROS, which initializes a field to zeros, or *BLANK/*BLANKS, which initializes a character field to blanks. The other figurative constants are *HIVAL, *LOVAL, *null, *ON, *OFF, and *ALL.
Keywords are used by Java and all other languages. Language designers decide on their names, usage, and meanings for each specific language. Because keywords and figurative constants have special meaning, you cannot use them as names of fields or variables in your programs. Table 3.5 lists the reserved keywords in Java.
abstract |
boolean |
break |
byte |
---|---|---|---|
case |
catch |
char |
class |
const |
continue |
default |
do |
double |
else |
extends |
false |
final |
finally |
float |
for |
goto |
if |
implements |
import |
instanceof |
int |
interface |
long |
native |
new |
null |
package |
private |
protected |
public |
return |
short |
static |
super |
switch |
synchronized |
this |
throw |
throws |
transient |
true |
try |
void |
volatile |
while |
The two special words const and goto are not used in Java. They may be assigned meanings in future versions of the Java language but, in truth, their reserved status is to keep C and C++ programmers from accidentally using them.
To compare the two languages, let's review at a high level the anatomy of an RPG program and then compare that to a high-level view of a Java class. (Interesting terms we use in computer science, aren't they? Anatomies describe bodies of code. We aren't pulling your leg! We just want to give you a hand!)
An RPG IV program consists of specifications, which must be in the correct order. The specifications are Control, File, Definition, Input, Calculation, and Output. There are also procedures, which are made up of a beginning and ending Procedure specification, within which are Definition and Calculation specifications.
The interesting specifications in terms of actual executable code are the Calculation specifications, which contain op-codes defining the operation to perform, and the information required by the op-code. Generally, we refer to a C-spec that has an op-code as a statement. There are fixed-format op-codes and the newer free-format factor-two op-codes. The fixed-format statements you are familiar with from RPG III. The new free-format factor-two op-codes allow an expression to be coded in the expanded factor 2 in columns 36 to 80, and that expression can be continued in factor 2 of subsequent C-specs as needed. (Continuation C-specs have no op-code, and no continuation character is required unless a name or literal is split.) The free-format op-codes are CALLP, DOU, DOW, EVAL, EVALR, FOR, IF, RETURN, and WHEN.
Expressions coded in factor 2 of a free-format statement come in two flavors:
Now, let's look at Java's anatomy.
A Java class contains a class definition, which consists of variable declaration statements and method definitions. Method definitions consist of variable declaration statements and other statements. The interesting parts are the statements. Statements in Java come in different flavors:
Note there are no compiler directives as RPG has, although you can think of package and import statements as being compiler directives, if that helps. You can have more than one statement per physical line, but this is considered bad style.
Expressions in Java, unlike RPG, are divided into the following two categories:
All these statement types and expression syntax are covered in more detail shortly. Remember, though, that white space (blanks) is not important to the Java compiler. So, X=A+B is the same as X=A+B, and you can decide what you like best.
Programmers use statements to control the sequence and frequency of execution of different segments of a program. Because of RPG's fixed-form nature, the compiler can easily analyze and parse the syntax of the values present in their fixed-column locations. Unlike RPG, Java is a free-form language. There is no demarcation of a line by columns. There are many more variations of what makes up an executable statement, what indicates a block of consecutive statements, and what ends an executable line of code. The following sections cover four of the six different types of statements in Java:
The other two are variable declaration statements and other statements. They're covered in Chapter 5 and Chapter 4, respectively.
With the simple arithmetic operators plus, minus, multiply, and divide (+, -, *, /), you can build simple arithmetic expressions in both Java and RPG. For example, X+1 or Y +2/3 are simple expressions, where X and Y are variables. The following examples demonstrate different expressions you may use in your programs:
1.8 / 3 X+2-3+I amountDue > 0
On their own, these expressions are not very interesting, but even if you end them in a semicolon, they are not valid statements. Instead, they are used as part of a statement for their value. For example, you can assign expressions in a program to a variable, thus turning the expression into an assignment statement. To do this, you use a field on the left side with the assignment operator (equal sign), as follows:
myvalue = 1.8 / 3 result = X+2-3+I
Notice in these examples that the white space between the operators is generally not important, although consistency does aid readability. These examples show how you might code some sample expressions in your program, but they are not syntactically correct for Java statements. Can you guess why not? To make these valid expression assignment statements, you must end each with a semicolon. Obviously, RPG, as a column-oriented language, has no construct like the statement terminator. However, even for RPG, these expressions are valid only when used with one of the free-format factor-two op-codes to form a statement.
An expression statement consists of an expression that is executed for its side effects. For instance, the assignment expression has the side effect of altering the value of a variable (the operand on the left side of the statement). A method (in Java) or procedure (in RPG) call can have the side effects of the call. If you don't care about the returned value (or it doesn't return anything), you can just code the method call without assigning the result in an assignment statement. For example, this is a legal Java statement:
myObject.myMethod();
The other expression statements in Java are the pre- and post-increment and -decrement expression statements (covered later), and the new operator expression statement. You saw the new operator in Chapter 2, and almost always assign the result of it to an object reference variable to form an assignment statement. However, you can also code a call to new as a standalone statement by itself, just for the side effect of creating the object. (Maybe it starts the payroll system in its constructor!) For example, this is a legal Java statement:
new Payroll();
A Java block statement groups together a sequence of one or more statements. The group is delimited by enclosing it with a starting brace, {, and a closing brace, }. A semicolon is used to end each statement in the sequence, as usual. There is no semicolon after either brace. Braces can be used to group declarations and statements together into a single entity, or block. They are syntactically equivalent to single braces that surround the statements of a class or method. You can also group multiple statements together after an if or while structure. For example, you can block the expression statements used in the previous example as follows:
{ myvalue = 1.8 / 3; result = X+2-3+I; }
This block is syntactically correct. The compiler will not issue any errors for it. However, it would be more typical for you to block a group of statements in order to make them look equivalent to a single statement. You can then apply an if or a loop condition before the block. The compiler will execute the block only if the condition is met. Another reason to use blocks is to define a set of variables locally in the block. If you try to reference one of these variables outside the block, the compiler will indicate that it is not declared. For example, the if statement syntax in Java is as follows:
if (expression) statement;
To condition the previous example, you would code an if with its expression above the block. This indicates to the compiler that you want the block to execute only when the expression evaluates to true. To use an if condition with a block of code, you would code as follows:
if (expression) { float myvalue; // declare a float type variable called myvalue int result; // declare an integer type variable called result myvalue = 1.8 / 3; result = X+2-3+I; }
It is important to note that the block is treated as a single statement. That is, either all or none of the statements inside it are executed. If you only had one statement to execute after the if, you would not need the braces. For example, the following if statement is syntactically correct:
if (x == 2) x = x+1;
You normally use a block statement when you want to execute more than one statement after an if or while condition. Braces are allowed, but optional when you have only one statement to execute. In other words, you could have coded the example as follows:
if (x == 2) { x = x + 1; }
In Java, the double equal sign, ==, distinguishes comparisons such as this one from assignment statements that use the single equal sign. Note also that assignment statements are not allowed inside a conditional expression like this. Only expressions that evaluate to true or false are allowed. This is different than C, and leads to many bugs in C when a single equal sign is used in a relational expression by mistake.
The simplest kind of Java statement is an empty one. You now know that Java statements must end with a semicolon. Consider statements like this:
if (x == 2) ; for (i = 0; i < 10; i = i + 1) { ; }
Are they syntactically correct? (Do not worry about the syntax of the for statement for now.) Yes. A semicolon on its own with nothing preceding it is just another Java statement. It is called the empty statement. Empty statements are very rarely used, but they appear occasionally as the true part of an if statement when all you are interested in is the else part, for example:
if (x > 2) ; else // interesting statements
This, however, is more elegantly coded by negating the conditional expression. Also notice that an equivalent to the empty statement is an empty block, for example:
if (x > 2) {}
Java labels are similar to the RPG TAG operation code, with the tag name specified in factor one. In Java, you can have one or more labels separated by a colon. The following example shows a label definition:
ReturnPoint: while (x>10) { // code }
In RPG, a TAG can be specified on any line. In Java, too, any line can be labeled. However, the compiler only recognizes a label at the beginning of a loop, such as a while or for loop, when it is used as a target with the break or continue statement. Also, label names are independent of all other kinds of names used in the program. For example, you can have a variable defined as an integer and, in the same block of code, also have a label with the same name. The compiler can distinguish between both entities. The most common use of labels is with the break statement. Listing 3.2 illustrates this usage.
Listing 3.2: The Java break Statement
int index = 1; int index2 = 1; outerLoop: while(true) { index = index + 1; index2 = 1; innerLoop: while(true) { index2 = index2 + 1; if (index2 == 3) break outerLoop; } }
First, two loops are defined, one outer and one nested inner. The outer loop is labeled outerLoop, and you are then able to exit directly from that outer loop using a labeled break statement. If you did not specify the outerLoop parameter with break, you could only have exited the innermost loop. Note that you are not jumping to a labeled state ment, but rather exiting from a labeled loop. (The if, for, while, and break statements are covered in detail in the next chapter.)
Listing 3.3 illustrates all of the Java statement types. To get extra credit for this lesson, take a little pop quiz by considering each statement. Decide which ones are syntactically correct and which ones the Java compiler would flag as an error.
Listing 3.3: Examples of All Java Statements
public class Statement { public static void main(String args[]) { int x = 8; for (int i=0;i<10;i++) { } label1: while(x<0) { break label1; ; } if (x == 10); ; {}; { System.out.println("I am in a block!"); } label0:; label2:label3:label4:; } }
The first structure is a for loop with all header information correctly specified. It includes an empty block. This is syntactically correct in Java. Next, a labeled statement has a loop that breaks out of the label. Again, this is correct. On the line after the break label1; statement, an empty statement is specified. Next, the statement if ( x==10 ); is a correctly specified if statement with an empty body. Then, there is an empty block, followed immediately by an empty statement. Both are valid in Java, and so is the block that includes the println statement. Finally, several labels are defined, separated by colons. This is also correct.
As it turns out, all of the Java code in this example compiles cleanly. It is not terribly useful, but it is valid. It demonstrates many of Java's syntax rules and statement types. Feel free to use it!
Expressions in RPG and Java are used to fetch, compute, and store values. Those that compute and store values are referred to as computational expressions, and those that simply fetch a value without altering it are called fetch expressions. (We'll cover the latter later.)
Table 3.6 illustrates the simplest form of a computational expression. The RPG expression *IN(99) will return zero or one, and end the loop if it is zero. The Java expression (in99) will return true or false and end the loop if it is false. (The variable must be declared boolean in this case.) Both of these are computation expressions. They don't do much computation, however, other than return the current value in the variable and test it for truth or falsity.
RPG |
Java |
||
---|---|---|---|
C |
DOW |
*IN(99) |
while(in99) |
C |
{ |
||
C |
ENDDO |
} |
Table 3.7 illustrates another computational expression. This expression computes the value x+1 and stores the result of the computation back into x. Strictly speaking, in both columns of Table 3.7, only "x=x+1" is an expression. The EVAL op-code in RPG makes it a statement, and the semicolon in Java makes it a statement. Unlike RPG, though, that expression in Java is also valid in other situations. For example, in Java, it would be legal to code this:
y = (x = x + 1);
In this case, that whole expression of (x =x+1) is used as a sub-expression in an expression assignment statement. In this case, the nested assignment is actually performed, so the side effect of this is to not only assign a value to y, but also to assign a new value to x! This is not a good programming style, but alas, it is legal.
RPG |
Java |
|
---|---|---|
C |
EVAL x = x + 1 |
x = x + 1; |
The following sections discuss computational expressions and their associated operators in both RPG IV and Java, followed by a discussion of fetch expressions.
Operators are commonly classified by the number of values (operands or parameters) on which they operate. This distinction is useful because some operators have different (al- though related) meanings, depending on whether they are combined with two operands or only one. For example, if you remember algebra from your school days, you know that you can use -i as the equivalent of 0-i, right? In the first case, the minus sign acts on the single numeric value, performing negation; in the second, it is operating on two numeric values. An operator that acts on a single operand is known as a unary operator. An operator that acts on two operands is known as a binary operator. In this example, the minus sign can be used as either a binary or a unary operator.
Arithmetic operators
Arithmetic operators are the simplest and, probably, the most used in all languages. Table 3.8 lists all of the arithmetic binary operators used in both RPG and Java.
Java |
RPG Op-code RPG |
Expression |
---|---|---|
+ (addition) |
ADD or Z-ADD |
+ |
- (subtraction) |
SUB or Z-SUB |
- |
* (multiplication) |
MULT |
* |
/ (division) |
DIV |
/ |
% (modulus or remainder) |
MVR |
%REM |
** (exponent) |
The binary arithmetic operators are +, -, *, and /, and the modulus operator %. In RPG, you use the MVR (Move Remainder) operation code or the %REM built-in function to accomplish what the modulus operator provides in Java. An important point to remember is that RPG IV, through free-form factor two, supports free-form expressions that very closely match what Java supports. In addition, to make things easier in RPG IV, many new operators have been introduced in the language, which we will use in comparison to Java. In all of the examples used in this chapter, you can still use the fixed-form operation codes provided. However, because you are already familiar with these and not the free-form operators, our examples include free-form expressions with the newly introduced operators.
Consider the examples in Table 3.9, which show different expressions using the various binary arithmetic operators in both languages, but using RPG's new EVAL op-code. In the first example, the additive operator + adds the value contained in [B78] to one, and places the sum back in variable X. The +, -, *, and / arithmetic binary operators are similar in the way they operate.
RPG |
Java |
||
---|---|---|---|
C |
EVAL |
X=X+1 |
X=X+1; |
C |
EVAL |
X = X / 2 |
X = X / 2; |
C |
EVAL |
A = A + 2 * 3 |
A = A + 2 * 3; |
C |
EVAL |
A = (A - 3) / 2 |
A = (A - 3) / 2 |
The next example uses the division operator to divide X by two. The next two examples show expressions that use the additive and multiplicative operators. In the first case, given that the precedence of * and / are higher than - and +, the number two is multiplied by three, the result is added to the variable A, and then the result is stored back in A. In the last example, the parentheses force the addition to occur before the multiplication. As you will see later in this chapter when you learn about operator precedence, the parentheses have higher precedence than any of these arithmetic operators.
The binary modulus operator (%) produces a pure value that is the remainder from an implied division of its operands. As mentioned earlier, this is equivalent to using the DIV operation code in RPG followed by the MVR operation code.
The expressions in Table 3.10 calculate the number of minutes and seconds, given a value in seconds. If X contains the value 185 seconds, the division operation produces a value of three minutes, and the remainder produces a value of five seconds. Alternatively, in RPG, you can replace the two statements with statements using eval, minutes = %DIV(X:60), and seconds = %REM(X:60).
RPG |
Java |
||||
---|---|---|---|---|---|
C |
X |
DIV |
60 |
minutes |
minutes = X / 60; |
C |
MVR |
seconds |
seconds = X % 60; |
The only operator not yet discussed is the exponentiation (**) operator. This operator is used in RPG IV, but not in Java. Instead, Java provides a method supplied in its Math class that supports this function. This is covered later in this chapter.
Assignment operators
Once a variable has been declared, you can assign a value or a field to it using the assignment operator, =. In fact, this simple form of assignment operator was used in the previous section. To assign a value of zero to the field X, you code as in Table 3.11.
RPG |
Java |
||
---|---|---|---|
C |
EVAL |
X = 0 |
X = 0; |
In the case of RPG, the MOVE operation code could be called an assignment operator because it accomplishes the same function. However, you should try using the new EVAL operation code instead. This way of coding is more structured and flexible.
To reduce the number of assignment statements, Java allows the stringing of variables together. If you want to assign three variables to the same value, you can string them all together in a single statement, as follows:
A = B = C = 25;
In this example, all variables will contain the value 25. RPG does not support this structure in its free-form format.
Java takes this concept of reduction one step further and introduces short forms of the assignment statement for cases when the assignee is also one of the operands. With an expression such as x=x+1; the language designers noticed that the variable on the left side is repeated on the right side of the assignment operator. They shortened this construct to x+= 1; and produced a new set of variations for assignment statement, called a contracted operator. For example, the combination of + and = operators creates a new operator, the += operator. These operators are shown in Table 3.12.
Operator |
Example |
Meaning |
---|---|---|
= |
A = A+B |
assignment |
+= |
A += B |
A = A + B |
-= |
A -= B |
A = A — B |
/= |
A /= B |
A = A / B |
*= |
A *= B |
A = A * B |
%= |
A %= B |
A = A % B |
^= |
A ^= B |
A = A ^ B |
&= |
A &= B |
A = A & B |
|= |
A |= B |
A = A | B |
<= |
A <= B |
A = A < B |
>= |
A >= B |
A = A > B |
>>= |
A >>= B |
A = A >> B |
Given that there are many other binary operators in Java, the language designers introduced the new x= operator where x stands for other supported binary operators. These include not only the arithmetic operators you have already seen, but all binary operators: +, -, /, *, %, ^, &, |, <, >, and >>.
The general rule is, if expression1 and expression2 are expressions, then expression1 x= expression2 is equivalent to expression1 = expression1 x expression2 where x stands for one of the operators mentioned. Obviously, both forms are allowed in Java (and in C and C++ as well). This format is a shorthand version that accomplishes the same thing with less typing. It hails originally from C, where the design philosophy was "less is more."
These contracted operators are not totally foreign to RPG programmers. Really, they are a shorthand that is exactly the same as using the ADD, SUB, MULT, and DIV op-codes without a factor-one value. In RPG, this means to perform the operation using factor two and the result field, and place the answer back into the result field.
Incrementing, decrementing, and unary operators
Java provides two unusual operators, also borrowed from C, for incrementing and decrementing variables. The increment operator, ++, adds one to its operand, while the decrement operator, --, subtracts one from its operand. These are most commonly used to increment or decrement the index of an array or other incrementing value inside a loop. Table 3.13 illustrates a while loop that uses the ++ operator for incrementing its index.
RPG |
Java |
||
---|---|---|---|
C |
EVAL |
IDX = 1 |
idx = 0; |
C |
DOW |
(IDX <= 10) |
while (idx < 10) |
C* |
: Some code |
{ |
|
C |
EVAL |
IDX = IDX +1 |
// some code |
C |
ENDDO |
idx ++; |
|
} |
This example also shows an RPG DOW (do-while) loop that is similar to Java. The primary difference between them is in the way you increment the index. In RPG, a common way to do this is to use the EVAL operation code and add one to the index. You can also use the ADD operation code to increment the field by one. In Java, using the traditional assignment statement with the + operator is valid, too, as in:
idx = idx + 1;
These operators are unusual in that both ++ and- can be used as either prefix or suffix operators. In the preceding example, the ++ is used as a suffix operator; that is, the ++ is placed after the operand. To use it as a prefix operator, you would code the expression as follows:
++idx;
What is the difference between these two forms? When the ++ and - are prefix operators, the operand will be incremented or decremented by one before its value is used in the expression. When used as suffix operators, the operand will be incremented or decremented by one after its value has been used in the expression.
Consider the examples in Listing 3.4. In the first case, the ++ operator prefixes the variable a. The operand a is incremented by one (changed to six) before it is used in the expression. This value, in turn, is added to 50, and the sum 56 is placed in the variable x. In the second case, 50 is added to the content of operand b, which is five, and the sum of 55 is placed in the variable y.
Listing 3.4: Examples of Prefix and Suffix Increment Operator
public class PrefixSuffix { public static void main(String args[]) { int a = 5; int b = 5; int x = ++a + 50; // x is 56 after execution System.out.println("x = " + x + ", a = " + a); int y = 50 + b++; // y is 55 after execution System.out.println("y = " + y + ", b = " + b); } }
Compiling and running Listing 3.4 gives the following (remember the main method is called by Java when a class is run from the command line):
>javac PrefixSuffix.java >java PrefixSuffix x = 56, a = 6 y = 55, b = 6
Note that x=++a +50 is equivalent to this:
a = a + 1; x = a + 50;
Something else is unique about these operators. Unlike all other arithmetic operators, they have side effects on their operands even when used in fetch expressions, such as the right side of an assignment statement. Beware of this!
In the preceding example, for instance, both a and b are affected by the statements. At the end, both have been incremented. The difference between prefix and suffix use is relative to the target of the assignment statement, but, as far as the variables a and b are concerned, both had the same effect of increasing their value by one. As part of the expression evaluation, the value of b is incremented to six; however, the increment occurs after the expression has been evaluated because the ++ operator is used as a suffix. It is because of this unique side effect that expressions with these operators can be used as standalone with a semicolon to form a valid expression statement, as mentioned earlier. So, this is valid in Java:
price++;
It has the effect of incrementing price. Since the other operators, like +, -, * and /, have no side effects on their operands, you are not allowed to add a semicolon and turn them into statements; they would be meaningless. The following, then, are not valid in Java (and result in "invalid expression statement" errors from the compiler):
price - discount; price * tax; -5;
The increment and decrement operators are similar to those in C and C++, with the exception that C and C++ do not allow the operand to be of type float. Notice also that these operators can only be applied to variable operands; they cannot be applied to expressions. For example, expressions like (a+b)++ or (a+b)- are invalid. Both of these operators are considered unary operators because they are used with one operand.
Table 3.14 lists the RPG and Java unary arithmetic operators. These operators take exactly one argument.
Operator |
RPG Operator |
Java Operator |
---|---|---|
Increment |
N/A |
++ |
Decrement |
N/A |
— |
Unary plus |
+ |
+ |
Unary minus |
- |
- |
Table 3.15 illustrate how to use the unary minus and plus operators in both RPG and Java. It's interesting to note that the unary plus operator really does nothing, while the unary minus operator actually negates the given operand. Thus, if y is set to -1, then -y evaluates to 1, while +y evaluates to -1.
RPG |
Java |
||
---|---|---|---|
C |
EVAL |
X = -X |
X = -x; |
C |
EVAL |
x = +x |
x = +x; |
Relational operators
RPG and Java have several operators for testing equality and magnitude, or relationships. All relational expressions using these operators return a boolean value of true or false. For example, to test if variable X is greater than 10, you can have a simple relational expression such as X>10 in both languages.
This expression is most useful when used in conditional or loop statements to determine the flow of control, as you will see in detail in the next chapter. For example, it is often used as the expression test in an if statement or the loop-termination test in an RPG dow loop or Java while loop. Simple relational expressions use the operators >, >=, <, <= in both languages, while RPG uses = and for equality and inequality comparisons, versus the Java operators == and !=. Table 3.16 summarizes the available relational operators in both RPG and Java, including the older RPG fixed-format op-code suffixes.
RPG XX |
RPG Expression |
Java |
Description |
---|---|---|---|
EQ |
= |
== |
equal |
NE |
!= |
not equal |
|
GT |
> |
> |
greater than |
LT |
< |
< |
less than |
GE |
>= |
>= |
greater than or equal |
LE |
<= |
<= |
less than or equal |
Table 3.17 illustrates a simple relational expression used on an if statement. This is a straightforward test of a simple relational expression that tests for equality to determine conditionally whether to execute a subsequent block of statements.
RPG |
Java |
|
---|---|---|
C |
IF prefix = 'A' |
if (prefix == 'A') |
C* |
some code |
{ |
C* |
more code |
// code |
C |
ENDIF |
} |
Logical operators
Simple relational expressions that use the relational operators listed in Table 3.16 can be combined by using logical operators to form a more complex test. The logical binary operators are AND and OR in RPG, while Java uses && and || and an additional one, ^. Java uses doubled-up characters for its relational operator ==, and its logical operators || and && . This is to clearly distinguish them from the similar-looking but different operators =, |, and &. (The last two are bitwise operators you'll learn about soon.) Negation of a simple relational expression is done with the NOT operator in RPG and the ! operator in Java.
These logical operators can combine simple relational expressions or even combine other combined expressions. As long as the sub-expressions being combined or negated evaluate to true or false, you can use the logical operators to form a larger test.
Let's look at some examples of combined simple relational expressions. If you want to test whether the variable age is greater than 10 and less than 20, you can have an RPG logical expression such as this:
(age>10) AND (age<20)
The Java equivalent is this:
((age>10) && (age<20))
This syntax combines the two relational expressions using the AND operator, and will only evaluate to true if both sub-expressions evaluate to true. Again, the use of blanks in the expressions is totally optional, as expressions are free-format in both languages. For example, many people prefer to code (age > 10) instead of (age>10). The use of parentheses around the sub-expressions is also optional, but often used for readability, or to be sure the compiler interprets the expression correctly. However, one difference between the languages is that Java requires parentheses around the entire expression, whether it is a simple relational expression or a combined logical expression, as you saw in the Java column of Table 3.17. RPG, on the other hand, does not force this requirement, but does allow it optionally.
If you want to test whether the variable age is less than 11 or greater than 19, you can have an RPG logical expression such as this:
(age<=10) OR (age>=20)
The Java equivalent is this:
((age<=10) || (age>=20))
This combines the two relational expressions with the OR operator, and will evaluate to true if either sub-expression is true.
Java has an additional binary logical operator that is not supported in RPG, namely the exclusive OR operator, ^, for example:
((age <= 10) ^ (day == 2))
With this operator, the expression will evaluate to true if exactly one of the sub-expressions evaluates to true. However, it will evaluate to false if they are both true! Obviously, this is a rarely needed operator, which underscores RPG's decision not to include it.
Consider the OR example: "age less than 11 or greater than 19." It really is the opposite of the AND example. That is, you could have worded the test "if it is not the case that the age is greater than 10 and less than 20." So, you could have coded that last example by negating the logical expression from the AND example. In RPG, this would be:
NOT ((age>10) AND (age<20))
The Java equivalent is this:
(! ((age>10) && (age<20)))
Notice that the negation operator works on a single expression, not two expressions like the previous logical operators. To reflect that, we prefer to put the entire expression being negated inside parentheses, as you see. Then, for Java, we have to again put the entire expression, including the negation operator, inside parentheses as per Java's rules. Hence, all these parentheses! The negation operator negates the expression that follows it. Therefore, the entire expression results in true if the negated expression returns false. If the negated expression returns true, the entire expression returns false.
For both languages (really, for all languages), it is very helpful when using negation to know DeMorgan's Rule from the study of algebra. This rule describes how to negate a boolean expression of any complexity, and can save you much head-scratching when you try to manually ripple a negation through an expression, or even read a negation expression. The rule is, to negate an OR expression, negate each operand and change the OR to an AND. To negate an AND expression, negate each operand and change the AND to an OR. For example, these are equivalent:
if ( !( (day != MON) || (age < 65) ) ) if ( (day == MON) && (age >= 65))
These are also equivalent:
if ( !( (day == MON) && (age >= 65) ) ) if ( (day != MON) || (age < 65))
Don't confuse the logical unary negation operators (NOT and !) with the relational binary inequality operators (<> and !=). The former negates an expression, while the latter compares two operands, returning true if they have different values. Table 3.18 summarizes the logical operators in RPG and Java.
RPG XX Op-codes |
RPG Op-codes |
Java |
Description |
---|---|---|---|
Orxx |
OR |
|| or | |
logical or |
ANDxx |
AND |
&& or & |
logical and |
NOT |
! |
logical not, or negation |
|
^ |
exclusive or |
You see that you can use the single & and | operators, as well the doubled-up versions. Be careful, however; the difference between these two operators is in the internal expression evaluation. For the & operator, both sides of the expression are evaluated regardless of the outcome. For the && operator, if the left side of the expression is false, the entire expression is obviously false, and the right side is never evaluated. Similarly, for the | operator, both sides are also evaluated, while for ||, the right side is never evaluated if the left side is true, as that means the whole expression is true.
We recommend always using the doubled-up version, as sometimes the right side is not valid if the left is true, for example ((x != 0) & ((y / x) > 0)). In this case, if x equals zero (the left sub-expression is false), you would be dividing y by zero in the right sub-expression.
As you will see in the following section on bitwise operators, the operators & , |, and ^ are used with bit manipulations, as well.
Bitwise operators
The RPG language only supports TESTB, BITON, and BITOFF op-codes for bitwise manipulation. Java, on the other hand, has seven bitwise operators that allow you to perform operations on individual bits in integer values, as shown in Table 3.19.
Bitwise Operator |
Meaning |
---|---|
& |
Bitwise AND |
| |
Bitwise OR |
^ |
Bitwise Exclusive OR |
~ |
Bitwise negation |
< < |
Left Shift |
> > |
Right Shift |
> > > |
Zero fill right shift |
All of these operators are inherited from the C and C++ languages. (And, yes, you too can be a "bit wiser.") It is very important to keep in mind that bitwise operators work only on integer types. Using any other type causes a compiler error. This is different than RPG's op-codes, which only work on character fields or hexadecimal literals or constants.
The bitwise AND (&) operator is often used to mask off some set of bits. It produces a value that is the bitwise AND of its operands. The bitwise & works on bits, whereas the logical && works on boolean values. Traversing each operand bit by bit, if the corresponding bits in both of the operands are ones, the corresponding bit in the result variable is set to one. Otherwise, the corresponding bit in the result variable is set to zero. This is similar to the logical AND where the resulting value is true if both operands evaluate to true, otherwise false, as shown in Listing 3.5.
Listing 3.5: The Bitwise & Operator in Java
public class Bit { public static void main(String args[]) { int firstNum = 14; int secondNum = 12; int result; result = firstNum & secondNum; System.out.println("The result is : " + result); } }
Listing 3.5 performs a bitwise & on two integer operands that contain the values 14 and 12. Knowing this, the internal representation of these two operand fields and of the resulting field is shown here in bit format:
firstNum == 14 == '00000000 00000000 00000000 00001110' secondNum == 12 == '00000000 00000000 00000000 00001100' ———————————————————————————————————————————————————————— result == 12 == '00000000 00000000 00000000 00001100' (after &)
In this case, only the third and fourth bits have a one in both operands. That means that all of the values of the result field will be zero except these positions. This value evaluates to 22 + 23, which equals 12. Therefore, the println method will print the value 12.
If you have followed the example so far, then the other bitwise operators will be just as easy to understand. The bitwise OR operator (|) traverses the operands bit by bit. A one is returned in the result value at each bit position when either of the two operand values have one in the same bit position. Otherwise, it is zero. By comparison, the exclusive OR operator (^) returns a one at each bit position when the two values have opposite values in the same bit position. Listing 3.6 shows an example of these.
Listing 3.6: The Bitwise OR and Bitwise Exclusive OR Operators in Java
public class OrxOr { public static void main(String args[]) { int firstNum = 14; int secondNum = 12; int firstResult, secondResult; firstResult = (byte) (firstNum | secondNum); System.out.println("First result: " + firstResult); secondResult = (byte) (firstNum ^ secondNum); System.out.println("Second result: " + secondResult); } }
Listing 3.6 uses the operand values of 12 and 14 again. Here are the bit values of the operands and two results after doing a bitwise OR and bitwise exclusive OR:
firstNum == 14 == '00000000 00000000 00000000 00001110' secondNum == 12 == '00000000 00000000 00000000 00001100' ——————————————————————————————————————————————————————————— firstResult == 14 == '00000000 00000000 00000000 00001110' (after |) secondResult == 2 == '00000000 00000000 00000000 00000010' (after ^)
All this talk about twiddling bits might have you wondering how to print out the binary version of an integer variable. This is jumping ahead a bit, but there are classes in Java that mimic each of the built-in data types and supply some cool methods. The one we want is the Integer class, and the method is the static method toBinaryString, which takes an integer as input and outputs a string containing its binary or bitwise value. You might want to create your own static method named printBits in your own helper class that, in turn, uses this Integer method:
public static void printBits(String name, int x) { System.out.println(name + " == " + x + " == " + Integer.toBinaryString(x)); }
Calling this with the firstNum and secondNum variables you have seen so far gives the following output (note that leading-zero value bits are not printed):
firstNum == 14 == 1110 secondNum == 12 == 1100
The inverse operator (~) is similar to the logical negation operator (!), but at the bit level. That is, it negates whatever the value is in each bit of the operand. So ones become zeros and zeros become ones. Imagine, for example, that the previous examples changes to this:
firstNum = ~firstNum; secondNum = ~secondNum;
You would get the following before and after results:
firstNum == '00000000 00000000 00000000 00001110' (before) secondNum == '00000000 00000000 00000000 00001100' (before) ——————————————————————————————————————————————————————————— firstNum == '11111111 11111111 11111111 11110001' (after ~) secondNum == '11111111 11111111 11111111 11110011' (after ~)
Shift operators
The shift operators complete our discussion of bitwise operators. As you work with the bits that make up an integer number, some operations might require you to shift the bit values to the right or to the left. In Java, this operation is performed with the left bitwise shift operator, <<, and the right bitwise shift operator, >>. Listing 3.7 illustrates how these operators work.
Listing 3.7: Shift Operators in Java
public class Shift { public static void main(String args[]) { int firstNum = 2; int firstResult, secondResult; firstResult = (firstNum < 2); System.out.println("The first result is : " + firstResult); secondResult = (firstResult > 1); System.out.println("The second result is : " + secondResult); } }
You start by initializing the variable firstNum to two. This is represented internally by the following sequence of bits, shown for firstNum:
firstNum == 2 == '00000000 00000000 00000000 00000010' —————————————————————————————————————————————————————————— firstResult == 8 == '00000000 00000000 00000000 00001000' secondResult == 4 == '00000000 00000000 00000000 00000100'
The first operation performed on the variable shifts it left twice. Then, you use the result from the first operation to shift right once. As a result, the internal representation for each of the variables firstResult and secondResult is as shown. Notice that shifting left is equivalent to multiplying by the corresponding power of two, and shifting right is equivalent to dividing by the corresponding power of two, with possible truncation in both cases. These operations are generally more efficient than using multiplication or division, however.
Unlike the inconsistencies found in some implementations of C and C++, Java always preserves the sign bit (the leftmost bit) after performing the right bitwise shift. To handle this situation, Java introduces a new bitwise operator, the shift-right operator, >>>. The difference between >>> and the other shift-right operator, >>, is that the >>> operator does not preserve the leftmost sign bit. In other words, the operator always sets the leftmost bit to zero.
After all this, keep in mind that all these bitwise operators are very rarely used in business applications!
Conditional operators
Another of Java's short-form operators is the conditional operator (? :), also called a ternary operator. This operator is similar to the one in C and C++. RPG IV does not have it. This operator, a short version of the if statement, is used to choose alternate values for a variable, based on an expression that evaluates to true or false. The following example shows how to use this operator and compares its use to the if statement (explained in more detail in the following chapter):
result = (idx == 20) ? 30 : 35; // same as... if (idx == 20) result = 30; else result = 35;
The conditional boolean expression, written with the ternary operator ?:, provides an alternate way to write similar constructs. The boolean expression before the ? is evaluated first. If it is true, then the expression between the ? and : is evaluated, and its value is assigned to the left-hand variable (result, in our example). Otherwise, the expression between the : and ; is evaluated, and its value is assigned to the left-hand variable.
Conditional expressions are only suitable when you want to return one of two values, depending on the value of a boolean expression. Conditional expressions are compact; they save you a few keystrokes. Once you become accustomed to their notation, as with the increment (++) and decrement (-) operators, you might find them faster to code (even if longer to read!) than their longer equivalents. However, if you don't like them, you don't have to use them.
Operator precedence
So far, you have seen all of the Java and RPG operators that you can use in expressions. This section discusses operator precedence: the order of evaluation of multiple operators in expressions. That is, these are the rules that govern which operator is evaluated first, second, third, and so on. Operator precedence is important in any programming language; it determines the final result of an expression, which depends on the order in which operands are evaluated. Table 3.20 summarizes operator precedence in RPG IV.
( ) Built-in functions, user-defined procedures unary +, unary -, NOT ** *, / Binary +, and Binary - =, , >, >=, <, <= AND OR |
In an earlier program example, you saw the expression A+2*3. If the value of A is four, what would the result be after evaluation? Would it be 18 or 10? If you add first, the final value will be 4+2, or six, multiplied by three, which gives the result 18. However, if you multiply first, the value will be 2*3, or six, with 4 added, which gives the result 10. This is why operator precedence has to be established.
As you can see in Table 3.20, the multiplication operator has higher precedence, so the value of the expression is 10. Multiplication will be done first, followed by addition. In fact, this is the logic that the compiler uses to establish the evaluation of any given expression in a language. High-precedence operators are evaluated before low-precedence operators.
What happens if you have operators with the same precedence? For example, what would the expression (X /4*3) evaluate to? If X is 12, would the result be 1 or 9? The result depends on how the compiler parses and evaluates the line. Is parsing done from left to right, or right to left? For the multiplication and division operators, RPG and Java parse and evaluate from left to right. This means that the expression in both languages evaluates to 9.
The Java operator precedence and associativity is shown in Table 3.21. Again, operators at the top of the table have higher precedence than those below them. For operators that have equal precedence, the "Associativity" column indicates which ones will be evaluated first. For example, in the case of the * and / operators, evaluation is done left to right, as indicated by the L in the column. On the other hand, the operators ++, -, ~, !, -, and (type cast) are evaluated from right-to-left. (Type casting is discussed in Chapter 5, string concatenation in Chapter 7, and the instanceof operator in Chapter 9.)
Operators |
Associativity |
---|---|
() |
L |
++, —, ~, !, -, (type cast) |
R |
*, /, % |
L |
+, - |
L |
+ (concat operator) |
L |
>> |
L |
>, < |
L |
<, <=, >, >= |
L |
instanceof |
L |
= =, != |
L |
& |
L |
^ |
L |
&& | |
L |
| | |
L |
?: |
R |
=, *=, /=, %=, +=, -=, <=, >=, >>=, &=, ^=, |= |
R |
You have learned about computational expressions, which compute a boolean or arithmetic value. The following sections discuss the other kind of expressions, fetch expressions, which are the most elementary type. They don't compute a value, they get, or fetch, a value. The different kinds of fetch expressions are null, method call, and array index.
Null expressions
The fetch expression null produces a special object reference value that does not refer to any object, but is assignment-compatible with all object reference types. These are simply any variable declared to be of a class type, as described in the previous chapter. The null is the default value for these types of variables before they have been assigned to an object by using the new operator. Keep in mind that, if you subsequently assigned an object reference variable to null, the object it was pointing to will be left "dangling" if no other variables point to it. Hence, the garbage collector will sweep it up. The null value is most easily thought of as a language-supplied constant, but it is actually an expression, a fetch expression. This is splitting hairs, though, and not of much consequence. (Notice, however, that null is not considered a zero as it is in C and C++.)
If you need to determine whether an object reference variable has yet to be assigned to an object, you can compare it to null, as in:
if (myObject == null) // not instantiated yet? myObject = new MyClass(); // instantiate it now
Method call and array index expressions
A method call expression is a primary expression that invokes a method. This is similar to a procedure call expression in RPG IV. A method call expression fetches a value returned by the method or the procedure. Similarly, an array index expression produces an array element value when it is evaluated. Arrays are indexed using square brackets in Java. (Arrays are covered in detail in Chapter 6; they are mentioned here only for completeness.) In both cases, the returned or fetched value can then be used in-place in an expression, as though a variable had been used. The following illustrates both of these expressions:
if (stateObject.getStateTax() > 0) ... if (stateTaxArray[stateIndex] > 0) ...
Earlier in this chapter, you saw the basic math operators that are used in expressions. These include +, -, *, /, and %. However, RPG and Java support many other mathematical functions, such as op-codes and built-in functions in RPG, and supplied methods in Java. The Java-supplied class Math contains methods for performing basic numeric operations, such as exponentiation, logarithms, square roots, and the trigonometric functions.
To help ensure the portability of Java programs, the definitions of many of the numeric functions in the Math class supplied by Java are implemented using certain accepted, published algorithms. These algorithms are available from the well-known network library NETLIB in the package "Freely Distributable Math Library" (FDLIBM). These algorithms, which are written in the C programming language, were rewritten in Java and supplied as the Java Math class. The Java Math library is defined with respect to the version of FDLIBM dated January 4, 1995.
Listing 3.8 shows an example of the RPG %ABS (absolute) built-in function. The fields firstNum and secondNum are zoned (4,0) and initialized to the values 40 and 65, respectively. On the C-spec, you perform two different calculations using the EVAL operation code. In both calculations, the field with the larger value, secondNum, is subtracted from the field containing the smaller value, firstNum. In both cases, the subtraction results in a value of -25. The %ABS built-in function then returns the absolute value of -25, which is 25. Thus, %ABS returns the positive value of a given negative number. It has no effect on positive numbers. The output of the sample is -25 and 25.
Listing 3.8: The RPG %ABS Built-in Function
D firstNum S 4S 0 INZ(40) D secondNum S 4S 0 INZ(65) D result S 4S 0 C EVAL result = firstNum - secondNum C result DSPLY C EVAL result = %ABS(firstNum-secondNum) C result DSPLY
The same result can be accomplished in Java by using the Math class, which is found in the Java.lang package. Listing 3.9 illustrates the same example written in Java.
Listing 3.9: The Absolute (ABS) Java Method in the Math Class of the java.lang Package
public class ABS { public static void main(String args[]) { int firstNum = 40; int secondNum = 65; int result1, result2; result1 = firstNum - secondNum; result2 = Math.abs(firstNum - secondNum); System.out.println("First result is: " + result1); System.out.println("Absolute result is: " + result2); } }
As in the RPG example, two fields of type integer are declared and initialized to 40 and 65. In the first case, we just do the subtraction. In the second case, we subtract and then use the abs method to return the absolute value. Again, this gives -25 and 25, respectively. This is just one example of the many different methods available in the Math package.
Another straightforward math function in RPG and Java involves retrieving the square root of a given number. The special RPG op-code SQRT does what you need. Listing 3.10 declares a field with the value of nine and uses SQRT to find its square root. The expected result of three is returned.
Listing 3.10: The RPG IV SQRT Op-code
D test S 4S 0 INZ(9) D result S 4S 0 C* C SQRT test result C result DSPLY C EVAL *INLR = *ON
It is just as simple to do this in Java. The Math class contains the method sqrt for just this purpose. This method is available only for fields with a double data type (covered in Chapter 5). Listing 3.11 illustrates the Java way of getting the square root of nine.
Listing 3.11: The Square Root (sqrt) Java Method in the Math Class of the java.lang Package
public class SqRoot { public static void main (String args[]) { double firstNum = 9; double result; result = Math.sqrt(firstNum); System.out.println("The result is: " + result); } }
As you see can see, the static method sqrt is used with a nine as the parameter. This results in a three being returned.
We have shown you only a couple of examples of the available methods in the Java Math class. There are many more, including those in Table 3.22.
Note |
These methods are all static, and therefore, resemble traditional, standalone functions in other non-OO languages. The exception is that, in order to call them, you must qualify the method name with the class name, as in Math.xxxx(). |
Method |
Description |
---|---|
abs(double) |
Returns the absolute value of a double value. |
abs(float) |
Returns the absolute value of a float value. |
abs(int) |
Returns the absolute value of an int value. |
abs(long) |
Returns the absolute value of a long value. |
acos(double) |
Returns the arc cosine of an angle, in the range of 0.0 through pi. |
asin(double) |
Returns the arc sine of an angle, in the range of -pi/2 through pi/2. |
atan(double) |
Returns the arc tangent of an angle, in the range of -pi/2 through pi/2. |
atan2(double,double) |
Returns the rectangular coordinates (b, a) to polar (r, theta). |
ceil(double) |
Returns the smallest (closest to negative infinity) double value that is not less than the argument and is equal to a mathematical integer. |
cos(double) |
Returns the trigonometric cosine of an angle. |
exp(double) |
Returns the exponential number (e.g., 2.718) raised to the power of a double value. |
floor(double) |
Returns the largest (closest to positive infinity) double value that is not greater than the argument and returns the greater of two double values. |
max(float, float) |
Returns the greater of two float values. |
max(int, int) |
Returns the greater of two int values. |
max(long, long) |
Returns the greater of two long values. |
min(double, double) |
Returns the smaller of two double values. |
min(float, float) |
Returns the smaller of two float values. |
min(int, int) |
Returns the smaller of two int values. |
min(long, long) |
Returns the smaller of two long values. |
pow(double, double) |
Returns the value of the first argument raised to the power of the second argument. |
Random() |
Returns a random number between 0.0 and 1.0. |
rint(double) |
Returns the closest integer to the argument. |
round(double) |
Returns the closest long to the argument. |
round(float) |
Returns the closest int to the argument. |
sin(double) |
Returns the trigonometric sine of an angle. |
sqrt(double) |
Returns the square root of a double value. |
tan(double) |
Returns the trigonometric tangent of an angle. |
In many cases, a method listed in the table may have an equivalent RPG built-in function or op-code that performs the same function. In some cases, though, there is no equivalent RPG functionality. In these cases, it is a good opportunity for you to plug that hole by writing a procedure! For example, in the next chapter, you will see a procedure named Max that gives the same function as Java's max method.
Finally, when arithmetic operators were discussed earlier in this chapter, we mentioned that RPG has an exponentiation operator, while Java does not. Listing 3.12 illustrates an expression that uses exponentiation in RPG. The DSPLY operation outputs the value of 16, which is the result of 24.
Listing 3.12: The Exponentiation Operator in RPG
D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++ D firstNum S 4S 0 INZ(2) D exp S 4S 0 INZ(4) D result S 4S 0 C* C EVAL result = firstNum ** exp C result DSPLY C EVAL *INLR = *ON
Although Java has no standalone exponentiation operator, it does have a static method named pow, again in the Math class. As an exercise, you might try experimenting with it.
This chapter introduced you to the following concepts:
Foreword