Java Generics
Upcoming SlideShare
Loading in...5
×
 

Java Generics

on

  • 3,739 views

 

Statistics

Views

Total Views
3,739
Views on SlideShare
3,648
Embed Views
91

Actions

Likes
5
Downloads
206
Comments
0

4 Embeds 91

http://owen.com 73
http://www.slideshare.net 8
http://localhost 8
http://sysdecom-projects.com 2

Accessibility

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Let's start then by looking at the new features included at the language level in J2SE 5
  • This slide lists the seven new key features in J2SE 5. We'll describe each of these features. For generics and metadata we're going to go into a lot of detail to help you understand all of the issues around using these features correctly and effectively.
  • Generics is a feature that has been requested many times in Java. Sun have had to be very careful about how to introduce this feature in a way that minimises the impact of compatability. As we'll see generics is a rather bad name for this feature since what we're really doing is allowing classes to be made type specific rather than type generic (which is really the situation that we have had all along in Java).
  • OK, Lets take a look at Pre Java SE 5.0 code here. Can anyone tell if there is a problem here. Is it a compile time problem or a runtime problem? What problem? => Runtime exception
  • This piece of code illustrates the problem in Java that generics addresses. A programmer has created a method called expurgate that takes a collection and removes all strings who's length is four characters from it. The method takes a Collection as a parameter and then iterates through all of the elements looking for four character strings. The Collection can hold objects of any type (meaning strictly speaking that it is generic - see the naming problem?) When we extract an element from the collection we need to do an explicit cast to tell the compiler the type of the object we're getting. This is dangerous, as we can see. A different programmer creates a Vector and rather than adding a String, adds an Integer object. This all compiles fine, as Integer is still a sub-class of Object which is the type of the argument for the add method. However, at run time when the code calls expurgate the VM will throw a ClassCastException since the Integer object is not a String or sub-type of String. This is bad because it is a runtime exception. This code could be running in a telco billing application where runtime exceptions mean potentially large loss of revenue. What we need is a way to tell the compiler, not the VM what type the collection is so that the compiler can check all uses and report an error when the code is compiled, not when it's running. This is what generics do.
  • To restate the problem, the issue is that the compiler cannot check the types of the objects being stored in a collection because it has no way of knowing the type of the object, other than that it will be an Object or sub-type, which all classes by default are. All assignments when using the collections must do an explicit cast and can generate a runtime ClassCastException. The solution is for the programmer to give an explicit typing to a collection (or other class where this is required). By doing that the compiler can now check that all items added to a typed collection are correct. If we try to add an Integer to a String typed collection we will get a compiler error telling us that it is an inappropriate type. We can make the changes and prevent a runtime exception. The implementation of this feature is only in terms of compilation. The compiler is effectively adding the explicit cast for you and ensuring that only the correct type of obejcts are added. This is a key point from the perspective of compatability, which we'll discuss in more detail later. This is guaranteed to succeed from the point of view of eliminating ClassCastExceptions caused by this type of error. The asterisk is there because this will only hold true if all the code of an application is recompiled using the J2SE 5 compiler, so that all references can be checked. Pre 5.0 class files will still run using the new JVM. If you mix old and new class files you could still get a ClassCastException since the compiler will have been unable to check that the type of object being added to a collection is correct.
  • In J2SE 5 all the collection classes (as well as many others) have been made generic. Here we look at the same example we had earlier that would have thrown a ClassCastException. Using generics, when we instantiate the Vector class we also include a type argument to tell the compiler that the Vector is only to be used to hold objects of type String (String is final so it's not possible to use a sub-class). If we then try and call the add method with an Integer object as a parameter the compiler will know this is wrong and will report an error. Lets declare another Vector, this time parameterised for Integer objects. If we return the comparison between the two Vectors what will the result be, true or false? The answer is true. The base type of the objects is still the same, they are both Vector and they both share the same class at runtime. The fact that one has been typed to hold Strings and one has been typed to hold Integers does not affect this comparison. This is an important fact to remember as we'll see later when we discuss type erasure.
  • Well of course you all know that I wouldn't ask if the answer was yes. The problem is that A collection with the type argument of Objects is NOT a supertype of all types of collection. If you try to call this method and pass in a collection with type argument String you will get a compiler error due to the type mismatch. How do we therefore solve this problem? Invariant sub-typing: Collection is not a super-class of Collection Remember earlier when we saw the comparison of the two references? The base types are the same, but parameters do not have inheritance in the same way as concrete classes.
  • The answer is using what is called a wildcard type argument. This is the question mark that we saw earlier in the syntax definition for type arguments. The wildcard type is equivalent to saying the type is unknown, so Collection is the same as saying a Collection of unknown type. This is also something important to remember as we'll see shortly
  • There may be situations where we want to be able to define a type argument so that it is restricted to a particular class or sub-type of that class. Unlike normal classes, parameterised types do not have inheritance - we saw this earlier where a Collection of type String could not be treated as a sub-class of Collection of type Object. In this example we want to define a method that can draw a set of shapes taken from a List. Since we have a good OO design let's say we've defined an interface called Shape which has concrete implementations called Circle and Triangle. If we defined the drawAll() method to take a List of type Shape we'd get compiler errors trying to pass a List of Circle or Triangle objects.. We could use the wildcard type, but then we could pass any List to the method including ones that did not contain Shape objects. What we need to do is use a bounded wildcard, which is what we do here. We still use the wildcard type but we also specify that it extends Shape. This means that only a List typed to contain objects that are a sub-class of Shape can be passed as a parameter (remember that Shape is a sub-class of itself). Our example will compile and work as we want it to do.
  • Generics is a feature that has been requested many times in Java. Sun have had to be very careful about how to introduce this feature in a way that minimises the impact of compatability. As we'll see generics is a rather bad name for this feature since what we're really doing is allowing classes to be made type specific rather than type generic (which is really the situation that we have had all along in Java).
  • The first feature is what's called autoboxing and unboxing. Java is an object oriented language, but to purist like Smalltalk developers it's not truly object oriented as it still has primitive types to represent numbers and booleans. The reason for including these is that if everything is treated as an object you will never be able to get the application to perform as well as natively compiled C and C++ code. The problem with primitives is that in order to store them in a collection they have to be made into an object. Java provides the wrapper classes like Integer and Short for this purpose. To add a primitive to a collection is therefore complex as we must first instantiate a new wrapper class object and then add it to the collection. Similarly when getting the value out of the collection we first must retrieve the wrapper object and then call the appropriate method. Auto-boxing and unboxing solves this problem by letting the compiler do the hard work for us. As we can see in the example we can simply assign the value 22 to the Byte wrapper class object. The compiler will instantiate the object for us. We can do this because Java does not support explicit pointers. In C or C++ we wouldn't know whether this was assigning the memory address 22 to this object reference. Since in Java you cannot do that, the compiler knows it must be an auto-boxing conversion. Similarly when we want to get the value back we simply say int i = byteObj and the compiler fills in the method call for us. This will also work in method calls so we can simply pass the value 22 to the add method of ArrayList and the compiler will replace that with add(new Integer(22)).
  • The first feature is what's called autoboxing and unboxing. Java is an object oriented language, but to purist like Smalltalk developers it's not truly object oriented as it still has primitive types to represent numbers and booleans. The reason for including these is that if everything is treated as an object you will never be able to get the application to perform as well as natively compiled C and C++ code. The problem with primitives is that in order to store them in a collection they have to be made into an object. Java provides the wrapper classes like Integer and Short for this purpose. To add a primitive to a collection is therefore complex as we must first instantiate a new wrapper class object and then add it to the collection. Similarly when getting the value out of the collection we first must retrieve the wrapper object and then call the appropriate method. Auto-boxing and unboxing solves this problem by letting the compiler do the hard work for us. As we can see in the example we can simply assign the value 22 to the Byte wrapper class object. The compiler will instantiate the object for us. We can do this because Java does not support explicit pointers. In C or C++ we wouldn't know whether this was assigning the memory address 22 to this object reference. Since in Java you cannot do that, the compiler knows it must be an auto-boxing conversion. Similarly when we want to get the value back we simply say int i = byteObj and the compiler fills in the method call for us. This will also work in method calls so we can simply pass the value 22 to the add method of ArrayList and the compiler will replace that with add(new Integer(22)).
  • Generics is a feature that has been requested many times in Java. Sun have had to be very careful about how to introduce this feature in a way that minimises the impact of compatability. As we'll see generics is a rather bad name for this feature since what we're really doing is allowing classes to be made type specific rather than type generic (which is really the situation that we have had all along in Java).
  • The next new feature is the enhanced for loop, If we have a collection and want to iterate over all the elements we use a for loop and an Iterator object. This is potentally error prone as the for loop has three parts to it initialisation, test and increment. The iterator can be used in all three of these places; if cut and paste is used incorrectly or an identifier is mis-typed some very subtle and hard to find bugs can be introduced. The solution is to let the compiler do the hard work for you again. To do this, the for loop has had a new syntactical construct added. Rather than using the traditional three statements separated by semi-colons, we have a single statement of the form variable defintiion colon collection name. This tells the compiler that we want to iterate over the collection specified and will use the variable identifier within the loop to reference each item. This sytax will work either for a collection or for an array.
  • Here we see a good example of old and new style programming. We have a method that is designed to cancel a set of timer tasks. In the old code we would need to retrieve the Iterator from the collection passed as a parameter, which is the initialisation of the for loop. The test of the for loop uses the hasNext method of the iterator and then within the body of the foor loop we use the next method to retrieve the element. We also need to do an explicit cast so that the object retrieved from the collection can be assigned to the correct type. Obvioulsy, this is rather verbose and prone to errors when using the same Iterator three times. The new code makes this much simpler. We simply use the new for loop construct to define a variable, task that will be used in the body of the for loop, being of type TimerTask and iterating over the collection passed in, c. We then simply call the cancel method on task. We're also using generics in this example to tell the compiler the type of the collection.
  • Generics is a feature that has been requested many times in Java. Sun have had to be very careful about how to introduce this feature in a way that minimises the impact of compatability. As we'll see generics is a rather bad name for this feature since what we're really doing is allowing classes to be made type specific rather than type generic (which is really the situation that we have had all along in Java).
  • Often there are times when a programmer wants to have a variable that can only hold one of a fixed set of values. Typically we do this by assigning a number to each value and then storing it as an integer, using final static defintitions to assign the appropriate values. This is not a reliable mechanism which is why J2SE has introduced type safe enumerations. An enumeration is a new kind of class definition which uses the keyword enum to differentiate it from a normal class. Even though an enumeration is like a class in many way, it is not the same. You cannot instantiate an enumeration; this is effectively done once by the VM when the system. The definition of an enumeration contains a set of public, self-typed members which are used as the constants of that type. These values can be used in a switch statement with the case keyword. Previously all values used with a case statement had to be integers.(Sang: so you can do swtich statement with a typed object?) The compiler will handle the use of the enumeration correctly. With the introduction of enumerations Java now has a new reserved word, enum. This is a consideration from a migration perspective since any code using enum as an identifier will need to be changed to compile under J2SE 5.
  • First example of the use of an enumeration. This code uses two simple enumerations to represent the cards in a pack. One enumeration is used for the suits and one is used for the values. The definition is very simple, we just define the enumeration as having the constants we want separated by commas. We can then refer to these constants in our program, for example in a switch statement. For this example we create an ArrayList to hold the pack of cards. We use a type argument to tell the compiler that we want this List to only hold objects of type Card (which is defined elsewhere). We can then use the new for loop construct to iterate over the enumerations, populating the list. Notice the use of the values() method to return a collection of the constants of the enumeration. Finally we shuiffle the deck using the shuffle() utility method of the Collections class. Using a combination of features from J2SE 5 we can see that code can become much more concise, easy to read and easy to maintain. Imagine writing this code in pre J2SE 5 Java; it would take 3 or 4 times as much code
  • .
  • Generics is a feature that has been requested many times in Java. Sun have had to be very careful about how to introduce this feature in a way that minimises the impact of compatability. As we'll see generics is a rather bad name for this feature since what we're really doing is allowing classes to be made type specific rather than type generic (which is really the situation that we have had all along in Java).
  • Java has always supported import declarations that allow types from other packages to be referred to using their simple names, i.e. without using a fully qualified class name. However, the static members of classes have not been treated in the same way; for example, whenever you refer to a static member of the Color class it's necessary to explicitly state Color.yellow or Color.blue. In J2SE 5 the import mechanism has been extended to include static members. To use this the static keyword is added to the normal import to indicate that static members can be accessed without specifying the class name. As with normal imports the wildcard * can be used to indicate all members of the package. The import applies to all static members of the class including methods and enums.
  • Lets look at some of the changes and new features in the Java Virtual Machine
  • Now that Java supports varargs, the much loved (or maligned) printf library call has been added that will be familiar to C and C++ programmers. If you have not used these languages before you will want to have a look at the manual page to see exactly how to use this. printf takes a string as an argument that will be displayed on the standard output. This string can contain arguments identified by the % character that will be replaced by the values of the other arguments when the string is displayed. The order of the arguments in the string must match the order of the arguments in the method call. The % character is followed by characters to indicate what type the argument is and how it should be formatted for display. For example, %s indicates a free format string; %2.2F indicates a floating point number that should have two digits before and after the decimal point. Since Java is cross platform you can use %n to specify a newline that will be correct for the current OS. <br /> and <br /> can still be used, but these will only output carriage return and linefeed. The scanf function that is the inverse of printf has not been included. The Scanner class provides a simple text scanner which can parse primitive types and strings using regular expressions. A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace. The resulting tokens may then be converted into values of different types using the various next methods. In the example shown, the code allows a user to read a number from System.in
  • Lets look at some of the changes and new features in the Java Virtual Machine
  • Metadata allows programmer to specify annotations for parts of a program. An annotation is a modifier consisting of an annotation type and zero or more element-value pairs, each of which associates a value with a different element of the annotation type. The purpose of an annotation is simply to associate information with the annotated program element. Annotations can be used by tools such as compilers, IDEs and runtime tools to produce derived files, whether that is something like a new source file, a deployment descriptor or some other file. Java already has some annotations, but these are not organised in a formal way, which is what metadata does. For example, the Serializeable interface contains no methods. If you create a class that implements Serializeable, what does it do? The answer is that implementing the interface is used as a marker (or annotation) to tell the compiler that this class can be serialised. The compiler will then add apropriate code to perform serialisation when required. Xdoclets is another example of a form of annotation that can be used to derive deployment descriptors, etc from infromation contained in the source file. Annotations may be used as modifiers in any declaration, whether package, class, interface, field, method, parameter, constructor, or local variable. Annotations may also be used on enum constants. Such annotations are placed immediately before the enum constant they annotate.

Java Generics Java Generics Presentation Transcript

  • J2SE 5.0 Generics
    • Carol McDonald
      • Java Technology Architect
        • Sun Microsystems, Inc.
  • Speaker’s Qualifications
    • Carol cDonald:
      • Java Architect at Sun Microsystems
      • Before Sun, worked on software development of:
        • Application to manage car Loans for Toyota (>10 million loans)
        • Pharmaceutical Intranet ( Roche Switzerland)
        • Telecom Network Mgmt ( Digital France)
        • X.400 Email Server ( IBM Germany)
  • Java SE 1.5 Language Changes
  • Seven Major New Features
    • Generics
    • Autoboxing/Unboxing
    • Enhanced for loop (“foreach”)
    • Type-safe enumerations
    • Varargs
    • Static import
    • Metadata
  • Generics
  • Is there a problem in here? Vector v = new Vector(); v.add(new Integer (4)); OtherClass.expurgate(v); ... static void expurgate(Collection c) { for (Iterator it = c.iterator(); it.hasNext();) if ((( String )it.next()).length() == 4) it.remove(); }
  • The Problem (Pre-J2SE 5.0) Vector v = new Vector(); v.add(new Integer (4)); OtherClass.expurgate(v); ... static void expurgate(Collection c) { for (Iterator it = c.iterator(); it.hasNext();) /* ClassCastException */ if ((( String )it.next()).length() == 4) it.remove(); }
  • Generics
    • Problem: Collection element types
      • Compiler is unable to verify types
      • Assignment must use the cast operator
      • This can generate runtime errors ( ClassCastException )
    • Solution:
      • Tell the compiler what type the collection is
      • Let the compiler fill in the cast
  • Using Generic Classes
    • Instantiate a generic class to create type specific object
    • Example
    • Vector <String> x = new Vector <String> ();
    • x.add(new Integer(5)); // Compiler error!
    • Vector <Integer> y = new Vector <Integer> ();
  • Wildcards
    • Method to print contents of any Collection?
    • Wrong!
    • Passing a Collection of type String will give a compiler error
    void printCollection(Collection <Object> c) { for (Object o : c) System.out.println( o ); }
  • Wildcards
    • Correct way:
    • ? is the wildcard type
    • Collection <?> means Collection of unknown
    void printCollection( Collection <?> c) { for (Object o : c) System.out.println(o); }
  • Bounded Wildcards
    • A wildcard can be specified with an upper bound
    public void drawAll (List< ? extends Shape >s) { ... } List<Circle> c = getCircles(); drawAll(c) ; List<Triangle> t = getTriangles(); drawAll(t) ;
  • Autoboxing & Unboxing
  • Autoboxing/Unboxing of Primitive Types
    • Problem: (pre-J2SE 5.0) Conversion between primitive types and wrapper types (and vice-versa)
      • must manually convert a primitive type to a wrapper type before adding it to a collection
      • int i = 22;
      • List l = new LinkedList();
      • l.add( new Integer(i) );
  • Autoboxing/Unboxing of Primitive Types
    • Solution: Let the compiler do it
      • Integer intObj = 22 ; // Autoboxing conversion
      • int i = intObj; // Unboxing conversion
      • ArrayList< Integer > al = new ArrayList<Integer>();
      • al .add( i ); // Autoboxing conversion
  • Enhanced for Loop
  • Enhanced for Loop (foreach)
    • Problem: (pre-J2SE 5.0)
      • Iterating over collections is tricky
      • Often, iterator only used to get an element
      • Iterator is error prone (Can occur three times in a for loop)
    • Solution: Let the compiler do it
      • New for loop syntax for (variable : collection)
      • Works for Collections and arrays
  • Enhanced for Loop Example
    • Old code pre-J2SE 5.0
      • void cancelAll(Collection c) {
      • for ( Iterator i = c.iterator(); i.hasNext() ; ){
        • TimerTask task = (TimerTask) i.next();
        • task.cancel();
        • }
      • }
    • New Code
      • void cancelAll(Collection <TimerTask> c) {
        • for ( TimerTask task : c )
        • task.cancel();
      • }
    Iterating over collections, tricky, error prone
    • New for loop syntax:
    • Let the compiler do it
    • Works for Collections and arrays
  • Type-safe Enumerations
  • Type-safe Enumerations
    • Problem: (pre-J2SE 5.0) to define an enumeration:
      • Defined a bunch of integer constants:
      • public static final int SEASON_WINTER = 0;
      • public static final int SEASON_SPRING = 1;
    • Issues of using Integer constants
      • Not type safe (any integer will pass),Brittleness (how do add value in-between?), Printed values uninformative (prints just int values)
    • Solution: New type of class declaration
      • enum type has public, self-typed members for each enum constant
      • enum Season { WINTER, SPRING, SUMMER, FALL }
  • Enumeration Example: public class Card { public enum Suit { spade, diamond, club, heart }; public enum Rank { ace, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king }; private Card (Rank rank, Suit suit) { this.rank = rank; this.suit = suit; } } List< Card > deck = new ArrayList< Card >(); for ( Suit suit : Suit.values ()) for ( Rank rank : Rank.values ()) deck.add(new Card(rank, suit)); Think how much JDK1.4 code this would require!
  • Varargs
  • Before Varargs Example //example method that takes a variable number of parameters int sum( Integer[] numbers ) { for(int i: numbers) // do something } // Code fragment that calls the sum method sum( new Integer[] {12,13,20} ); http://www.javaworld.com/javaworld/jw-04-2004/jw-0426-tiger1.html
    • Problem: (in pre-J2SE 5.0) To have a method that takes a variable number of parameters
      • Can be done with an array, but caller has to create the array first
  • Varargs Example (Cont) //example method that takes a variable number of parameters int sum ( Integer... numbers ) { for(int i: numbers) // do something } // Code fragment that calls the sum method sum( 12,13,20 ); http://www.javaworld.com/javaworld/jw-04-2004/jw-0426-tiger1.html
    • Solution: Let the compiler do it for you:
      • String format (String fmt, Object... args);
      • Java now supports printf(...)
  • Varargs examples
    • APIs have been modified so that methods accept variable-length argument lists where appropriate
      • Class.getMethod
      • Method.invoke
      • Constructor.newInstance
      • Proxy.getProxyClass
      • MessageFormat.format
    • New APIs do this too
      • System.out. printf (“%d + %d = %d ”, a, b, a+b);
  • Static Imports
  • Static Imports
    • Problem: (pre-J2SE 5.0)
      • Having to fully qualify every static referenced from external classes
    • Solution: New import syntax
      • import static TypeName.Identifier;
      • import static Typename.*;
      • Also works for static methods and enums
      • e.g Math.sin(x) becomes sin(x)
  • Formatted I/O
  • Simple Formatted I/O
    • Printf is popular with C/C++ developers
      • Powerful, easy to use
    • Finally adding printf to J2SE 5.0 (using varargs)
      • out.printf(“%-12s is %2d long”, name, l);
      • out.printf(“value = %2.2F”, value);
  • Annotations
  • Annotations Metadata (JSR-175)
    • Provide standardised way of adding annotations to Java code
      • public @Remote void foo() {}
    • Annotations are used by tools that work with Java code:
      • Compiler
      • IDE
      • Runtime tools
    • Used to generate interfaces, deployment descriptors...
  • Annotations Example: JAX-RPC
    • Old Code
    • public interface PingIF implements java.rmi.Remote {
      • public void foo() throws java.rmi.RemoteException;
      • }
      • public class Ping implements PingIF {
      • public void foo() {...}
      • }
    • New Code
      • public class Ping {
      • public @Remote void foo() {}
      • }
  • Resources and Summary
  • For More Information (1/2)
    • Memory management white paper
      • http://java.sun.com/j2se/reference/whitepapers/
    • Destructors, Finalizers, and Synchronization
      • http://portal.acm.org/citation.cfm?id=604153
    • Finalization, Threads, and the Java Technology Memory Model
      • http://developers.sun.com/learning/javaoneonline/2005/coreplatform/TS-3281.html
    • Memory-retention due to finalization article
      • http://www.devx.com/Java/Article/30192
  • For More Information (2/2)
    • FindBugs
      • http://findbugs.sourceforge.net
    • Heap analysis tools
      • Monitoring and Management in 6.0
        • http://java.sun.com/developer/technicalArticles/J2SE/monitoring/
      • Troubleshooting guide
        • http://java.sun.com/javase/6/webnotes/trouble/
      • JConsole
        • http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html
  • Resources
    • http://java.sun.com/javase
    • Java.net
    • http://jdk.dev.java.net
  • Stay in Touch with Java SE
    • http://java.sun.com/javase
    • JDK Software Community
      • planetjdk.org
      • community.java.net/jdk
    • JDK 6
      • http://jdk6.dev.java.net/
      • http://jcp.org/en/jsr/detail?id=270
    • JDK 7
      • http://jdk7.dev.java.net/
      • http://jcp.org/en/jsr/detail?id=277
  • Thank You!
    • Carol McDonald
      • Java Technology Architect
        • Sun Microsystems, Inc.