Author Archives: Nirmal Jatania

How to implement HttpSessionListener

The HttpSessionListenerinterface is used to monitor when sessions are created and destroyed on the application server. Its best practical use would be to track session use statistics for a server. To receive notification events, the implementation class must be configured in the deployment descriptor for the web application. This entry points the server to a class that will be called when a session is created or destroyed. The entry required is simple. All you need is a listener and listener-class element in the following format. The listener-class element must be a fully qualified class name.


com.test.mypackage.MySessionListener

The HttpSessionListenerinterface has two methods:

  • public void sessionCreated(HttpSessionEvent se) : Notification that a session was created.
  • public void sessionDestroyed(HttpSessionEvent se) : Notification that a session is about to be invalidated.

The following example demonstrates how these methods may be used:

package com.test.mypackage;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;

public class MyHttpSessionListener implements HttpSessionListener
{
    public void sessionCreated(HttpSessionEvent se)
    {
        HttpSession session = se.getSession();
        System.out.print(getTime() + " (session) Created:");
        System.out.println("ID=" + session.getId() + " MaxInactiveInterval="
 + session.getMaxInactiveInterval());
    }
    public void sessionDestroyed(HttpSessionEvent se)
    {
        HttpSession session = se.getSession();
        // session has been invalidated and all session data
//(except Id)is no longer available
        System.out.println(getTime() + " (session) Destroyed:ID="
+ session.getId());
    }
    private String getTime()
    {
        return new Date(System.currentTimeMillis()).toString();
    }
}

There is no distinct difference between session timeout and session invalidation from the perspective of the session object. Other HttpSession API methods may be used to determine timeout and invalidation values. The HttpSessionListener and HttpSessionAttributeListener is defined in <listener> in your web.xml file. They are “application-wide”, they manage all the session in your web-application! And they are instanticated by your web-container. Even if your session attribute implements HttpSessionListener or HttpSessionAttributeListener, but you do not define that in web.xml, there is NO HttpSessionListener or HttpSessionAttributeListener instance in your web-application at all! (If you just create an HttpSessionListener instance by your own, it won’t work because your web-application does not know at all, it only checks the web.xml).

Some Useful Hibernate Interview questions with answers

Q1. How will you configure Hibernate?

Answer:

The configuration files hibernate.cfg.xml (or hibernate.properties) and mapping files *.hbm.xml are used by the Configuration class to create (i.e. configure and bootstrap hibernate) the SessionFactory, which in turn creates the Session instances. Session instances are the primary interface for the persistence service.

hibernate.cfg.xml (alternatively can use hibernate.properties): These two files are used to configure the hibernate sevice (connection driver class, connection URL, connection username, connection password, dialect etc). If both files are present in the classpath then hibernate.cfg.xml file overrides the settings found in the hibernate.properties file.

Mapping files (*.hbm.xml): These files are used to map persistent objects to a relational database. It is the best practice to store each object in an individual mapping file (i.e mapping file per class) because storing large number of persistent classes into one mapping file can be difficult to manage and maintain. The naming convention is to use the same name as the persistent (POJO) class name. For example Account.class will have a mapping file named Account.hbm.xml. Alternatively hibernate annotations can be used as part of your persistent class code instead of the *.hbm.xml files.

Q2. What is a SessionFactory? Is it a thread-safe object?

Answer:

SessionFactory is Hibernate’s concept of a single datastore and is threadsafe so that many threads can access it concurrently and request for sessions and immutable cache of compiled mappings for a single database. A SessionFactory is usually only built once at startup. SessionFactory should be wrapped in some kind of singleton so that it can be easily accessed in an application code.

SessionFactory sessionFactory = new Configuration().configure().buildSessionfactory();

Q3. What is a Session? Can you share a session object between different theads?

Answer:

Session is a light weight and a non-threadsafe object (No, you cannot share it between threads) that represents a single unit-of-work with the database. Sessions are opened by a SessionFactory and then are closed when all work is complete. Session is the primary interface for the persistence service. A session obtains a database connection lazily (i.e. only when required). To avoid creating too many sessions ThreadLocal class can be used as shown below to get the current session no matter how many times you make call to the currentSession() method.

public class HibernateUtil {

public static final ThreadLocal local = new ThreadLocal();

public static Session currentSession() throws HibernateException {
Session session = (Session) local.get();
//open a new session if this thread has no session
if (session == null) {
    session = sessionFactory.openSession();
    local.set(session);
   }
   return session;
  }
}

It is also vital that you close your session after your unit of work completes. Note: Keep your Hibernate Session API handy.

Q4. What are the benefits of detached objects?

Answer:

Detached objects can be passed across layers all the way up to the presentation layer without having to use any DTOs (Data Transfer Objects). You can later on re-attach the detached objects to another session.

Q5. What are the pros and cons of detached objects?

Answer:

pros:

When long transactions are required due to user think-time, it is the best practice to break the long transaction up into two or more transactions. You can use detached objects from the first transaction to carry data all the way up to the presentation layer. These detached objects get modified outside a transaction and later on re-attached to a new transaction via another session.

Cons

In general, working with detached objects is quite cumbersome, and better to not clutter up the session with them if possible. It is better to discard them and re-fetch them on subsequent requests. This approach is not only more portable but also more efficient because – the objects hang around in Hibernate’s cache anyway.

Also from pure rich domain driven design perspective it is recommended to use DTOs (DataTransferObjects) and DOs (DomainObjects) to maintain the separation between Service and UI tiers.

Q6. How does Hibernate distinguish between transient (i.e. newly instantiated) and detached objects?

Answer

” Hibernate uses the version property, if there is one.
” If not uses the identifier value. No identifier value means a new object. This does work only for Hibernate managed surrogate keys. Does not work for natural keys and assigned (i.e. not managed by Hibernate) surrogate keys.
” Write your own strategy with Interceptor.isUnsaved().

Q7. What is the difference between the session.get() method and the session.load() method?

Answer:

Both the session.get(..) and session.load() methods create a persistent object by loading the required object from the database. But if there was not such object in the database then the method session.load(..) throws an exception whereas session.get(&) returns null.

Q8. What is the difference between the session.update() method and the session.lock() method?

Answer:

Both of these methods and saveOrUpdate() method are intended for reattaching a detached object. The session.lock() method simply reattaches the object to the session without checking or updating the database on the assumption that the database in sync with the detached object. It is the best practice to use either session.update(..) or session.saveOrUpdate(). Use session.lock() only if you are absolutely sure that the detached object is in sync with your detached object or if it does not matter because you will be overwriting all the columns that would have changed later on within the same transaction.

Note: When you reattach detached objects you need to make sure that the dependent objects are reatched as well.

Q9. How would you reatach detached objects to a session when the same object has already been loaded into the session?

Answer:

You can use the session.merge() method call.

Q10. What are the general considerations or best practices for defining your Hibernate persistent classes?

Answer:


1.You must have a default no-argument constructor for your persistent classes and there should be getXXX() (i.e accessor/getter) and setXXX( i.e. mutator/setter) methods for all your persistable instance variables.

2.You should implement the equals() and hashCode() methods based on your business key and it is important not to use the id field in your equals() and hashCode() definition if the id field is a surrogate key (i.e. Hibernate managed identifier). This is because the Hibernate only generates and sets the field when saving the object.

3. It is recommended to implement the Serializable interface. This is potentially useful if you want to migrate around a multi-processor cluster.

4.The persistent class should not be final because if it is final then lazy loading cannot be used by creating proxy objects.

5.Use XDoclet tags for generating your *.hbm.xml files or Annotations (JDK 1.5 onwards), which are less verbose than *.hbm.xml files.

Tapestry – Override the default CSS of BeanEditForm Component

Tapestry includes a powerful component capable of generating a complete create/edit user interface for a typical JavaBean, BeanEditForm.

When a page is rendered (which has t:beaneditform tag), the BeanEditForm component will read its object parameter as the JavaBean to edit (with the current properties of the JavaBean becoming the defaults for the various fields). Likewise, when the form is submitted by the user, the object parameter is read and its properties populated from the request.

Indeed another great component of Tapestry, which shows the power of it…

When I was practicing this feature today, with some basic tutorial application, I have seen following form for my bean called “CreateAddress”.

Image_1

Well, I didn’t likde the provided in-built css (i.e. default.css), and tried to add some css class directly into the .tml file… But it was not the solution for this issue.

Following are the steps to apply your own css to the BeanEditForm component page :

Step  : 1

Create your own directory inside Web Pages, To create it in NetBeans, right click on the Web Pages folder inside the project structure. Select New|File/Folder…, then Other in Categories and Folder in File Types. Click on Next, give the new folder a name “style”, and then click on Finish.

