Thinking in Java 4th Edition phần 4 ppsx

108 384 0
Thinking in Java 4th Edition phần 4 ppsx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

}; } public static void main(String[] args) { CollectionSequence c = new CollectionSequence(); InterfaceVsIterator.display(c); InterfaceVsIterator.display(c.iterator()); } } /* Output: 0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx 0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx *///:~ The remove( ) method is an "optional operation," which you will learn about in the Containers in Depth chapter. Here, it’s not necessary to implement it, and if you call it, it will throw an exception. From this example, you can see that if you implement Collection, you also implement iterator( ), and just implementing iterator( ) alone requires only slightly less effort than inheriting from AbstractCoUection. However, if your class already inherits from another class, then you cannot also inherit from AbstractCollection. In that case, to implement Collection you’d have to implement all the methods in the interface. In this case it would be much easier to inherit and add the ability to create an iterator: //: holding/NonCollectionSequence.java import typeinfo.pets.*; import java.util.*; class PetSequence { protected Pet[] pets = Pets.createArray(8); } public class NonCollectionSequence extends PetSequence { public Iterator<Pet> iterator() { return new Iterator<Pet>() { private int index = 0; public boolean hasNext() { return index < pets.length; } public Pet next() { return pets[index++]; } public void remove() { // Not implemented throw new UnsupportedOperationException(); } }; } public static void main(String[] args) { NonCollectionSequence nc = new NonCollectionSequence(); InterfaceVsIterator.display(nc.iterator()); } } /* Output: 0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx *///:~ Producing an Iterator is the least-coupled way of connecting a sequence to a method that consumes that sequence, and puts far fewer constraints on the sequence class than does implementing Collection. Exercise 30: (5) Modify CollectionSequence.java so that it does not inherit from AbstractCollection, but instead implements Collection. Holding Your Objects 303 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Foreach and iterators So far, the foreach syntax has been primarily used with arrays, but it also works with any Collection object. You’ve actually seen a few examples of this using ArrayList, but here’s a general proof: //: holding/ForEachCollections.java // All collections work with foreach. import java.util.*; public class ForEachCollections { public static void main(String[] args) { Collection<String> cs = new LinkedList<String>(); Collections.addAll(cs, "Take the long way home".split(" ")); for(String s : cs) System.out.print("‘" + s + "‘ "); } } /* Output: ‘Take’ ‘the’ ‘long’ ‘way’ ‘home’ *///:~ Since cs is a Collection, this code shows that working with foreach is a characteristic of all Collection objects. The reason that this works is that Java SE5 introduced a new interface called Iterable which contains an iterator( ) method to produce an Iterator, and the Iterable interface is what foreach uses to move through a sequence. So if you create any class that implements Iterable, you can use it in a foreach statement: //: holding/IterableClass.java // Anything Iterable works with foreach. import java.util.*; public class IterableClass implements Iterable<String> { protected String[] words = ("And that is how " + "we know the Earth to be banana-shaped.").split(" "); public Iterator<String> iterator() { return new Iterator<String>() { private int index = 0; public boolean hasNext() { return index < words.length; } public String next() { return words[index++]; } public void remove() { // Not implemented throw new UnsupportedOperationException(); } }; } public static void main(String[] args) { for(String s : new IterableClass()) System.out.print(s + " "); } } /* Output: And that is how we know the Earth to be banana-shaped. *///:~ 304 Thinking in Java Bruce Eckel Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Holding Your Objects 305 The iterator( ) method returns an instance of an anonymous inner implementation of Iterator<String> which delivers each word in the array. In main( ), you can see that IterableClass does indeed work in a foreach statement. In Java SE5, a number of classes have been made Iterable, primarily all Collection classes (but not Maps). For example, this code displays all the operating system environment variables: //: holding/EnvironmentVariables.java import java.util.*; public class EnvironmentVariables { public static void main(String[] args) { for(Map.Entry entry: System.getenv().entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } } } /* (Execute to see output) *///:~ System.getenv( ) 7 returns a Map, entrySet( ) produces a Set of Map.Entry elements, and a Set is Iterable so it can be used in a foreach loop. A foreach statement works with an array or anything Iterable, but that doesn’t mean that an array is automatically an Iterable, nor is there any autoboxing that takes place: //: holding/ArrayIsNotIterable.java import java.util.*; public class ArrayIsNotIterable { static <T> void test(Iterable<T> ib) { for(T t : ib) System.out.print(t + " "); } public static void main(String[] args) { test(Arrays.asList(1, 2, 3)); String[] strings = { "A", "B", "C" }; // An array works in foreach, but it’s not Iterable: //! test(strings); // You must explicitly convert it to an Iterable: test(Arrays.asList(strings)); } } /* Output: 1 2 3 A B C *///:~ Trying to pass an array as an Iterable argument fails. There is no automatic conversion to an Iterable; you must do it by hand. Exercise 31: (3) Modify polymorphism/shape/RandomShapeGenerator.java to make it Iterable. You’ll need to add a constructor that takes the number of elements that you want the iterator to produce before stopping. Verify that it works.  7 This was not available before Java SE5, because it was thought to be too tightly coupled to the operating system, and thus to violate "write once, run anywhere." The fact that it is included now suggests that the Java designers are becoming more pragmatic. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The Adapter Method idiom What if you have an existing class that is Iterable, and you’d like to add one or more new ways to use this class in a foreach statement? For example, suppose you’d like to choose whether to iterate through a list of words in either a forward or reverse direction. If you simply inherit from the class and override the iterator( ) method, you replace the existing method and you don’t get a choice. One solution is what I call the Adapter Method idiom. The "Adapter" part comes from design patterns, because you must provide a particular interface to satisfy the foreach statement. When you have one interface and you need another one, writing an adapter solves the problem. Here, I want to add the ability to produce a reverse iterator to the default forward iterator, so I can’t override. Instead, I add a method that produces an Iterable object which can then be used in the foreach statement. As you see here, this allows us to provide multiple ways to use foreach: //: holding/AdapterMethodIdiom.java // The "Adapter Method" idiom allows you to use foreach // with additional kinds of Iterables. import java.util.*; class ReversibleArrayList<T> extends ArrayList<T> { public ReversibleArrayList(Collection<T> c) { super(c); } public Iterable<T> reversed() { return new Iterable<T>() { public Iterator<T> iterator() { return new Iterator<T>() { int current = size() - 1; public boolean hasNext() { return current > -1; } public T next() { return get(current ); } public void remove() { // Not implemented throw new UnsupportedOperationException(); } }; } }; } } public class AdapterMethodIdiom { public static void main(String[] args) { ReversibleArrayList<String> ral = new ReversibleArrayList<String>( Arrays.asList("To be or not to be".split(" "))); // Grabs the ordinary iterator via iterator(): for(String s : ral) System.out.print(s + " "); System.out.println(); // Hand it the Iterable of your choice for(String s : ral.reversed()) System.out.print(s + " "); } } /* Output: To be or not to be be to not or be To *///:~ If you simply put the ral object in the foreach statement, you get the (default) forward iterator. But if you call reversed( ) on the object, it produces different behavior. 306 Thinking in Java Bruce Eckel Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Using this approach, I can add two adapter methods to the IterableClass.java example: //: holding/MultiIterableClass.java // Adding several Adapter Methods. import java.util.*; public class MultiIterableClass extends IterableClass { public Iterable<String> reversed() { return new Iterable<String>() { public Iterator<String> iterator() { return new Iterator<String>() { int current = words.length - 1; public boolean hasNext() { return current > -1; } public String next() { return words[current ]; } public void remove() { // Not implemented throw new UnsupportedOperationException(); } }; } }; } public Iterable<String> randomized() { return new Iterable<String>() { public Iterator<String> iterator() { List<String> shuffled = new ArrayList<String>(Arrays.asList(words)); Collections.shuffle(shuffled, new Random(47)); return shuffled.iterator(); } }; } public static void main(String[] args) { MultiIterableClass mic = new MultiIterableClass(); for(String s : mic.reversed()) System.out.print(s + " "); System.out.println(); for(String s : mic.randomized()) System.out.print(s + " "); System.out.println(); for(String s : mic) System.out.print(s + " "); } } /* Output: banana-shaped. be to Earth the know we how is that And is banana-shaped. Earth that how the be And we know to And that is how we know the Earth to be banana-shaped. *///:~ Notice that the second method, random( ), doesn’t create its own Iterator but simply returns the one from the shuffled List. You can see from the output that the Collections.shuffle( ) method doesn’t affect the original array, but only shuffles the references in shuffled. This is only true because the randomized( ) method wraps an ArrayList around the result of Arrays.asList( ). If the List produced by Arrays.asList( ) is shuffled directly, it will modify the underlying array, as you can see here: //: holding/ModifyingArraysAsList.java import java.util.*; public class ModifyingArraysAsList { public static void main(String[] args) { Holding Your Objects 307 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Random rand = new Random(47); Integer[] ia = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); System.out.println("Before shuffling: " + list1); Collections.shuffle(list1, rand); System.out.println("After shuffling: " + list1); System.out.println("array: " + Arrays.toString(ia)); List<Integer> list2 = Arrays.asList(ia); System.out.println("Before shuffling: " + list2); Collections.shuffle(list2, rand); System.out.println("After shuffling: " + list2); System.out.println("array: " + Arrays.toString(ia)); } } /* Output: Before shuffling: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] After shuffling: [4, 6, 3, 1, 8, 7, 2, 5, 10, 9] array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Before shuffling: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] After shuffling: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8] array: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8] *///:~ In the first case, the output of Arrays.asList( ) is handed to the ArrayList( ) constructor, and this creates an ArrayList that references the elements of ia. Shuffling these references doesn’t modify the array. However, if you use the result of Arrays.asList(ia) directly, shuffling modifies the order of ia. It’s important to be aware that Arrays.asList( ) produces a List object that uses the underlying array as its physical implementation. If you do anything to that List that modifies it, and you don’t want the original array modified, you should make a copy into another container. Exercise 32: (2) Following the example of MultilterableClass, add reversed( ) and randomized( ) methods to NonCollectionSequence.java, as well as making NonCollectionSequence implement Iterable, and show that all the approaches work in foreach statements. Summary Java provides a number of ways to hold objects: 1. An array associates numerical indexes to objects. It holds objects of a known type so that you don’t have to cast the result when you’re looking up an object. It can be multidimensional, and it can hold primitives. However, its size cannot be changed once you create it. 2. A Collection holds single elements, and a Map holds associated pairs. With Java generics, you specify the type of object to be held in the containers, so you can’t put the wrong type into a container and you don’t have to cast elements when you fetch them out of a container. Both Collections and Maps automatically resize themselves as you add more elements. A container won’t hold primitives, but autoboxing takes care of translating primitives back and forth to the wrapper types held in the container. 3. Like an array, a List also associates numerical indexes to objects— thus, arrays and Lists are ordered containers. 308 Thinking in Java Bruce Eckel Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 4. Use an ArrayList if you’re doing a lot of random accesses, but a LinkedList if you will be doing a lot of insertions and removals in the middle of the list. 5. The behavior of Queues and stacks is provided via the LinkedList. 6. A Map is a way to associate not integral values, but objects with other objects. HashMaps are designed for rapid access, whereas a TreeMap keeps its keys in sorted order, and thus is not as fast as a HashMap. A LinkedHashMap keeps its elements in insertion order, but provides rapid access with hashing. 7. A Set only accepts one of each type of object. HashSets provide maximally fast lookups, whereas TreeSets keep the elements in sorted order. LinkedHashSets keep elements in insertion order. 8. There’s no need to use the legacy classes Vector, Hashtable, and Stack in new code. It’s helpful to look at a simplified diagram of the Java containers (without the abstract classes or legacy components). This only includes the interfaces and classes that you will encounter on a regular basis. Simple Container Taxonomy You’ll see that there are really only four basic container components—Map, List, Set, and Queue—and only two or three implementations of each one (the java.util.concurrent implementations of Queue are not included in this diagram). The containers that you will use most often have heavy black lines around them. The dotted boxes represent interfaces, and the solid boxes are regular (concrete) classes. The dotted lines with hollow arrows indicate that a particular class is implementing an interface. The solid arrows show that a class can produce objects of the class the arrow is pointing to. For example, any Collection can produce an Iterator, and a List can produce a ListIterator (as well as an ordinary Iterator, since List is inherited from Collection). Here’s an example that shows the difference in methods between the various classes. The actual code is from the Generics chapter; I’m just calling it here to produce the output. The output also shows the interfaces that are implemented in each class or interface: //: holding/ContainerMethods.java import net.mindview.util.*; Holding Your Objects 309 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com public class ContainerMethods { public static void main(String[] args) { ContainerMethodDifferences.main(args); } } /* Output: (Sample) Collection: [add, addAll, clear, contains, containsAll, equals, hashCode, isEmpty, iterator, remove, removeAll, retainAll, size, toArray] Interfaces in Collection: [Iterable] Set extends Collection, adds: [] Interfaces in Set: [Collection] HashSet extends Set, adds: [] Interfaces in HashSet: [Set, Cloneable, Serializable] LinkedHashSet extends HashSet, adds: [] Interfaces in LinkedHashSet: [Set, Cloneable, Serializable] TreeSet extends Set, adds: [pollLast, navigableHeadSet, descendingIterator, lower, headSet, ceiling, pollFirst, subSet, navigableTailSet, comparator, first, floor, last, navigableSubSet, higher, tailSet] Interfaces in TreeSet: [NavigableSet, Cloneable, Serializable] List extends Collection, adds: [listIterator, indexOf, get, subList, set, lastIndexOf] Interfaces in List: [Collection] ArrayList extends List, adds: [ensureCapacity, trimToSize] Interfaces in ArrayList: [List, RandomAccess, Cloneable, Serializable] LinkedList extends List, adds: [pollLast, offer, descendingIterator, addFirst, peekLast, removeFirst, peekFirst, removeLast, getLast, pollFirst, pop, poll, addLast, removeFirstOccurrence, getFirst, element, peek, offerLast, push, offerFirst, removeLastOccurrence] Interfaces in LinkedList: [List, Deque, Cloneable, Serializable] Queue extends Collection, adds: [offer, element, peek, poll] Interfaces in Queue: [Collection] PriorityQueue extends Queue, adds: [comparator] Interfaces in PriorityQueue: [Serializable] Map: [clear, containsKey, containsValue, entrySet, equals, get, hashCode, isEmpty, keySet, put, putAll, remove, size, values] HashMap extends Map, adds: [] Interfaces in HashMap: [Map, Cloneable, Serializable] LinkedHashMap extends HashMap, adds: [] Interfaces in LinkedHashMap: [Map] SortedMap extends Map, adds: [subMap, comparator, firstKey, lastKey, headMap, tailMap] Interfaces in SortedMap: [Map] TreeMap extends Map, adds: [descendingEntrySet, subMap, pollLastEntry, lastKey, floorEntry, lastEntry, lowerKey, navigableHeadMap, navigableTailMap, descendingKeySet, tailMap, ceilingEntry, higherKey, pollFirstEntry, comparator, firstKey, floorKey, higherEntry, firstEntry, navigableSubMap, headMap, lowerEntry, ceilingKey] Interfaces in TreeMap: [NavigableMap, Cloneable, Serializable] *///:~ You can see that all Sets except TreeSet have exactly the same interface as Collection. List and Collection differ significantly, although List requires methods that are in Collection. On the other hand, the methods in the Queue interface stand alone; the Collection methods are not required to create a functioning Queue implementation. Finally, the only intersection between Map and Collection is the fact that a Map can produce Collections using the entrySet( ) and values( ) methods. Notice the tagging interface java.util.RandomAccess, which is attached to ArrayList but not to LinkedList. This provides information for algorithms that might want to dynamically change their behavior depending on the use of a particular List. 310 Thinking in Java Bruce Eckel Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Holding Your Objects 311 It’s true that this organization is somewhat odd, as object-oriented hierarchies go. However, as you learn more about the containers in java.util (in particular, in the Containers in Depth chapter), you’ll see that there are more issues than just a slightly odd inheritance structure. Container libraries have always been difficult design problems—solving these problems involves satisfying a set of forces that often oppose each other. So you should be prepared for some compromises here and there. Despite these issues, the Java containers are fundamental tools that you can use on a day-to-day basis to make your programs simpler, more powerful, and more effective. It might take you a little while to get comfortable with some aspects of the library, but I think you’ll find yourself rapidly acquiring and using the classes in this library. Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated Solution Guide, available for sale from www.MindView.net. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... Output: originating the exception in f() Inside g(),e.printStackTrace() java. lang.Exception: thrown from f() at Rethrowing.f(Rethrowing .java: 7) at Rethrowing.g(Rethrowing .java: 11) at Rethrowing.main(Rethrowing .java: 29) main: printStackTrace() java. lang.Exception: thrown from f() at Rethrowing.f(Rethrowing .java: 7) at Rethrowing.g(Rethrowing .java: 11) at Rethrowing.main(Rethrowing .java: 29) originating the... exception in f() Inside h(),e.printStackTrace() java. lang.Exception: thrown from f() at Rethrowing.f(Rethrowing .java: 7) at Rethrowing.h(Rethrowing .java: 20) at Rethrowing.main(Rethrowing .java: 35) main: printStackTrace() java. lang.Exception: thrown from f() at Rethrowing.h(Rethrowing .java: 24) at Rethrowing.main(Rethrowing .java: 35) *///:~ The line where fillInStackTrace( ) is called becomes the new point of... try { print("Point 1"); if(i == 1) return; print("Point 2"); if(i == 2) return; print("Point 3"); if(i == 3) return; print("End"); return; } finally { print("Performing cleanup"); } } public static void main(String[] args) { for(int i = 1; i . LoggingExceptions.main(LoggingExceptions .java: 19) Caught LoggingException Aug 30, 2005 4: 02:31 PM LoggingException <init> SEVERE: LoggingException at LoggingExceptions.main(LoggingExceptions .java: 24) . library, but I think you’ll find yourself rapidly acquiring and using the classes in this library. Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated. about the containers in java. util (in particular, in the Containers in Depth chapter), you’ll see that there are more issues than just a slightly odd inheritance structure. Container libraries

Ngày đăng: 14/08/2014, 00:21

Mục lục

  • Thinking in Java

  • Content

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan