E N D
CSC 2053 New from 5.0
AutoBoxing • Before J2SE 5.0, working with primitive types required the repetitive work of converting between the primitive types and the wrapper classes. The new autoboxing feature in J2SE 5.0 handles conversions -- for example, between values of type int and values of type Integer – in much more straightforward manner. • Autoboxing can be used with assignment conversion and with wrapper class methods (e.g. Integer.parseInt()) • If n is value of type int, then boxing converts n to an Integer object objN such that objN.intValue() is n
AutoBoxing Example: int m = 20, n; Integer objM = new Integer(10); Integer objN; objN = m; // autoboxing - converts m to an object n = objN; // unboxing – changes objN to an int // Expressions n = objM + 5; // unbox before addition objM++; // unbox before incrementing
The statement is executed until the condition becomes false The initialization is executed once before the loop begins The increment portion is executed at the end of each iteration The Enhanced for Statement • A for statement has the following syntax: for ( initialization ; condition ; increment ) statement;
The pattern for processing elements of an ArrayList of Student objects called StudentList is : • ArrayList StudentList = new ArrayList(); Student currentObject; for (int index = 0; index < StudentList.size();index++) { currentObject = StudentList.get(index); // process currentObject } • To perform the same operation with an enhanced for loop, for(Student currentObject:StudentList) { System.out.println(currentObject); } Where currentObject is a variable of Student
Enhanced For Loop // For loop – old way: ArrayList listofAutos = new ArrayList(); Auto currentAuto; for (int index = 0; index < listofAutos.size();index++) { currentAuto = listofAutos.get(index); // process currentAuto } // For loop – new way: // Declare an object of an ArrayList of Autos called cars ArrayListcars = new ArrayList(); for (Auto currentAuto: cars) { // process currentAuto System.out.println(currentAuto);
public static void main( String [] args ) { ArrayList<Integer> list = new ArrayList<Integer>( ); list.add( new Integer( 34 ) ); list.add( new Integer( 89 ) ); list.add( 65 ); // autoboxing System.out.println( "\nUsing the enhanced for loop:" ); for ( Integer currentInteger : list ) System.out.print( currentInteger + "\t" ); System.out.println( "\nUsing unboxing and enhanced for loop:" ); for ( int currentInt : list ) // unboxing System.out.print( currentInt + "\t" );
import java.util.ArrayList; public class Autoboxing { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < 10; i++) list.add(i); int sum = 0; for ( Integer j : list) sum += j; //unboxing for calculating System.out.printf("The sum is %d.", sum ); } } First, ints are boxed to Integers as they are added to the ArrayList. Then Integers are unboxed to ints to be used in calculating the sum. Finally, the int representing the sum is boxed for use in the printf() statement.
Iterators and for Loops • Recall that an iterator is an object that allows you to process each item in a collection • A variant of the for loop simplifies the repetitive processing the items • For example, if BookList is an iterator that manages Book objects, the following loop will print each book: for (Book myBook : BookList) System.out.println (myBook); Where Book is the name of the class and mybook is the object that will be used to iterate through it.
Iterators and for Loops • This style of for loop can be read "for each Book in BookList, …" • Therefore the iterator version of the for loop is sometimes referred to as the foreach loop • It eliminates the need to call thehasNext and next methods explicitly.
Variable Length Parameter Lists • Suppose we wanted to create a method that processed a different amount of data from one invocation to the next • For example, let's define a method called average that returns the average of a set of integer parameters // one call to average three values mean1 = average (42, 69, 37); // another call to average seven values mean2 = average (35, 43, 93, 23, 40, 21, 75);
Variable Length Parameter Lists • We could define overloaded versions of the average method • Downside: we'd need a separate version of the method for each parameter count • We could define the method to accept an array of integers • Downside: we'd have to create the array and store the integers prior to calling the method each time • Instead, Java provides a convenient way to create variable length parameter lists
Indicates a variable length parameter list element type array name Variable Length Parameter Lists • Using special syntax in the formal parameter list, we can define a method to accept any number of parameters of the same type • For each call, the parameters are automatically put into an array for easy processing in the method public double average (int ... list) { // whatever }
Variable Length Parameter Lists public double average (int ... list) { double result = 0.0; if (list.length != 0) { int sum = 0; for (int num : list) sum += num; result = (double)num / list.length; } return result; }
Variable Length Parameter Lists • The type of the parameter can be any primitive or object type public void printGrades (Grade ... grades) { for (Grade letterGrade : grades) System.out.println (letterGrade); }
Variable Length Parameter Lists • A method that accepts a variable number of parameters can also accept other parameters • The following method accepts an int, a String object, and a variable number of double values into an array called nums public void test (int count, String name, double ... nums) { // whatever }
Generic Types • Java enables us to define a class based upon a generic type • This means that we can define a class so that it stores, operates on, and manages objects whose type is not specified until the class is instantiated. • Assume that we need to define a class named Box that stores and manages other objects class Box<T> { // declarations and code that manage // objects of type T }
Generic Types • Then if we wanted to instantiate a Box to hold objects of the Widget class Box<Widget> box1 = new Box<Widget> • But we could also instantiate a Box to hold objects of the Gadget class Box<Gadget> box2 = new Box<Gadget>
Generic Types • The type supplied at the time of instantiation replaces the type T wherever it is used in the declaration of the class • A generic type such as T cannot be instantiated • Generics are used to develop collection classes
Generics • One of the primary uses of generics is to abstract data types when working with collections. • Prior to the JDK 5.0 release, when you created a Collection, you could put anything in it, for example: ArrayList myList = new ArrayList(10); myList.add(new Integer(10)); myList.add("Hello, World"); • Since ArrayList takes any kind of object, if you wanted to restrict your Collection to a specific type, it was difficult at best. • Getting items out of the collection required you to use a casting operation: Integer myInt = (Integer)myList.iterator().next();
Generics • Previously, if you accidentally cast the wrong type, the program would successfully compile, but an exception would be thrown at runtime. • Such an event could impair the reliability of the code. • Generics allows you to specify, at compile-time, the types of objects you want to store in a Collection. • The compiler can then check that the code is consistent with the specified code.
Generics • Then when you add and get items from the list, the list knows what types of objects are supposed to be acted on. • You don't need to cast anything. • A Collection object is created with a specified type that dictates what type of element can be stored in it. • The "<>" characters are used to designate what type is to be stored. • If the wrong type of data is provided, a compile-time error is thrown. For example, if you try to compile the following class:
Generics public class First { public static void main(String args[]) { List <Integer> myList = new ArrayList <Integer> (10); myList.add(10); myList.add("Hello, World"); } } you get an error like this: First.java:7: cannot find symbol : method add(java.lang.String) location: interface java.util.List<java.lang.Integer> myList.add("Hello, World"); ^ 1 error
Generics • This message basically says that there is no add(String) method available when the interface is for a List of Integer objects. • The myList.add(10); method did add the Integer object of number 10 to the list. • Autoboxing converted the int type to an Integer object. • It is only the adding of a String to a List of Integer objects that failed here.
Generics • If you look at the interface declaration for java.util.List, you see the following: public interface List<E> extends Collection<E> • This literally says that it is declaring a List of E's. • Later in the interface definition, you see methods where the argument or return type is replaced by an E: (or T) Iterator <E> iterator(); ListIterator <E> listIterator(); boolean add(E o); boolean addAll(Collection<?> extends <E> c);
Generics • When we invoke this with: List <Integer> myList = new ArrayList <Integer> (10); • All of the E’s in the List interface are replaced by Integer. The E is a formal parameter and the Integer is the actual argument. • The ? in the addAll line can be thought of as a collection of unknown, but the unknown would be E or a subclass. • The question mark is called a wildcard. It is a supertype allowing you specify at creation the type you want to store .
Generics • Because the E is specified at compile time, you don't have to rely on runtime exceptions to find type mismatches. • This construct allows you to work with collections of subclasses, and not simply exact matches.
Using bounds for Generic Types • To check the type at compile time, we need to bind the generic type using the modifier <T extends Comparable>: public static <T extends Comparable<T> > max(T objA, T objB) { if(objA.compareTo(objB) > 0) return objA; else return objB; } • Now the compiler flags with an error if any class is used which does not implement Comparable.
Generic Methods - Using Bounds • We use bounding to ensure that the compiler will check the type arguments to see if they implement the Comparable interface. • We bound the generic type using the modifier: <T extends Comparable<T>> • Extends is used rather than implements because this syntax can be used in an inheritance hierarchy for generic super classes and subclasses.
Wildcards • To deal with generic classes and methods that could be passed either a superclass or subclass as a type argument, Java introduced wildcards. In this final version of max: public static <T extends Comparable<? Super T>> T max(T objA, T objB) { if(objA.compareTo(objB) > 0)) return objA; else return objB; }
Wildcards • The tag ?in this final version of the max method, indicates that the type itself or some super class implements the Comparable interface • The ? With bound “super T> directs the compiler to verify that either T or some super class of T implements Comparable. • If this method compiles without a warning, it is then assuredly type safe.