Step : 2

Create your own .css file inside newly created directory “style” with name my_style.css.

Step : 3

Add following lines into my_style.css file :



DIV.t-beaneditor

{

display: block;

background: white;

border: 2px solid green;

padding: 2px;

font-family: "Trebuchet MS", Arial, sans-serif;

}

DIV.t-beaneditor LABEL

{

width: 150px;

display: block;

float: left;

text-align: left;

clear: left;

padding-right: 3px;

}

input.t-beaneditor-submit

{

position: relative;

left: 150px;

}

Step : 4

Now Inside your class (controller) you need to inject an Asset, use following code to do so :

@Inject
    @Path("context:style/my_style.css")
    private Asset styles;

    public Asset getStyles() {
        return styles;
    }

Step : 5

Finally provide in the page template a link to the stylesheet, (where you have t:beaneditform tag)


<head>

<link rel="stylesheet" href="${style}" type="text/css"/>

</head>

After applying all the above changes, when I tested the same page, I got the overridden css styles (my_style.css) on the browser :

Provide your suggestions on this, so that I can modify the private data if required…

How Class.forName(“…”) works

When we create an instance of a class using new operator, it does two things

1. Load the class in to memory, if it is not loaded –
which means creating in-memory representation of the class from the .class file so that an instance can be created out of it. This includes initializing static variables (resolving of that class)
2. create an instance of that class and store the reference to the variable.

Class.forName does only the first thing.
It loads the class in to memory and return that reference as an instance of Class. If we want to create an instance then, we can call newInstance method of that class. which will invoke the default constructor (no argument constructor).
Note that if the default constructor is not accessible, then newInstance method will throw an IllegalAccessException. and if the class is an abstract class or interface or it does not have a default constructor, then it will throw an InstantiationException. If any exception araises during resolving of that class, it will throw an ExceptionInInitializerError.

If the default constructor is not defined, then we have to invoke the defiend constructor using reflection API.

But the main advantage with Class.forName is, it can accept the class name as a String argument. So we can pass the class name dynamically. But if we create an instance of a class using new operator, the class name can’t be changed dynamically.

Class.forName() inturn will call loadClass method of the caller ClassLoader (ClassLoder of the class from where Class.forName is invoked).

By default, the Class.forName() resolve that class. which means, initialize all static variables inside that class.
same can be changed using the overloaded method of Class.forName(String name,boolean initialize,ClassLoader loader)

The main reason for loading jdbc driver using Class.forName() is, the driver can change dynamically.
in the static block all Drivers will create an instance of itself and register that class with DriverManager using DriverManager.registerDriver() method. Since the Class.forName(String className) by default resolve the class, it will initialize the static initializer.
So when we call Class.forName(“com.sun.jdbc.odbc.JdbcOdbcDriver”),
the Driver class will be loaded, instantiated and registers with DriverManager

So if you are using new Operator you have to do the following things.

Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver();
DriverManager.registerDriver(drv);

Hibernate Caching Tutorial

(1) Why Need ?

While working with Hibernate web applications we will face so many problems in its performance due to database traffic. That to when the database traffic is very heavy . Actually hibernate is well used just because of its high performance only. So some techniques are necessary to maintain its performance. Caching is the best technique to solve this problem. In this article we will discuss about, how we can improve the performance of Hibernate web applications using caching.

The performance of Hibernate web applications is improved using caching by optimizing the database applications. The cache actually stores the data already loaded from the database, so that the traffic between our application and the database will be reduced when the application want to access that data again. Maximum the application will works with the data in the cache only. Whenever some another data is needed, the database will be accessed. Because the time needed to access the database is more when compared with the time needed to access the cache. So obviously the access time and traffic will be reduced between the application and the database. Here the cache stores only the data related to current running application. In order to do that, the cache must be cleared time to time whenever the applications are changing.

Hibernate uses two different caches for objects: first-level cache and second-level cache..

1.1) First-level cache

First-level cache always Associates with the Session object. Hibernate uses this cache by default. Here, it processes one transaction after another one, means wont process one transaction many times. Mainly it reduces the number of SQL queries it needs to generate within a given transaction. That is instead of updating after every modification done in the transaction, it updates the transaction only at the end of the transaction.

1.2) Second-level cache

