Thursday, February 4, 2016

Topic 37: Additional Keywords in Java

  • When an instance variable is declared as transient, then its value need not persist when an object is stored. For example:

class T
{
transient int a; // will not persist
int b; // will persist
}

Here, if an object of type T is written to a persistent storage area, the contents of "a" would not be saved, but the contents of "b" would.

  • Variable modified by volatile can be changed unexpectedly by other parts of the program. Specifying the variable as volatile tells the compiler that it must always use the master copy of a volatile variable (or, at least, always keep any private copies up-to-date with the master copy, and vice versa). Used mostly in multithreaded programming.

  • Sometimes, knowing the type of an object during run time is useful. For example, we might have one thread of execution that generates various types of objects, and another thread that processes these objects. In this situation, it might be useful for the processing thread to know the type of each object when it receives it. The instanceof operator has this general form: 

    objref instanceof type

Here, objref is a reference to an instance of a class, and type is a class type. If objref is of the specified type or can be cast into the specified type, then the instanceof operator evaluates to true. Otherwise, its result is false. The following program demonstrates instanceof:

// Demonstrate instanceof operator.
class A
{
int i, j;
}


class B
{
int i, j;
}


class C extends A
{
int k;
}


class InstanceOf
{
public static void main(String args[])
{
A a = new A();
B b = new B();
C c = new C();


if(a instanceof A)
System.out.println("a is instance of A");
if(b instanceof B)
System.out.println("b is instance of B");
if(c instanceof C)
System.out.println("c is instance of C");
if(c instanceof A)
System.out.println("c can be cast to A");
System.out.println();


// compare types of derived types
A ob = c; // A reference to c
System.out.println("ob now refers to c");
if(ob instanceof A)
System.out.println("ob can be cast to A");
System.out.println();
// all objects can be cast to Object
if(a instanceof Object)
System.out.println("a may be cast to Object");
if(b instanceof Object)
System.out.println("b may be cast to Object");
if(c instanceof Object)
System.out.println("c may be cast to Object");
}
}

  • By modifying a class or a method with strictfp, we  ensure that floating-point calculations (and thus all truncations) take place precisely as they did in earlier versions of Java. When a class is modified by strictfp, all the methods in the class are also modified by strictfp automatically. For example, the following fragment tells Java to use the original floating-point model for calculations in all methods defined within MyClass: 

    strictfp class MyClass { //...

Frankly, most programmers never need to use strictfp, because it affects only a very small class of problems.

  • Keyword assert is used during program development to create an assertion, which is a condition that should be true during the execution of the program. For example,we  might have a method that should always return a positive integer value. We might test this by asserting that the return value is greater than zero using an assert statement. At run time, if the condition actually is true, no other action takes place. However, if the condition is false, then an AssertionError is thrown. Assertions are often used during testing to verify that some expected condition is actually met. They are not usually used for released code.

The assert keyword has two forms. The first is shown here:


assert condition;

Here, condition is an expression that must evaluate to a Boolean result. If the result is true, then the assertion is true and no other action takes place. If the condition is false, then the assertion fails and a default AssertionError object is thrown.


The second form of assert is shown here:

assert condition : expr;

In this version, expr is a value that is passed to the AssertionError constructor. This value is converted to its string format and displayed if an assertion fails. Typically, we will specify a string for expr, but any non-void expression is allowed as long as it defines a reasonable string conversion.


Here is an example that uses assert. It verifies that the return value of getnum( ) is positive.

// Demonstrate assert.
class AssertDemo
{
static int val = 3;
// Return an integer.
static int getnum()
{
return val--;
}
public static void main(String args[])
{
int n;
for(int i=0; i < 10; i++)
{
n = getnum();
assert n > 0; // will fail when n is 0
System.out.println("n is " + n);
}
}
}

To enable assertion checking at run time, we must specify the -ea option. For example, to enable assertions for AssertDemo, execute it using this line:


java -ea AssertDemo

As explained, we can specify the message displayed when an assertion fails. For example, we can specify:


assert n > 0 : "n is negative!";

One important point to understand about assertions is that we must not rely on them to perform any action actually required by the program. The reason is that normally, released code will be run with assertions disabled. For ex:

assert (n = getnum()) > 0; // This is not a good idea!

This works fine if assertions are enabled, it will cause a malfunction when assertions are disabled, because the call to getnum( ) will never be executed! In fact, n must now be initialized, because the compiler will recognize that it might not be assigned a value by the assert statement.

Assertions are a good addition to Java because they streamline the type of error checking that is common during development. For example, prior to assert, if we wanted to verify that n was positive in the preceding program, we had to use a sequence of code similar to this:

if(n < 0){System.out.println("n is negative!"); return; // or throw an exception}

With assert, you need only one line of code. Furthermore, we don’t have to remove the assert statements from our released code.

When executing code, we can disable assertions by using the -da option. We can enable or disable a specific package by specifying its name after the -ea or -da option. For example, to enable assertions in a package called MyPack:


-ea:MyPack

To disable assertions in MyPack:


-da:MyPack

To enable or disable all subpackages of a package, follow the package name with three dots:


-ea:MyPack...

We can also specify a class with the -ea or -da option. For example, this enables AssertDemo individually:


-ea:AssertDemo

  • A new feature to Java called static import that expands the capabilities of the import keyword. By following import with the keyword static, an import statement can be used to import the static members of a class or interface. When using static import, it is possible to refer to static members directly by their names, without having to qualify them with the name of their class.
    To understand the usefulness of static import, let’s begin with an example that does not use it. The following code fragment computes the hypotenuse of a right triangle. It uses two static methods from Java’s built-in math class Math, which is part of java.lang. The first is Math.pow( ), which returns a value raised to a specified power. The second is Math.sqrt( ), which returns the square root of its argument.

// Notice how sqrt() and pow() must be qualified by their class name, which is Math.

hypot = Math.sqrt(Math.pow(side1, 2) + Math.pow(side2, 2));

Because pow( ) and sqrt( ) are static methods, they must be called through the use of their class’ name, Math. As this simple example illustrates, having to specify the class name each time pow( ) or sqrt( ) is used can grow tedious. We can use static import in such cases:

import static java.lang.Math.sqrt;

import static java.lang.Math.pow;

class Hypot {//...

hypot = sqrt(pow(side1, 2) + pow(side2, 2));

There are two general forms of the import static statement:

  • The first, brings into view a single name. Its general form is shown here:


import static pkg.type-name.static-member-name;

Here, type-name is the name of a class or interface that contains the desired static member. Its full package name is specified by pkg. The name of the member is specified by static-member-name.

  • The second form, imports all static members of a given class or interface. Its general form is shown here:


import static pkg.type-name.*;

One other point: in addition to importing the static members of classes and interfaces defined by the Java API, we can also use static import to import the static members of classes and interfaces that we create. If using a static member once or twice in the program, it’s best not to import it. Static import is designed for those situations in which we are using a static member repeatedly, such as when performing a series of mathematical computations.

  • When working with overloaded constructors, it is sometimes useful for one constructor to invoke another. In Java, this is accomplished by using another form of the this keyword. The general form is shown here: 

    this(arg-list)

When this( ) is executed, the overloaded constructor that matches the parameter list specified by arg-list is executed first. The call to this( ) must be the first statement within the constructor. To understand how this( ) can be used, let’s work through a short example. First, consider the following class that does not use this( ):

class MyClass
{
int a, b;
// initialize a and b individually
MyClass(int i, int j) { a = i; b = j; }
// initialize a and b to the same value
MyClass(int i) { a = b = i; }
// give a and b default values of 0
MyClass( ) { a = b = 0; }
}

By using this( ), it is possible to rewrite MyClass as shown here:

// initialize a and b individually

MyClass(int i, int j) { a = i; b = j; }

// initialize a and b to the same value
MyClass(int i)
{
this(i, i); // invokes MyClass(i, i)
}


// give a and b default values of 0
MyClass( )
{
this(0); // invokes MyClass(0)
}


In this version of MyClass, the only constructor that actually assigns values to the a and b fields is MyClass(int, int). The other two constructors simply invoke that constructor (either directly or indirectly) through this( ). For example, consider what happens when this statement executes:

MyClass mc = new MyClass(8);

The call to MyClass(8) causes this(8, 8) to be executed, which translates into a call to MyClass(8, 8), because this is the version of the MyClass constructor whose parameter list matches the arguments passed via this( ). Now, consider the following statement, which uses the default constructor:

MyClass mc2 = new MyClass();

In this case, this(0) is called. This causes MyClass(0) to be invoked because it is the constructor with the matching parameter list. Of course, MyClass(0) then calls MyClass(0, 0) as just described.

One reason why invoking overloaded constructors through this( ) can be useful is that it can prevent the unnecessary duplication of code.


Constructors that call this( ) will execute a bit slower than those that contain all of their initialization code inline. This is because the call and return mechanism used when the second constructor is invoked adds overhead.


There are two restrictions when using this( ).

  • First, we cannot use any instance variable of the constructor’s class in a call to this( ).


  • Second, we cannot use super( ) and this( ) in the same constructor because each must be the first statement in the constructor.


Click for NEXT article. 

 

Please feel free to correct me by commenting your suggestions and feedback.

No comments:

Post a Comment