Professional Documents
Culture Documents
Technogy Interview
Technogy Interview
htm
Batch Processing allows you to group related SQL statements into a batch and submit them with one call to the database. When you send several SQL statements to the database at once, you reduce the amount of communication overhead, thereby improving performance.
JDBC drivers are not required to support this feature. You should use theDatabaseMetaData.supportsBatchUpdates() method to determine if the target database supports batch update processing. The method returns true if your JDBC driver supports this feature. The addBatch() method of Statement, PreparedStatement, and CallableStatement is used to add individual statements to the batch. The executeBatch() is used to start the execution of all the statements grouped together. The executeBatch() returns an array of integers, and each element of the array represents the update count for the respective update statement. Just as you can add statements to a batch for processing, you can remove them with theclearBatch() method. This method removes all the statements you added with the addBatch() method. However, you cannot selectively choose which statement to remove.
1. 2. 3. 4. 5.
Create a Statement object using either createStatement() methods. Set auto-commit to false using setAutoCommit(). Add as many as SQL statements you like into batch using addBatch() method on created statement object. Execute all the SQL statements using executeBatch() method on created statement object. Finally, commit all the changes using commit() method.
Example:
The following code snippet provides an example of a batch update using Statement object:
// Create statement object Statement stmt = conn.createStatement(); // Set auto-commit to false conn.setAutoCommit(false); // Create SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(200,'Zia', 'Ali', 30)"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create one more SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(201,'Raj', 'Kumar', 35)";
// Add above SQL statement in the batch. stmt.addBatch(SQL); // Create one more SQL statement String SQL = "UPDATE Employees SET age = 35 " + "WHERE id = 100"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
For a better understanding, I would suggest to study Batching - Example Code.
2. 3. 4. 5. 6.
The following code snippet provides an example of a batch update using PrepareStatement object:
// Create SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(?, ?, ?, ?)"; // Create PrepareStatement object PreparedStatemen pstmt = conn.prepareStatement(SQL); //Set auto-commit to false conn.setAutoCommit(false); // Set the variables pstmt.setInt( 1, 400 ); pstmt.setString( 2, "Pappu" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 33 ); // Add it to the batch pstmt.addBatch(); // Set the variables pstmt.setInt( 1, 401 ); pstmt.setString( 2, "Pawan" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 31 ); // Add it to the batch pstmt.addBatch(); //add more batches .
. . . //Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
JDBC: CallableStatement
http://tutorials.jenkov.com/jdbc/callablestatement.html
A java.sql.CallableStatement is used to call stored procedures in a database. A stored procedure is like a function or method in a class, except it lives inside the database. Some database heavy operations may benefit performance-wise from being executed inside the same memory space as the database server, as a stored procedure.
Creating a CallableStatement
You create an instance of a CallableStatement by calling the prepareCall() method on a connection object. Here is an example:
CallableStatement callableStatement =
If the stored procedure returns a ResultSet, and you need a non-default ResultSet (e.g. with different holdability, concurrency etc. characteristics), you will need to specify these characteristics already when creating the CallableStatement. Here is an example:
CallableStatement callableStatement =
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_OVER_COMMIT
);
CallableStatement callableStatement =
callableStatement.setString(1, "param1");
callableStatement.setInt
(2, 123);
The executeQuery() method is used if the stored procedure returns a ResultSet. If the stored procedure just updates the database, you can call the executeUpdate() method instead, like this:
callableStatement.executeUpdate();
Batch Updates
You can group multiple calls to a stored procedure into a batch update. Here is how that is done:
CallableStatement callableStatement =
callableStatement.setString(1, "param1");
callableStatement.setInt
(2, 123);
callableStatement.addBatch();
callableStatement.setString(1, "param2");
callableStatement.setInt
(2, 456);
callableStatement.addBatch();
OUT Parameters
A stored procedure may return OUT parameters. That is, values that are returned instead of, or in addition to, a ResultSet. After executing the CallableStatement you can then access these OUTparameters from the CallableStatement object. Here is an example:
CallableStatement callableStatement =
callableStatement.setString(1, "param1");
callableStatement.setInt
(2, 123);
callableStatement.registerOutParameter(1, java.sql.Types.VARCHAR);
callableStatement.registerOutParameter(2, java.sql.Types.INTEGER);
while(result.next()) { ... }
int
out2 = callableStatement.getInt
(2);
Why Prepared Statements are important and how to use them "properly"
http://www.theserverside.com/news/1365244/Why-Prepared-Statements-are-importantand-how-to-use-them-properly
It is recommended that you first process the ResultSet before trying to access any OUTparameters. This is recommended for database compatibility reasons. Databases have a tough job. They accept SQL queries from many clients concurrently and execute the queries as efficiently as possible against the data. Processing statements can be an expensive operation but databases are now written in such a way so that this overhead is minimized. However, these optimizations need assistance from the application developers if we are to capitalize on them. This article shows you how the correct use of PreparedStatements can significantly help a database perform these optimizations.
Statement Caches
Databases are tuned to do statement caches. They usually include some kind of statement cache. This cache uses the statement itself as a key and the access plan is stored in the cache with the corresponding statement. This allows the database engine to reuse the plans for statements that have been executed previously. For example, if we sent the database a statement such as "select a,b from t where c = 2", then the computed access plan is cached. If we send the same statement later, the database can reuse the previous access plan, thus saving us CPU power.
Note however, that the entire statement is the key. For example, if we later sent the statement "select a,b from t where c = 3", it would not find an access plan. This is because the "c=3" is different from the cached plan "c=2". So, for example: For(int I = 0; I < 1000; ++I) { PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + I); ResultSet rs = Ps.executeQuery(); Rs.close(); Ps.close(); } Here the cache won't be used. Each iteration of the loop sends a different SQL statement to the database. A new access plan is computed for each iteration and we're basically throwing CPU cycles away using this approach. However, look at the next snippet: PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?"); For(int I = 0; I < 1000; ++I) { ps.setInt(1, I); ResultSet rs = ps.executeQuery(); Rs.close(); } ps.close(); Here it will be much more efficient. The statement sent to the database is parameterized using the '?' marker in the sql. This means every iteration is sending the same statement to the database with different parameters for the "c=?" part. This allows the database to reuse the access plans for the statement and makes the program execute more efficiently inside the database. This basically let's your application run faster or makes more CPU available to users of the database.
Wrapping is very useful as it also helps J2EE application server implementers to add support for prepared statements in a sensible way. When an application calls Connection.prepareStatement, it is returned a PreparedStatement object by the driver. The application then keeps the handle while it has the connection and closes it before it closes the connection when the request finishes. However, after the connection is returned to the pool and later reused by the same, or another application, , then ideally, we want the same PreparedStatement to be returned to the application.
Summary
In conclusion, we should use parameterized queries with prepared statements. This reduces the load on the database by allowing it to reuse access plans that were already prepared. This cache is databasewide so if you can arrange for all your applications to use similar parameterized SQL, you will improve the efficiency of this caching scheme as an application can take advantage of prepared statements used by another application. This is an advantage of an application server because logic that accesses the database should be centralized in a data access layer (either an OR-mapper, entity beans or straight JDBC). Finally, the correct use of prepared statements also lets you take advantage of the prepared statement cache in the application server. This improves the performance of your application as the application can reduce the number of calls to the JDBC driver by reusing a previous prepared statement call. This makes it competitive with fat clients efficiency-wise and removes the disadvantage of not being able to keep a dedicated connection. If you use parameterized prepared statements, you improve the efficiency of the database and your application server hosted code. Both of these improvements will allow your application to improve its performance.
The method hashCode() is defined in the Object class and is inherited by all Java objects. The following code snippet shows how the hash codes of two objects relate to the corresponding equals() method:
1. 2. 3. 4. // Compare objects and then compare their hash codes if (object1.equals(object2) System.out.println("hash code 1 = " + object1.hashCode() + ", hashcode 2 = " + object2.hashCode());
// Compare hash codes and then compare objects if (object1.hashCode() == object2.hashCode()) { if (object1.equals(object2)) System.out.println"object1 equals object2"); else System.out.println"object1 does not equal object2"); }
In lines 3-4, the value of the two hash codes will always be the same. However, the program may go through line 10 or line 12 in the code. Just because an object's reference equals another object's reference (remember that the equals() method compares object references by default), it does not necessarily mean that the hash codes also match. The hashCode() method may be overridden by subclasses. Overriding the hash code will allow you to associate your own hash key with the object.
Java Serialization
http://www.tutorialspoint.com/java/java_serialization.htm
Java provides a mechanism, called object serialization where an object can be represented as a sequence of bytes that includes the object's data as well as information about the object's type and the types of data stored in the object. After a serialized object has been written into a file, it can be read from the file and deserialized that is, the type information and bytes that represent the object and its data can be used to recreate the object in memory. Most impressive is that the entire process is JVM independent, meaning an object can be serialized on one platform and deserialized on an entirely different platform. Classes ObjectInputStream and ObjectOutputStream are high-level streams that contain the methods for serializing and deserializing an object. The ObjectOutputStream class contains many write methods for writing various data types, but one method in particular stands out:
public String name; public String address; public int transient SSN; public int number; public void mailCheck() { System.out.println("Mailing a check to " + name + " " + address); } }
Notice that for a class to be serialized successfully, two conditions must be met:
The class must implement the java.io.Serializable interface. All of the fields in the class must be serializable. If a field is not serializable, it must be marked transient.
If you are curious to know if a Java Satandard Class is serializable or not, check the documentation for the class. The test is simple: If the class implements java.io.Serializable, then it is serializable; otherwise, it's not.
Serializing an Object:
The ObjectOutputStream class is used to serialize an Object. The following SerializeDemo program instantiates an Employee object and serializes it to a file. When the program is done executing, a file named employee.ser is created. The program does not generate any output, but study the code and try to determine what the program is doing. Note: When serializing an object to a file, the standard convention in Java is to give the file a.ser extension.
import java.io.*; public class SerializeDemo { public static void main(String [] args) { Employee e = new Employee(); e.name = "Reyan Ali"; e.address = "Phokka Kuan, Ambehta Peer"; e.SSN = 11122333; e.number = 101; try { FileOutputStream fileOut = new FileOutputStream("employee.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(e); out.close(); fileOut.close(); }catch(IOException i) { i.printStackTrace(); } } }
Deserializing an Object:
The following DeserializeDemo program deserializes the Employee object created in the SerializeDemo program. Study the program and try to determine its output:
import java.io.*; public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { FileInputStream fileIn = new FileInputStream("employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); }catch(IOException i) { i.printStackTrace(); return; }catch(ClassNotFoundException c) { System.out.println(.Employee class not found.); c.printStackTrace(); return; } System.out.println("Deserialized Employee..."); System.out.println("Name: " + e.name); System.out.println("Address: " + e.address); System.out.println("SSN: " + e.SSN); System.out.println("Number: " + e.number); } }
This would produce following result:
Deserialized Employee... Name: Reyan Ali Address:Phokka Kuan, Ambehta Peer SSN: 0 Number:101
Here are following important points to be noted:
The try/catch block tries to catch a ClassNotFoundException, which is declared by the readObject() method. For a JVM to be able to deserialize an object, it must be able to find the bytecode for the class. If the JVM can't find a class during the deserialization of an object, it throws a ClassNotFoundException. Notice that the return value of readObject() is cast to an Employee reference. The value of the SSN field was 11122333 when the object was serialized, but because the field is transient, this value was not sent to the output stream. The SSN field of the deserialized Employee object is 0.
Serialization in Java
http://www.jusfortechies.com/java/core-java/serialization.php
Serialization is the process of converting an object's state (including its references) to a sequence of bytes, as well as the process of rebuilding those bytes into a live object at some future time. Simple......Coverting an object to bytes and bytes back to object. So when is serialization used? Serialization is used when you want to persist the object. It is also used by RMI to pass objects between JVMs, either as arguments in a method invocation from a client to a server or as return values from a method invocation. In general, serialization is used when we want the object to exist beyond the lifetime of the JVM. Lets see couple of different scenarios (examples) where we use serialization.
1. Banking example: When the account holder tries to withdraw money from
the server through ATM, the account holder information along with the withdrawl details will be serialized (marshalled/flattened to bytes) and sent to server where the details are deserialized (unmarshalled/rebuilt the bytes)and used to perform operations. This will reduce the network calls as we are serializing the whole object and sending to server and further request for information from client is not needed by the server.
2. Stock example: Lets say an user wants the stock updates immediately
when he request for it. To achieve this, everytime we have an update, we can serialize it and save it in a file. When user requests the information, deserialize it from file and provide the information. This way we dont need to make the user wait for the information until we hit the database, perform computations and get the result. Here are some uses of serialization
To persist data for future use. To send data to a remote computer using such client/server Java technologies To "flatten" an object into array of bytes in memory. To exchange data between applets and servlets. To store user session in Web applications. To activate/passivate enterprise java beans. To send objects between the servers in a cluster.
So far we saw what and when serialization is used. Lets see now how serialization is performed in java. Java provides Serialization API, a standard mechanism to handle object serialization. To persist an object in java, the first step is to flatten the object. For that the respective class should implement "java.io.Serializable" interface. Thats it. We dont need to implement any methods as this interface do not have any methods. This is a marker
interface/tag interface. Marking a class as Serializable indicates the underlying API that this object can be flattened.
Now you marked the object for flattening. Next step is to actually persist the object. To persist an object you need to use node stream to write to file systems or transfer a flattened object across a network wire and have it be rebuilt on the other side. You can use java.io.ObjectOutputStream class, a filter stream which is a wrapper around a lower-level byte stream. So to write an object you use "writeObject(<<instance>>)" method of "java.io.ObjectOutputStream" class and to read an object you use "readObject()" method of "java.io.ObjectOutputStream" class. "readObject()" can read only serialized object, that means if the class does not implement "java.io.Serializable" interface, "readObject()" cannot read that object.
//Class to persist the time in a flat file time.ser public class PersistSerialClass {
PersistSerialClass time = new PersistSerialClass(); FileOutputStream fos = null; ObjectOutputStream out = null;
try{ fos = new FileOutputStream(filename); out = new ObjectOutputStream(fos); out.writeObject(time); out.close(); }catch(IOException ex){ ex.printStackTrace(); } } }
//Class to read the time from a flat file time.ser public class ReadSerialClass {
in = new ObjectInputStream(fis); time = (PersistSerialClass)in.readObject(); in.close(); }catch(IOException ex){ ex.printStackTrace(); }catch(ClassNotFoundException cnfe){ cnfe.printStackTrace(); }
} } When you serialize an object, only the object's state will be saved, not the object's class file or methods. When you serialize the above example class, the serialized class will look like below. Surprising.. isn't it? Yes, when you serialized a 2 byte object, you see 51 bytes serialized file. How did it convert to 51 bytes file? To know this, Let's see step by step on how the object is serialized and de-serialized. So when an object is serailized
First it writes out the serialization stream magic data - What is serialization
stream magic data? This is nothing but the STREAM_MAGIC and STREAM_VERSION data (static data) so that JVM can deserialize it when it has to. The STRAM_MAGIC will be "AC ED" and the STREAM_VERSION will be the version of the JVM.
Then it writes out the metadata (description) of the class associated with an
instance. So in the below example after writing out the magic data, it writes out the description of "SerialClass" class. What does this description include? It includes the length of the class, the name of the class, serialVersionUID (or serial version), various flags and the number of fields in this class.
Then it recursively writes out the metadata of the superclass until it finds
java.lang.object. Again in the below example, it writes out the description of "SerialParent" and "SerialParentParent" classes.
Once it finishes writing the metadata information, it then starts with the actual
data associated with the instance. But this time, it starts from the top most superclass. So it starts from "SerialParentParent", then writes out "SerialParent".
Finally it writes the data of objects associated with the instance starting from
metadata to actual content. So here it starts writing the metadata for the class Contain and then the contents of it as usual recursively.
public class SerialClass extends SerialParent implements Serializable { int version = 12; Contain con = new Contain();
public static void main(String args[]) throws IOException { FileOutputStream fos = new FileOutputStream("temp.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); SerialClass st = new SerialClass(); oos.writeObject(st); oos.flush(); oos.close();
} }
How to customize the default protocol? MMmmmm.. Now its getting more interesting. Lets say, you need to perform some specific operations in the constructor when you are instantiating the class but you cant perform those operations when you deserialize the object because constructor wont be called when an object is de-serialized. Here we are restoring an object but not reconstructing an object. Then how will you call or perform those operations when you desrialize the object? Well, you have a way here and its simple too. You can enhance the normal process by providing two methods inside your serializable class. Those methods are: private void writeObject(ObjectOutputStream out) throws IOException; private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException; Notice that both methods are declared private and ofcourse they must be declared private, proving that neither method is inherited and overridden or overloaded. The trick here is that the virtual machine will automatically check to see if either method is declared during the corresponding method call. The virtual machine can call private methods of your class whenever it wants but no other objects can. Thus, the integrity of the class is maintained and the serialization protocol can continue to work as normal.
// our "pseudo-constructor" in.defaultReadObject(); // now perfrom same operation you need to do in constructor calculateCurrentTime(); } }
Ooops. I mentioned earlier that for a class to be serializable either the class should implement "Serializable" interface or one of its super class should implement "Serializable" interface. Now what if you dont want to serialize one of the sub class of a serializable class? You have a way here tooo. To stop the automatic serialization, you can once again use the private methods to just throw the NotSerializableException in your class.
Well... One more way to serialize the object - the Externalizable Interface Again there is one more way to serialize the object - create your own protocol with the Externalizable interface. Instead of implementing the Serializable interface, you can implement Externalizable, which contains two methods: public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; The Externalization is discussed as separate topic. Check it out here or check the menu. How not to serialize some fields in a serializble object? Sometimes you dont want to serialize/store all the fields in the object. Say some fields you want to hide to preserve the privacy or some fields you may want to read only from master data, then you dont seriaalize them. To do this, you just need to declare a field as transient field. transient private int checkPoint; Also the static fields are not serialized. Actually there is no point in serializing static fields as static fields do not represent object state but represent class state and it can be modified by any other object. Lets assume that you have serialized a static field and its value and before deserialization of the object, the static field value is changed by some other object. Now the static field value that is serialized/stored is no more valid. Hence it make no point in serializing the static field.
Apart from declaring the field as transient, there is another tricky way of controlling what fields can be serialized and what fields cannot be. This is by overriding the writeObject() method while serialization and inside this method you are responsible for writing out the appropriate fields. When you do this, you may have to override readObject() method as well. This sound similar to using Externalizable where you will write writeExternal() and readExternal() methods but anyways lets not take this route as this is not a neat route. Note that serialization does not care about access modifiers. It serializes all private, public and protected fields. Nonserializable objects Earlier we discussed about not serializing certain fields in a serializable object and why it may be needed sometimes. But now lets see why certain objects should not be serialized? As you know, the Object class does not implement Serializable interface and hence any object by default is not serializable. To make an object serializable, the respective class should explicitly implement Serializable interface. However certain system classes defined by java like "Thread", "OutputStream", "Socket" are not serializable. Why so? Lets take a step back - now what is the use of serializing the Thread running in System1 JVM using System1 memory and then deserializing it in System2 and trying to run in System2 JVM. Makes no sense right! Hence these classes are not serializable.
Ok. So far so good. Now what if you want to serialize an object containing an instance of Thread? Simple. Declare the Thread instance as transient.
public class SerialClass implements Serializable, Runnable { transient private Thread myThread;
Versioning issues One very important item to look at is the versioning issue. Sometimes you wil get "java.io.InvalidClassException" but when you check the class (it will be Serializable class), you will find nothing wrong with it. Then what is causing this exception to be thrown? Ok. Here it is. You create a Serializable class, instantiate it, and write it out to an object stream. That flattened object sits in the file system for some time. Meanwhile, you update the class file by adding a new field. Then try to read the flattened object. InvalidClassException is thrown because all persistent-capable classes are automatically given a unique identifier. If the identifier of the class does not equal the identifier of the flattened object, the exception will be thrown and when you update the class with a new field, a new identifier will be generated. To fix this issue, manually add the identifier to the class. The identifier that is part of all classes is maintained in a field called serialVersionUID. If you wish to control versioning, you simply have to provide the serialVersionUID field manually and ensure it is always the same, no matter what changes you make to the classfile. More about it is discussed in separate topic. Check it here. Performance Issues/Improvement with Serialization The default way of implementing the serialization (by implementing the Serializable interface) has performance glitches. Say you have to write an object 10000 times in a flat file through serialization, this will take much more (alomost double) the time than it takes to write the same object 10000 times to console. To overcome this issue, its always better to write your custom protocol instead of going for default option.
Also always note to close the streams (object output and input streams). The object references are cached in the output stream and if the stream is not closed, the system may not garbage collect the objects written to a stream and this will result in poor performance.
Using Serialization always have performance issues? Nope... Let me give you a situation where it is used for performance improvement. Lets assume you have an application that should display a map and pointing to different areas in the map should highlight those areas in different color. Since all these are images, when you point to each location, loading an image each time will slow the application heavily. To resolve this issue, serialization can be used. So here since the images wont change, you can serialize the image object and the respective points on the map (x and y co-ordinates) and deserialize it as and when necessary. This improves the performance greatly. What happens to inner classes? We forgot all about it. Yes, you can serialize inner classes by implementing the Serializable interface but it has some problems. Inner classes (declared in a non-static context) will always contain implicit references to their enclosing classes and these references are always nontransient. So, while object serialization process of inner classes, the enclosing classes will also be serialized. Now the problem is that the synthetic fields generated by Java compilers to implement inner classes are pretty much implementation dependent and hence we may face compatibility issues while deserialization on a different platform having a .class file generated by a different Java compiler. The default serialVerionUID may also be different in such cases. Not only this, the names assigned to the local and anonymous inner classes are also implementation dependent. Thus, we see that object serialization of inner classes may pose some unavoidable compatibility issues and hence the serialization of inner classes is strongly discouraged.
In real life, objects are often comparable. For example, Dad's car is more expensive than Mom's, this dictionary is thicker than those books, Granny is older than Auntie Mollie (well, yeah, living objects, too, are comparable), and so forth. In writing object-oriented programs, there are often needs to compare instances of the same class. And once instances are comparable, they can be sorted. As an example, given two Employees, you may want to know which one has stayed in the organization longer. Or, in a search method for Person instances with a first name of Larry, you may want to display search results sorted by age. This article teaches you how to design your class to make its instances comparable by using the java.lang.Comparable and java.util.Comparator interfaces and presents three examples that illustrate both interfaces. Most Java programmers know how to sort the elements of a String array by using the sort method of java.util.Arrays. For String instances in an ArrayList, you can sort them with the sort method of thejava.util.Collections class. The code in Listing 1 shows how to use Arrays.sort to order String instances.
If you run the program, the first for loop gives you the name of animals as follows:
animal animal animal animal 0 1 2 3 : : : : snake kangaroo wombat bird
And, the second for loop prints the animals sorted alphabetically.
animal animal animal animal 0 1 2 3 : : : : bird kangaroo snake wombat
With the java.util.Collections class's sort method, you can sort String instances in an ArrayList, as shown in Listing 2.
for (int i=0; i<size; i++) { System.out.println("insect " + i + " : " + (String) insects.get(i)); } Collections.sort(insects); for (int i=0; i<size; i++) { System.out.println("insect " + i + " : " + (String) insects.get(i)); }
In another part of the program, we construct four instances of the Person class and populate them with names and ages:
Person[] persons = new Person[4]; persons[0] = new Person(); persons[0].setFirstName("Elvis"); persons[0].setLastName("Goodyear"); persons[0].setAge(56); persons[1] = new Person(); persons[1].setFirstName("Stanley"); persons[1].setLastName("Clark"); persons[1].setAge(8); persons[2] = new Person(); persons[2].setFirstName("Jane"); persons[2].setLastName("Graff"); persons[2].setAge(16); persons[3] = new Person(); persons[3].setFirstName("Nancy"); persons[3].setLastName("Goodyear"); persons[3].setAge(69);
How do we sort these Person instances by age or by name? Using the java.util.Arrays class' sort method, as in:
Arrays.sort(persons);
will throw a ClassCastException. You can, of course, write your own code to sort them using an algorithm such as quick sort, bubble sort, or others, but that's impractical. The easy solution is to implement the java.lang.Comparable interface.
Using the java.lang.Comparable Interface
Implement the Comparable interface to make class instances comparable. This interface has one method, compareTo, which determines how to compare two instances of the class. The signature of this method is:
public int compareTo(Object o)
The compareTo method accepts Object, so you can pass it an instance of any type. However, chances are that you want to make sure to compare two instances of the same type. It does not make sense to compare an elephant with an ant, for example. Therefore, you can throw a java.lang.ClassCastException if the argument of this method is not the same type as your class.
The compareTo method returns zero if the object passed is equal to this instance. It returns a positive integer or a negative integer if this object is greater or smaller than the passed object, respectively. Let's have a look at the examples in Listing 4 and Listing 5. Listing 4 presents a Person class that implements the Comparable interface. Notice that a Person object is older if its age value is greater than the object compared. Listing 5 shows the Testing class that constructs four instances of the Person class and sorts them by age. Both classes in Listings 4 and 5 reside in the comparable.ex01 package.
import java.util.ArrayList; public class Testing { public static void main(String[] args) { Person[] persons = new Person[4]; persons[0] = new Person(); persons[0].setFirstName("Elvis"); persons[0].setLastName("Goodyear"); persons[0].setAge(56); persons[1] = new Person(); persons[1].setFirstName("Stanley"); persons[1].setLastName("Clark"); persons[1].setAge(8); persons[2] = new Person(); persons[2].setFirstName("Jane"); persons[2].setLastName("Graff"); persons[2].setAge(16); persons[3] = new Person(); persons[3].setFirstName("Nancy"); persons[3].setLastName("Goodyear"); persons[3].setAge(69); System.out.println("Natural Order"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } Arrays.sort(persons); System.out.println(); System.out.println("Sorted by age"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } } }
Sorted by age Clark, Stanley. Age:8 Graff, Jane. Age:16 Goodyear, Elvis. Age:56 Goodyear, Nancy. Age:69
Implementing the Comparable interface enables you to define one way to compare instances of your class. However, objects are sometimes comparable in many ways. For example, two Person objects may need to be compared by age or by last/first name. In cases like this, create a Comparator that defines how to compare two objects. To make objects comparable in two ways, then you need two comparators. To create a comparator, write a class that implements the java.util.Comparator interface--the compare method. This method has the following signature:
public int compare(Object o1, Object o2)
The compare method returns zero if o1 and o2 are equal, a negative integer if o1 is less than o2, and a positive integer if o1 is greater than o2. Just as in the compareTo method of Comparable, you define what makes an object equal or less/greater than another object. As an example, let's write two comparators for the Person class. This example consists of four classes, all of which reside in the comparable.ex02 package. The Person class is similar to the one in the previous example, and is reprinted in Listing 6 for reading convenience. Listings 7 and 8 present two comparators of Person objects (by last name and by first name), and Listing 9 offers the class that instantiates the Person class and the two comparators.
} public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int compareTo(Object anotherPerson) throws ClassCastException { if (!(anotherPerson instanceof Person)) throw new ClassCastException("A Person object expected."); int anotherPersonAge = ((Person) anotherPerson).getAge(); return this.age - anotherPersonAge; } }
String lastName2 = ((Person) anotherPerson).getLastName().toUpperCase(); String firstName2 = ((Person) anotherPerson).getFirstName().toUpperCase(); if (!(firstName1.equals(firstName2))) return firstName1.compareTo(firstName2); else return lastName1.compareTo(lastName2); } }
age); }
Arrays.sort(persons, new FirstNameComparator()); System.out.println(); System.out.println("Sorted by first name"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } Arrays.sort(persons); System.out.println(); System.out.println("Sorted by age"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } } }
If you run the comparable.ex02.Testing class, you can see the following result:
Natural Order Goodyear, Elvis. Age:56 Clark, Stanley. Age:8 Graff, Jane. Age:16 Goodyear, Nancy. Age:69 Sorted by last name Clark, Stanley. Age:8 Goodyear, Elvis. Age:56 Goodyear, Nancy. Age:69 Graff, Jane. Age:16 Sorted by first name Goodyear, Elvis. Age:56 Graff, Jane. Age:16 Goodyear, Nancy. Age:69 Clark, Stanley. Age:8 Sorted by age Clark, Stanley. Age:8 Graff, Jane. Age:16 Goodyear, Elvis. Age:56 Goodyear, Nancy. Age:69
The previous example with the Comparator interface works fine. However, the drawback is that it requires multiple classes. This means more maintenance work for the users of your comparable class. The next example shows how to integrate the comparators inside of the comparable class by making the comparators anonymous classes. This example has two classes: comparable.ex03.Person (Listing 10) and comparable.ex03.Testing (Listing 11). Note the two anonymous inner classes at the end of the Person class, and notice also in theTesting class how comparison is conducted.
public int compare(Object person, Object anotherPerson) { String lastName1 = ((Person) person).getLastName().toUpperCase(); String firstName1 = ((Person) person).getFirstName().toUpperCase(); String lastName2 = ((Person) anotherPerson).getLastName().toUpperCase(); String firstName2 = ((Person) anotherPerson).getFirstName().toUpperCase(); if (!(lastName1.equals(lastName2))) return lastName1.compareTo(lastName2); else return firstName1.compareTo(firstName2); }; }
public static Comparator FirstNameComparator = new Comparator() { public int compare(Object person, Object anotherPerson) { String lastName1 = ((Person) person).getLastName().toUpperCase(); String firstName1 = ((Person) person).getFirstName().toUpperCase(); String lastName2 = ((Person) anotherPerson).getLastName().toUpperCase(); String firstName2 = ((Person) anotherPerson).getFirstName().toUpperCase(); if (!(firstName1.equals(firstName2))) return firstName1.compareTo(firstName2); else return lastName1.compareTo(lastName2); }; } }
persons[3] = new Person(); persons[3].setFirstName("Nancy"); persons[3].setLastName("Goodyear"); persons[3].setAge(69); System.out.println("Natural Order"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } Arrays.sort(persons, Person.LastNameComparator); System.out.println(); System.out.println("Sorted by last name"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } Arrays.sort(persons, Person.FirstNameComparator); System.out.println(); System.out.println("Sorted by first name"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } Arrays.sort(persons); System.out.println(); System.out.println("Sorted by age"); for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); String firstName = person.getFirstName(); int age = person.getAge(); System.out.println(lastName + ", " + firstName + ". Age:" + age); } } }
The result of the Testing class is the same as the previous example. However, note that the comparators are inside of the Person class. To sort instances of the Person class by last name, you just need to use:
Arrays.sort(persons, Person.LastNameComparator);
Summary
This article has demonstrated how to make class instances comparable and sortable. Example 1 shows that implementing the compareTo method of the java.lang.Comparable interface is the easiest solution. To compare instances in multiple ways, create comparators by implementing the java.util.Comparator class, as demonstrated in Example 2. For better maintenance, you can embed the comparators as anonymous classes in your comparable class, as shown in Example 3. Exception Handling works
1.It separates the working/functional code from the error-handling code by way of trycatch clauses. 2.It allows a clean path for error propagation. If the called method encounters a situation it can't manage, it can throw an exception and let the calling method deal with it. 3.By enlisting the compiler to ensure that "exceptional" situations are anticipated and accounted for, it enforces powerful coding. 4.Exceptions are of two types: Compiler-enforced exceptions, or checked exceptions. Runtime exceptions, or unchecked exceptions. Compiler-enforced (checked) exceptions are instances of the Exception class or one of its subclasses '?? excluding the RuntimeException branch. The compiler expects all checked exceptions to be appropriately handled. Checked exceptions must be declared in the throws clause of the method throwing them '?? assuming, of course, they're not being caught within that same method. The calling method must take care of these exceptions by either catching or declaring them in its throws clause. Thus, making an exception checked forces the us to pay heed to the possibility of it being thrown. An example of a checked exception is java.io.IOException. As the name suggests, it throws whenever an input/output operation is abnormally terminated.
synchronized(this) { } If you synchronize a static method, then you are synchronizing across all objects of the same class, i.e. the monitor you are using for the lock is one per class, not one per object. 2. wait/notify. wait() needs to be called from within a synchronized block. It will first release the lock acquired from the synchronization and then wait for a signal. In Posix C, this part is equivalent to the pthread_cond_wait method, which waits for an OS signal to continue. When somebody calls notify() on the object, this will signal the code which has been waiting, and the code will continue from that point. If there are several sections of code that are in the wait state, you can call notifyAll() which will notify all threads that are waiting on the monitor for the current object. Remember that both wait() and notify() have to be called from blocks of code that are synchronized on the monitor for the current object.
Ques. What is the difference between a Vector and an Array. Discuss the advantages and disadvantages of both?
Ans. Vector can contain objects of different types whereas array can contain objects only of a single type. - Vector can expand at run-time, while array length is fixed. - Vector methods are synchronized while Array methods are not
"abc" are constant and implemented as instances of this class; their values cannot be changed after they are created. Strings in Java are known to be immutable. Explanation: What it means is that every time you need to make a change to a String variable, behind the scene, a "new" String is actually being created by the JVM. For an example: if you change your String variable 2 times, then you end up with 3 Strings: one current and 2 that are ready for garbage collection. The garbage collection cycle is quite unpredictable and these additional unwanted Strings will take up memory until that cycle occurs. For better performance, use StringBuffers for string-type data that will be reused or changed frequently. There is more overhead per class than using String, but you will end up with less overall classes and consequently consume less memory. Describe, in general, how java's garbage collector works? The Java runtime environment deletes objects when it determines that they are no longer being used. This process is known as garbage collection. The Java runtime environment supports a garbage collector that periodically frees the memory used by objects that are no longer needed. The Java garbage collector is a mark-sweep garbage collector that scans Java's dynamic memory areas for objects, marking those that are referenced. After all possible paths to objects are investigated, those objects that are not marked (i.e. are not referenced) are known to be garbage and are collected. (A more complete description of our garbage collection algorithm might be "A compacting, mark-sweep collector with some conservative scanning".) The garbage collector runs synchronously when the system runs out of memory, or in response to a request from a Java program. Your Java program can ask the garbage collector to run at any time by calling System.gc(). The garbage collector requires about 20 milliseconds to complete its task so, your program should only run the garbage collector when there will be no performance impact and the program anticipates an idle period long enough for the garbage collector to finish its job. Note: Asking the garbage collection to run does not guarantee that your objects will be garbage collected. The Java garbage collector runs asynchronously when the system is idle on systems that allow the Java runtime to note when a thread has begun and to interrupt another thread (such as Windows 95). As soon as another thread becomes active, the garbage collector is asked to get to a consistent state and then terminate.
is call the constructor for its uppercase. This process continues until the constructor for java.lang.Object is called, as java.lang.Object is the base class for all objects in java. 4. Before the body of the constructor is executed, all instance variable initializers and initialization blocks are executed. Then the body of the constructor is executed. Thus, the constructor for the base class completes first and constructor for the most derived class completes last.
Ques. How can you minimize the need of garbage collection and make the memory use more effective?
Ans. Use object pooling and weak object references. Pooling basically means utilizing the resources efficiently, by limiting access of the objects to only the period the client requires it. Increasing utilization through pooling usually increases system performance. Object pooling is a way to manage access to a finite set of objects among competing clients. in other words, object pooling is nothing but sharing of objects between different clients. Since object pooling allows sharing of objects ,the other clients/processes need to reinstantiate the object(which decreases the load time), instead they can use an existing object. After the usage , the objects are returned to the pool.
Ques. How would you make a copy of an entire Java object with its state?
Ans. Have this class implement Cloneable interface and call its method clone().
Ques. What comes to mind when someone mentions a shallow copy and deep copy in Java?
Ans. Object cloning. Java provides a mechanism for creating copies of objects called cloning. There are two ways to make a copy of an object called shallow copy and deep copy. Shallow copy is a bit-wise copy of an object. A new object is created that has an exact copy of the values in the original object. If any of the fields of the object are references to other objects, just the references are copied. Thus, if the object you are copying contains references to yet other objects, a shallow copy refers to the same subobjects. Deep copy is a complete duplicate copy of an object. If an object has references to other objects, complete new copies of those objects are also made. A deep copy generates a copy not only of the primitive values of the original object, but copies of all subobjects as well, all the way to the bottom. If you need a true, complete copy of the original object, then you will need to implement a full deep copy for the object. Java supports shallow and deep copy with the Cloneable interface to create copies of objects. To make a clone of a Java object, you declare that an object implements Cloneable, and then provide an override of the clone method of the standard Java Object base class. Implementing Cloneable tells the java compiler that your object is Cloneable. The cloning is actually done by the clone method.
Ques. What comes to mind when you hear about a young generation in Java?
Ans. Garbage collection.
In the J2SE platform version 1.4.1 two new garbage collectors were introduced to make a total of four garbage collectors from which to choose. Beginning with the J2SE platform, version 1.2, the virtual machine incorporated a number of different garbage collection algorithms that are combined using generational collection. While naive garbage collection examines every live object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work. The default collector in HotSpot has two generations: the young generation and the tenured generation. Most allocations are done in the young generation. The young generation is optimized for objects that have a short lifetime relative to the interval between collections. Objects that survive several collections in the young generation are moved to the tenured generation. The young generation is typically smaller and is collected more often. The tenured generation is typically larger and collected less often. The young generation collector is a copying collector. The young generation is divided into 3 spaces: eden-space, to-space, and from-space. Allocations are done from eden-space and from-space. When those are full a young generation is collection is done. The expectation is that most of the objects are garbage and any surviving objects can be copied to to-space. If there are more surviving objects than can fit into to-space, the remaining objects are copied into the tenured generation. There is an option to collect the young generation in parallel. The tenured generation is collected with a mark-sweep-compact collection. There is an option to collect the tenured generation concurrently.
Usage patterns API: In The Java Programming Language Ken Arnold, James Gosling, and David Holmes describe the Vector as an analog to the ArrayList. So, from an API perspective, the two classes are very similar. However, there are still some major differences between the two classes. Synchronization: Vectors are synchronized. Any method that touches the Vector's contents is thread safe. ArrayList, on the other hand, is unsynchronized, making them, therefore, not thread safe. With that difference in mind, using synchronization will incur a performance hit. So if you don't need a thread-safe collection, use the ArrayList. Why pay the price of synchronization unnecessarily? Data growth: Internally, both the ArrayList and Vector hold onto their contents using an Array. You need to keep this fact in mind while using either in your programs. When you insert an element into an ArrayList or a Vector, the object will need to expand its internal array if it runs out of room. A Vector defaults to doubling the size of its array, while the ArrayList increases its array size by 50 percent. Depending on how you use these classes, you could end up taking a large performance hit while adding new elements. It's always best to set the object's initial capacity to the largest capacity that your program will need. By carefully setting the capacity, you can avoid paying the penalty needed to resize the internal array later. If you don't know how much data you'll have, but you do know the rate at which it grows, Vector does possess a slight advantage since you can set the increment value. Usage patterns: Both the ArrayList and Vector are good for retrieving elements from a specific position in the container or for adding and removing elements from the end of the container. All of these operations can be performed in constant time -- O(1). However, adding and removing elements from any other position proves more expensive -- linear to be exact: O(n-i), where n is the number of elements and i is the index of the element added or removed. These operations are more expensive because you have to shift all elements at index i and higher over by one element. So what does this all mean? It means that if you want to index elements or add and remove elements at the end of the array, use either a Vector or an ArrayList. If you want to do anything else to the contents, go find yourself another container class. For example, the LinkedList can add or remove an element at any position in constant time -- O(1). However, indexing an element is a bit slower -- O(i) where i is the index of the element. Traversing an ArrayList is also easier since you can simply use an index instead of having to create an iterator. The LinkedList also creates an internal object for each element inserted. So you have to be aware of the extra garbage being created.
If a class is located in a package, what do you need to change in the OS environment to be able to use it?
Ans. You need to add a directory or a jar file that contains the package directories to the CLASSPATH environment variable. Lets say a class Employee belongs to a package com.xyz.hr; and is located in the file c:/dev/com.xyz.hr.Employee.java. In this case, you'd need to add c:/dev to the variable CLASSPATH. If this class contains the method main(), you could test it from a command prompt window as follows: c:\>java com.xyz.hr.Employee
java.lang basic language functionality and fundamental types java.util collection data structure classes java.io file operations java.math multiprecision arithmetics java.nio the New I/O framework for Java java.net networking operations, sockets, DNS lookups, ... java.security key generation, encryption and decryption java.sql Java Database Connectivity (JDBC) to access databases java.awt basic hierarchy of packages for native GUI components javax.swing hierarchy of packages for platform-independent rich GUI components java.applet classes for creating an applet
public class Logon implements Serializable { private Date date = new Date(); private String username; private transient String password; public Logon(String name, String pwd) { username = name; password = pwd; } public String toString() { String pwd = (password == null) ? "(n/a)" : password; return "logon info: \n username: " + username + "\n date: " + date + "\n password: " + pwd; } public static void main(String[] args) throws Exception { Logon a = new Logon("Hulk", "myLittlePony"); System.out.println("logon a = " + a); ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream( "Logon.out")); o.writeObject(a); o.close();
Thread.sleep(1000); // Delay for 1 second // Now get them back: ObjectInputStream in = new ObjectInputStream(new FileInputStream( "Logon.out")); System.out.println("Recovering object at " + new Date()); a = (Logon) in.readObject(); System.out.println("logon a = " + a); } }
Ques. Why would you use a synchronized block vs. synchronized method?
Ans. Synchronized blocks place locks for shorter periods than synchronized methods. if you go for synchronized block it will lock a specific object. if you go for synchronized method it will lock all the objects. in other way Both the synchronized method and block are used to acquires the lock for an object. But the context may vary. Suppose if we want to invoke a critical method which is in a class whose access is not available then synchronized block is used. Otherwise synchronized method can be used. Synchronized methods are used when we are sure all instance will work on the same set of data through the same function Synchronized block is used when we use code which we cannot modify ourselves like third party jars etc For a detail clarification see the below code for example: //Synchronized block class A { public void method1() {...} } class B { public static void main(String s[]) { A objecta=new A(); A objectb=new A(); synchronized(objecta){objecta.method1();} objectb.method1(); //not synchronized } } //synchronized method class A { public synchronized void method1() { ...} } class B { public static void main(String s[]) { A objecta=new A(); A objectb =new A(); objecta.method1(); objectb.method2(); } }