Second-level cache always associates with the Session Factory object. While running the transactions, in between it loads the objects at the Session Factory level, so that those objects will available to the entire application, don’t bounds to single user. Since the objects are already loaded in the cache, whenever an object is returned by the query, at that time no need to go for a database transaction. In this way the second level cache works. Here we can use query level cache also. Later we will discuss about it.

(2) Way to Implement It

Hibernate supports four open-source cache implementations named EHCache (Easy Hibernate Cache), OSCache (Open Symphony Cache), Swarm Cache, and JBoss Tree Cache. Each cache has different performance, memory use, and configuration possibilities.

2.1) 2.1 EHCache (Easy Hibernate Cache) (org.hibernate.cache.EhCacheProvider)

  • It is fast.
  • lightweight.
  • Easy-to-use.
  • Supports read-only and read/write caching.
  • Supports memory-based and disk-based caching.

Does not support clustering.

2.2)OSCache (Open Symphony Cache) (org.hibernate.cache.OSCacheProvider)

  • It is a powerful .
  • flexible package
  • supports read-only and read/write caching.
  • Supports memory- based and disk-based caching.
  • Provides basic support for clustering via either JavaGroups or JMS.

2.3)SwarmCache (org.hibernate.cache.SwarmCacheProvider)

  • is a cluster-based caching.
  • supports read-only or nonstrict read/write caching .
  • appropriate for applications those have more read operations than write operations.

2.4)JBoss TreeCache (org.hibernate.cache.TreeCacheProvider)

  • is a powerful replicated and transactional cache.

useful when we need a true transaction-capable caching architecture .

 

(3) Caching Strateties

Important thing to remembered while studying this one is none of the cache providers support all of the cache concurrency strategies.

3.1) Read-only

  • Useful for data that is read frequently but never updated.
  • It is Simple .
  • Best performer among the all.

Advantage if this one is, It is safe for using in a cluster. Here is an example for using the read-only cache strategy.

                                       
<class name="abc.mutable " mutable="true ">
<cache usage="read-only"/>
....

</class>

3.2) Read-Write

  • Used when our data needs to be updated.
  • It’s having more overhead than read-only caches.
  • When Session.close() or Session.disconnect() is called the transaction should be completed in an environment where JTA is no used.
  • It is never used if serializable transaction isolation level is required.
  • In a JTA environment, for obtaining the JTA TransactionManager we must specify the property hibernate.transaction.manager_lookup_class.
  • To use it in a cluster the cache implementation must support locking.

Here is an example for using the read-write cache stringategy.

                                       
<class name="abc.xyz" .... >
<cache usage="read-write"/>
….
<set name="yuv" ... >
<cache usage="read-write"/>
….
</set>
</class>

3.3) Nonstrict read-write

  • Needed if the application needs to update data rarely.
  • we must specify hibernate.transaction.manager_lookup_class to use this in a JTA environment .
  • The transaction is completed when Session.close() or Session.disconnect() is called In other environments (except JTA) .

Here is an example for using the nonstrict read-write cache stringategy.

                                       
<class name="abc.xyz" .... >
<cache usage=" nonstringict-read-write"/>
….
</class>

3.4) Transactional

  • It supports only transactional cache providers such as JBoss TreeCache.
  • only used in JTA environment.

(4)  Configuration

For configuring cache the hibernate.cfg.xml file is used. A typical configuration file is shown below.

<hibernate-configuration>
        <session-factory>
               ...
               <property name="hibernate.cache.provider_class">
                       org.hibernate.cache.EHCacheProvider
               </property>
               ...
        </session-factory>
</hibernate-configuration>

The name in <property> tag must be hibernate.cache.provider_class for activating second-level cache. We can use hibernate.cache.use_second_level_cache property, which allows you to activate and deactivate the second-level cache. By default, the second-level cache is activated and uses the EHCache.

(5) Advantages

5.1) Performance

Hibernate provides some metrics for measuring the performance of caching, which are all described in the Statistics interface API, in three categories:

  • Metrics related to the general Session usage.
  • Metrics related to the entities, collections, queries, and cache as a whole.
  • Detailed metrics related to a particular entity, collection, query or cache region.

5.2) About Caching

  • All objects those are passed to methods save(), update() or saveOrUpdate() or those you get from load(), get(), list(), iterate() or scroll() will be saved into cache.
  • flush() is used to synchronize the object with database and evict() is used to delete it from cache.
  • contains() used to find whether the object belongs to the cache or not.
  • Session.clear() used to delete all objects from the cache .
  • Suppose the query wants to force a refresh of its query cache region, we should call Query.setCacheMode(CacheMode.REFRESH).

(6) Conclusion

Caching is good one and hibernate found a good way to implement it for improving its performance in web applications especially when more database traffic occurs. If we implement it very correctly, we will get our applications to be running at their maximum capacities. I will cover more about the caching implementations in my coming articles. Try to get full coding guidelines before going to implement this.

Major Difference Between StringBuffer and StringBuilder

StringBuffer and StringBuilder have the same methods with one difference and that’s of synchronization. StringBuffer is synchronized( which means it is thread safe and hence you can use it when you implement threads for your methods) whereas StringBuilder is not synchronized( which implies it isn’t thread safe).

So, if you aren’t going to use threading then use the StringBuilder class as it’ll be more efficient than StringBuffer due to the absence of synchronization.

Difference between String and StringBuffer Class

Java provides the StringBuffer and String classes, and the String class is used to manipulate character strings that cannot be changed. Simply stated, objects of type String are read only and immutable. The StringBuffer class is used to represent characters that can be modified.

The significant performance difference between these two classes is that StringBuffer is faster than String when performing simple concatenations. In String manipulation code, character strings are routinely concatenated. Using the String class, concatenations are typically performed as follows:

String str = new String ("Nirmal ");
str += "Jatania!!";

If you were to use StringBuffer to perform the same concatenation, you would need code that looks like this:

StringBuffer str = new StringBuffer ("Nirmal ");
str.append("Jatania!!");

Programmers usually assume that the first example above is more efficient (Just like me before some days !!!) because they think that the second example, which uses the append method for concatenation, is more costly than the first example, which uses the + operator to concatenate two String objects.

The + operator appears innocent, but the code generated produces some surprises. Using a StringBuffer for concatenation can in fact produce code that is significantly faster than using a String. To discover why this is the case, we must examine the generated bytecode from our two examples. The bytecode for the example using String looks like this:

0 new #7
3 dup
4 ldc #2
6 invokespecial #12
9 astore_1
10 new #8
13 dup
14 aload_1
15 invokestatic #23
18 invokespecial #13
21 ldc #1
23 invokevirtual #15
26 invokevirtual #22
29 astore_1

The bytecode at locations 0 through 9 is executed for the first line of code, namely:
String str = new String("Nirmal ");

Then, the bytecode at location 10 through 29 is executed for the concatenation:

str += "Jatania!!";

Things get interesting here. The bytecode generated for the concatenation creates a StringBuffer object, then invokes its append method: the temporary StringBuffer object is created at location 10, and its append method is called at location 23. Because the String class is immutable, a StringBuffer must be used for concatenation.

After the concatenation is performed on the StringBuffer object, it must be converted back into a String. This is done with the call to the toString method at location 26. This method creates a new String object from the temporary StringBuffer object. The creation of this temporary StringBuffer object and its subsequent conversion back into a String object are very expensive.

In summary, the two lines of code above result in the creation of three objects:

A String object at location 0
A StringBuffer object at location 10
A String object at location 26

Now, let’s look at the bytecode generated for the example using StringBuffer:

0 new #8
3 dup
4 ldc #2
6 invokespecial #13
9 astore_1
10 aload_1
11 ldc #1
13 invokevirtual #15
16 pop

The bytecode at locations 0 to 9 is executed for the first line of code:
StringBuffer str = new StringBuffer(“Nirmal “);

The bytecode at location 10 to 16 is then executed for the concatenation:
str.append("Jatania!!");

Notice that, as is the case in the first example, this code invokes the append method of a StringBuffer object. Unlike the first example, however, there is no need to create a temporary StringBuffer and then convert it into a String object. This code creates only one object, the StringBuffer, at location 0.

In conclusion, StringBuffer concatenation is significantly faster than String concatenation. Obviously, StringBuffers should be used in this type of operation when possible. If the functionality of the String class is desired, consider using a StringBuffer for concatenation and then performing one conversion to String.

I found this useful piece of information in sun website…

Rule for Exception Handling while overriding methods

The question why makes any topic makes more clearer and interesting than just to know about what the concept is.

The rule about exceptions when we use them in overriding is:

If super class method is throwing any exception(checked) and if we are overriding that method in sub class

Then the subclass method can be declared using following rules

1. The subclass method can throw exception or may ignore the exception, the rule here is quite clear because if super class method is taking risk does not mean that sub class has to take the same risk.

for example in sub class i can write the code which may not be risky at all so we need not to handle any exception or need not to throw any.

below code explains the scenario.
class Super{
public void test() throws IOException{
System.out.println(”Super.test()”);
}
}
class Sub extends Super{
public void test(){
System.out.println(”Sub.test()”);
}
}

2. If we are throwing any exceptions those should be sub type of exceptions declared in super class method.

this rule is very interesting to discuss.

Now i will present some code which is calling Super class method test()

public class Overriding {
public static void main(String[] args) {
Super super1 = new Super ();
try {
super1.test();
} catch (IOException e) {
e.printStackTrace();
}
}
}

In overriding class i am calling the method test() using object of Super class, here the reference variable super1 is of type Super,and test() method is throwing IOException which is checked exception so either we have to handle it or declare it, here i am handling it with try and catch.

Now i decided to override the test() method is my Sub class by throwing the same exception.

class Super{
public void test() throws IOException{
System.out.println(”Super.test()”);
}
}

and i will change the way i am creating instance in Overriding class to polymorphic

Super super1 = new Sub();

Here the reference super1 is of type Super but it is actually pointing ti Sub class object

so when we say super1.test()

compiler checks whether test() method is there in super class or not of it is not there it will not compile. We have test() method in Super class and it throws checked exception so we have to surround it with try and catch

try {
super1.test();
} catch (IOException e) {
e.printStackTrace();
}

Now let me say why we have to use Same or sub type of Exception in sub class test method declaration.

super1.test() is going to call subclass method in runtime because we are using polymorphic assignment in creating super1 instance.

if sub class method is allowed to throw any super type of exceptions declared in Super class method. that is if we are allowed to throw Exception instead IOException( or its subtype). it will not fit into catch statement since catch is using exception declared in super class method that is IOException.

That is the reason we have to use same exception or its subtype.

complete code is given below.

public class Overriding {
public static void main(String[] args) {
Super super1 = new Sub();
try {
super1.test();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Super{
public void test() throws IOException{
System.out.println(”Super.test()”);
}
}
class Sub extends Super{
public void test(){
System.out.println(”Sub.test()”);
}
}

Thanks…

Comparing Features: iPad vs. iPhone 3GS vs. iPod touch

At first glance, the iPad, iPhone 3GS, and iPod touch may look very similar to each other. After all, they use the same operating system, run the same apps, and look like larger and smaller versions of each other. But are they really the same?

A close look at the hardware and software features of each device reveals them to be very different indeed. One has a camera, the others don’t. One is a phone, the others aren’t. One offers a big screen, the others are palm-sized.

The chart below shows how these three devices stack up against each other in terms of hardware and software features.

Comparing Features: iPad, iPhone 3GS, and iPod touch

iPad iPhone 3GS iPod touch
capacity 16GB, 32GB, 64GB 16GB, 32GB 8GB, 32GB, 64GB
screen size/
resolution
9.7 inches/ 1024 x 768 3.5 inches/ 480 x 320 3.5 inches/ 480 x 320
GPS Yes (limited GPS on WiFi-only models) Yes (Assisted GPS) No
battery life (in hours) 10 up to 12 talk/ 9 Wifi/ 10 video/ 30 audio up to 6 video/ 30 audio
networking WiFi, 3G on some models WiFi/3G/EDGE WiFi
bluetooth Yes Yes Yes
camera No 3 megapixel, still and video No
video editing app No Yes No
video out to TV No No Yes
phone No Yes No
size (in inches) 9.56 x 7.47 x 0.5 4.5 x 2.4 x 0.48 4.3 x 2.4 x 0.33
weight (in pounds) 1.5 (1.6 on 3G models) 0.3 0.25
app store support Yes Yes Yes
price $499 – $829 $199 – $299 $199 – $399

New Features in Java 7.0

Have a look on New Features in Java 7.0

* JSR 277 Java Module System
* JSR 294 Improved Modularity Support
* JSR 295 Beans Binding
* JSR 303 Beans Validation
* JSR 296 Swing Application Framework
* JSR 203 NIO2 JSR 220 Java Persistence APIs
* JSR 255 JMX 2.0
* JSR 262 Web Services Connector for JMX
* JSR 260 Javadoc Technology Update
* JSR 275 Units and Quantities
* JSR 310 Date and Time API
* JSR 308 Annotations on Java Types