96dd155e2c
2005-02-17 Michael Koch <konqueror@gmx.de> * gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java, gnu/java/awt/peer/gtk/GdkFontPeer.java, gnu/java/awt/peer/gtk/GdkGlyphVector.java, gnu/java/awt/peer/gtk/GdkGraphics.java, gnu/java/awt/peer/gtk/GdkGraphics2D.java, gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java, gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java, gnu/java/awt/peer/gtk/GdkPixbufDecoder.java, gnu/java/awt/peer/gtk/GdkRobotPeer.java, gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java, gnu/java/awt/peer/gtk/GdkTextLayout.java, gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java, gnu/java/awt/peer/gtk/GtkChoicePeer.java, gnu/java/awt/peer/gtk/GtkClipboard.java, gnu/java/awt/peer/gtk/GtkComponentPeer.java, gnu/java/awt/peer/gtk/GtkFileDialogPeer.java, gnu/java/awt/peer/gtk/GtkFontPeer.java, gnu/java/awt/peer/gtk/GtkLabelPeer.java, gnu/java/awt/peer/gtk/GtkMenuBarPeer.java, gnu/java/awt/peer/gtk/GtkMenuItemPeer.java, gnu/java/awt/peer/gtk/GtkMenuPeer.java, gnu/java/awt/peer/gtk/GtkScrollPanePeer.java, gnu/java/awt/peer/gtk/GtkScrollbarPeer.java, gnu/java/awt/peer/gtk/GtkToolkit.java, gnu/java/awt/peer/gtk/GtkWindowPeer.java, java/applet/Applet.java, java/awt/AWTError.java, java/awt/AWTEvent.java, java/awt/AWTEventMulticaster.java, java/awt/AWTException.java, java/awt/AWTKeyStroke.java, java/awt/AWTPermission.java, java/awt/ActiveEvent.java, java/awt/Adjustable.java, java/awt/AlphaComposite.java, java/awt/AttributeValue.java, java/awt/BorderLayout.java, java/awt/BufferCapabilities.java, java/awt/Button.java, java/awt/Canvas.java, java/awt/CheckboxGroup.java, java/awt/CheckboxMenuItem.java, java/awt/Color.java, java/awt/ColorPaintContext.java, java/awt/Component.java, java/awt/ComponentOrientation.java, java/awt/Composite.java, java/awt/CompositeContext.java, java/awt/Container.java, java/awt/ContainerOrderFocusTraversalPolicy.java, java/awt/DefaultFocusTraversalPolicy.java, java/awt/Dialog.java, java/awt/Dimension.java, java/awt/DisplayMode.java, java/awt/EventQueue.java, java/awt/FileDialog.java, java/awt/FontFormatException.java, java/awt/Graphics.java, java/awt/Graphics2D.java, java/awt/GraphicsConfigTemplate.java, java/awt/GraphicsConfiguration.java, java/awt/GraphicsDevice.java, java/awt/GridBagLayout.java, java/awt/GridBagLayoutInfo.java, java/awt/GridLayout.java, java/awt/HeadlessException.java, java/awt/IllegalComponentStateException.java, java/awt/Image.java, java/awt/Insets.java, java/awt/ItemSelectable.java, java/awt/JobAttributes.java, java/awt/KeyEventDispatcher.java, java/awt/KeyEventPostProcessor.java, java/awt/KeyboardFocusManager.java, java/awt/Label.java, java/awt/LayoutManager.java, java/awt/MenuBar.java, java/awt/MenuComponent.java, java/awt/MenuContainer.java, java/awt/PageAttributes.java, java/awt/Paint.java, java/awt/PaintContext.java, java/awt/Panel.java, java/awt/Point.java, java/awt/Polygon.java, java/awt/PrintGraphics.java, java/awt/PrintJob.java, java/awt/Rectangle.java, java/awt/RenderingHints.java, java/awt/Shape.java, java/awt/Stroke.java, java/awt/SystemColor.java, java/awt/Toolkit.java, java/awt/Transparency.java, java/awt/Window.java, java/awt/color/CMMException.java, java/awt/color/ColorSpace.java, java/awt/color/ICC_ColorSpace.java, java/awt/color/ICC_Profile.java, java/awt/color/ProfileDataException.java, java/awt/datatransfer/FlavorTable.java, java/awt/datatransfer/MimeTypeParseException.java, java/awt/datatransfer/Transferable.java, java/awt/datatransfer/UnsupportedFlavorException.java, java/awt/dnd/Autoscroll.java, java/awt/dnd/DnDConstants.java, java/awt/dnd/DragGestureListener.java, java/awt/dnd/DragSourceAdapter.java, java/awt/dnd/DragSourceDropEvent.java, java/awt/dnd/DragSourceListener.java, java/awt/dnd/DragSourceMotionListener.java, java/awt/dnd/DropTargetAdapter.java, java/awt/dnd/DropTargetContext.java, java/awt/dnd/DropTargetListener.java, java/awt/dnd/InvalidDnDOperationException.java, java/awt/dnd/MouseDragGestureRecognizer.java, java/awt/dnd/peer/DropTargetContextPeer.java, java/awt/event/AWTEventListener.java, java/awt/event/AWTEventListenerProxy.java, java/awt/event/ActionEvent.java, java/awt/event/AdjustmentEvent.java, java/awt/event/AdjustmentListener.java, java/awt/event/ComponentAdapter.java, java/awt/event/ComponentEvent.java, java/awt/event/ComponentListener.java, java/awt/event/ContainerAdapter.java, java/awt/event/ContainerEvent.java, java/awt/event/ContainerListener.java, java/awt/event/FocusAdapter.java, java/awt/event/FocusEvent.java, java/awt/event/FocusListener.java, java/awt/event/InputEvent.java, java/awt/event/InputMethodEvent.java, java/awt/event/InputMethodListener.java, java/awt/event/InvocationEvent.java, java/awt/event/ItemEvent.java, java/awt/event/ItemListener.java, java/awt/event/KeyAdapter.java, java/awt/event/KeyEvent.java, java/awt/event/KeyListener.java, java/awt/event/MouseAdapter.java, java/awt/event/MouseEvent.java, java/awt/event/MouseListener.java, java/awt/event/MouseMotionAdapter.java, java/awt/event/MouseMotionListener.java, java/awt/event/MouseWheelEvent.java, java/awt/event/MouseWheelListener.java, java/awt/event/PaintEvent.java, java/awt/event/TextEvent.java, java/awt/event/TextListener.java, java/awt/event/WindowAdapter.java, java/awt/event/WindowEvent.java, java/awt/event/WindowFocusListener.java, java/awt/event/WindowListener.java, java/awt/event/WindowStateListener.java, java/awt/font/TextHitInfo.java, java/awt/geom/CubicCurve2D.java, java/awt/geom/Dimension2D.java, java/awt/geom/Ellipse2D.java, java/awt/geom/IllegalPathStateException.java, java/awt/geom/Line2D.java, java/awt/geom/NoninvertibleTransformException.java, java/awt/geom/PathIterator.java, java/awt/geom/Point2D.java, java/awt/geom/QuadCurve2D.java, java/awt/geom/RectangularShape.java, java/awt/geom/RoundRectangle2D.java, java/awt/im/InputContext.java, java/awt/im/InputMethodHighlight.java, java/awt/im/InputMethodRequests.java, java/awt/im/InputSubset.java, java/awt/im/spi/InputMethod.java, java/awt/im/spi/InputMethodDescriptor.java, java/awt/image/BandCombineOp.java, java/awt/image/BandedSampleModel.java, java/awt/image/ByteLookupTable.java, java/awt/image/ComponentSampleModel.java, java/awt/image/DataBuffer.java, java/awt/image/DataBufferByte.java, java/awt/image/DataBufferDouble.java, java/awt/image/DataBufferFloat.java, java/awt/image/DataBufferInt.java, java/awt/image/DataBufferShort.java, java/awt/image/DataBufferUShort.java, java/awt/image/ImagingOpException.java, java/awt/image/Kernel.java, java/awt/image/LookupTable.java, java/awt/image/MultiPixelPackedSampleModel.java, java/awt/image/PackedColorModel.java, java/awt/image/PixelInterleavedSampleModel.java, java/awt/image/RGBImageFilter.java, java/awt/image/Raster.java, java/awt/image/RasterFormatException.java, java/awt/image/SampleModel.java, java/awt/image/ShortLookupTable.java, java/awt/image/SinglePixelPackedSampleModel.java, java/awt/image/WritableRaster.java, java/awt/print/PrinterAbortException.java, java/awt/print/PrinterException.java, java/awt/print/PrinterIOException.java, java/beans/AppletInitializer.java, java/beans/ExceptionListener.java, java/beans/PropertyChangeEvent.java, java/beans/PropertyChangeListenerProxy.java, java/beans/PropertyChangeSupport.java, java/beans/PropertyDescriptor.java, java/beans/VetoableChangeListenerProxy.java, java/beans/VetoableChangeSupport.java, java/io/BufferedReader.java, java/io/ByteArrayInputStream.java, java/io/ByteArrayOutputStream.java, java/io/CharArrayReader.java, java/io/CharArrayWriter.java, java/io/CharConversionException.java, java/io/DataInput.java, java/io/DataInputStream.java, java/io/DataOutput.java, java/io/DataOutputStream.java, java/io/EOFException.java, java/io/FileInputStream.java, java/io/FileNotFoundException.java, java/io/FileOutputStream.java, java/io/FilenameFilter.java, java/io/FilterInputStream.java, java/io/FilterOutputStream.java, java/io/FilterReader.java, java/io/FilterWriter.java, java/io/IOException.java, java/io/InputStream.java, java/io/InterruptedIOException.java, java/io/LineNumberInputStream.java, java/io/LineNumberReader.java, java/io/ObjectInputStream.java, java/io/ObjectStreamException.java, java/io/OptionalDataException.java, java/io/OutputStream.java, java/io/OutputStreamWriter.java, java/io/PrintStream.java, java/io/PrintWriter.java, java/io/PushbackInputStream.java, java/io/PushbackReader.java, java/io/RandomAccessFile.java, java/io/Reader.java, java/io/SequenceInputStream.java, java/io/Serializable.java, java/io/StreamCorruptedException.java, java/io/StreamTokenizer.java, java/io/StringBufferInputStream.java, java/io/StringWriter.java, java/io/SyncFailedException.java, java/io/UTFDataFormatException.java, java/io/UnsupportedEncodingException.java, java/io/WriteAbortedException.java, java/io/Writer.java, java/lang/AbstractMethodError.java, java/lang/ArithmeticException.java, java/lang/ArrayIndexOutOfBoundsException.java, java/lang/ArrayStoreException.java, java/lang/AssertionError.java, java/lang/Boolean.java, java/lang/Byte.java, java/lang/Class.java, java/lang/ClassCastException.java, java/lang/ClassCircularityError.java, java/lang/ClassLoader.java, java/lang/ClassNotFoundException.java, java/lang/CloneNotSupportedException.java, java/lang/Cloneable.java, java/lang/Comparable.java, java/lang/Compiler.java, java/lang/Double.java, java/lang/Error.java, java/lang/Exception.java, java/lang/ExceptionInInitializerError.java, java/lang/Float.java, java/lang/IllegalAccessError.java, java/lang/IllegalAccessException.java, java/lang/IllegalArgumentException.java, java/lang/IllegalMonitorStateException.java, java/lang/IllegalStateException.java, java/lang/IllegalThreadStateException.java, java/lang/IncompatibleClassChangeError.java, java/lang/IndexOutOfBoundsException.java, java/lang/InheritableThreadLocal.java, java/lang/InstantiationError.java, java/lang/InstantiationException.java, java/lang/Integer.java, java/lang/InternalError.java, java/lang/InterruptedException.java, java/lang/LinkageError.java, java/lang/Long.java, java/lang/NegativeArraySizeException.java, java/lang/NoClassDefFoundError.java, java/lang/NoSuchFieldError.java, java/lang/NoSuchFieldException.java, java/lang/NoSuchMethodError.java, java/lang/NoSuchMethodException.java, java/lang/NullPointerException.java, java/lang/Number.java, java/lang/NumberFormatException.java, java/lang/OutOfMemoryError.java, java/lang/Process.java, java/lang/Runnable.java, java/lang/Runtime.java, java/lang/RuntimeException.java, java/lang/RuntimePermission.java, java/lang/SecurityException.java, java/lang/SecurityManager.java, java/lang/Short.java, java/lang/StackOverflowError.java, java/lang/StackTraceElement.java, java/lang/StringBuffer.java, java/lang/StringIndexOutOfBoundsException.java, java/lang/ThreadDeath.java, java/lang/ThreadGroup.java, java/lang/Throwable.java, java/lang/UnsatisfiedLinkError.java, java/lang/UnsupportedOperationException.java, java/lang/VerifyError.java, java/lang/VirtualMachineError.java, java/lang/reflect/AccessibleObject.java, java/lang/reflect/Array.java, java/lang/reflect/InvocationTargetException.java, java/lang/reflect/Member.java, java/lang/reflect/Modifier.java, java/lang/reflect/Proxy.java, java/lang/reflect/ReflectPermission.java, java/lang/reflect/UndeclaredThrowableException.java, java/math/BigInteger.java, java/net/NetworkInterface.java, java/nio/ByteBufferHelper.java, java/nio/ByteBufferImpl.java, java/nio/DirectByteBufferImpl.java, java/nio/DoubleBufferImpl.java, java/nio/FloatBufferImpl.java, java/nio/IntBufferImpl.java, java/nio/LongBufferImpl.java, java/nio/ShortBufferImpl.java, java/nio/channels/Channel.java, java/nio/channels/IllegalBlockingModeException.java, java/nio/charset/spi/CharsetProvider.java, java/security/AccessControlException.java, java/security/BasicPermission.java, java/security/DigestException.java, java/security/DigestInputStream.java, java/security/DigestOutputStream.java, java/security/GeneralSecurityException.java, java/security/Guard.java, java/security/GuardedObject.java, java/security/InvalidAlgorithmParameterException.java, java/security/InvalidKeyException.java, java/security/InvalidParameterException.java, java/security/Key.java, java/security/KeyException.java, java/security/KeyManagementException.java, java/security/KeyStoreException.java, java/security/MessageDigestSpi.java, java/security/NoSuchAlgorithmException.java, java/security/NoSuchProviderException.java, java/security/Permission.java, java/security/PermissionCollection.java, java/security/Permissions.java, java/security/Principal.java, java/security/PrivateKey.java, java/security/PrivilegedActionException.java, java/security/ProviderException.java, java/security/PublicKey.java, java/security/SecureRandom.java, java/security/SecureRandomSpi.java, java/security/SignatureException.java, java/security/SignatureSpi.java, java/security/SignedObject.java, java/security/Signer.java, java/security/UnrecoverableKeyException.java, java/security/UnresolvedPermission.java, java/security/acl/AclNotFoundException.java, java/security/acl/LastOwnerException.java, java/security/acl/NotOwnerException.java, java/security/cert/CertPath.java, java/security/cert/CertPathBuilderException.java, java/security/cert/CertPathValidatorException.java, java/security/cert/CertStoreException.java, java/text/BreakIterator.java, java/text/ChoiceFormat.java, java/text/CollationElementIterator.java, java/text/CollationKey.java, java/text/Collator.java, java/text/DateFormat.java, java/text/DateFormatSymbols.java, java/text/DecimalFormat.java, java/text/DecimalFormatSymbols.java, java/text/FieldPosition.java, java/text/Format.java, java/text/NumberFormat.java, java/text/ParseException.java, java/text/ParsePosition.java, java/text/StringCharacterIterator.java, java/util/AbstractCollection.java, java/util/AbstractList.java, java/util/AbstractMap.java, java/util/AbstractSequentialList.java, java/util/AbstractSet.java, java/util/ArrayList.java, java/util/Arrays.java, java/util/BitSet.java, java/util/Collection.java, java/util/Collections.java, java/util/Comparator.java, java/util/ConcurrentModificationException.java, java/util/Currency.java, java/util/Date.java, java/util/EmptyStackException.java, java/util/Enumeration.java, java/util/EventListener.java, java/util/EventListenerProxy.java, java/util/EventObject.java, java/util/HashMap.java, java/util/HashSet.java, java/util/Hashtable.java, java/util/IdentityHashMap.java, java/util/Iterator.java, java/util/LinkedHashSet.java, java/util/LinkedList.java, java/util/List.java, java/util/ListIterator.java, java/util/ListResourceBundle.java, java/util/Map.java, java/util/MissingResourceException.java, java/util/NoSuchElementException.java, java/util/Observable.java, java/util/Observer.java, java/util/Properties.java, java/util/PropertyPermissionCollection.java, java/util/RandomAccess.java, java/util/Set.java, java/util/SortedMap.java, java/util/SortedSet.java, java/util/Stack.java, java/util/StringTokenizer.java, java/util/TooManyListenersException.java, java/util/TreeMap.java, java/util/TreeSet.java, java/util/Vector.java, java/util/logging/FileHandler.java, java/util/logging/Level.java, java/util/prefs/BackingStoreException.java, java/util/prefs/InvalidPreferencesFormatException.java, java/util/prefs/Preferences.java, javax/accessibility/Accessible.java, javax/accessibility/AccessibleAction.java, javax/accessibility/AccessibleBundle.java, javax/accessibility/AccessibleComponent.java, javax/accessibility/AccessibleContext.java, javax/accessibility/AccessibleEditableText.java, javax/accessibility/AccessibleExtendedComponent.java, javax/accessibility/AccessibleExtendedTable.java, javax/accessibility/AccessibleHyperlink.java, javax/accessibility/AccessibleHypertext.java, javax/accessibility/AccessibleIcon.java, javax/accessibility/AccessibleKeyBinding.java, javax/accessibility/AccessibleRelation.java, javax/accessibility/AccessibleRelationSet.java, javax/accessibility/AccessibleResourceBundle.java, javax/accessibility/AccessibleRole.java, javax/accessibility/AccessibleSelection.java, javax/accessibility/AccessibleState.java, javax/accessibility/AccessibleStateSet.java, javax/accessibility/AccessibleTable.java, javax/accessibility/AccessibleTableModelChange.java, javax/accessibility/AccessibleText.java, javax/accessibility/AccessibleValue.java, javax/imageio/IIOException.java, javax/imageio/ImageIO.java, javax/imageio/spi/IIOServiceProvider.java, javax/imageio/spi/ImageInputStreamSpi.java, javax/imageio/spi/ImageOutputStreamSpi.java, javax/imageio/spi/ImageReaderWriterSpi.java, javax/imageio/spi/ImageTranscoderSpi.java, javax/imageio/spi/RegisterableService.java, javax/imageio/spi/ServiceRegistry.java, javax/imageio/stream/IIOByteBuffer.java, javax/imageio/stream/ImageInputStream.java, javax/imageio/stream/ImageOutputStream.java, javax/naming/Binding.java, javax/naming/CannotProceedException.java, javax/naming/CompositeName.java, javax/naming/CompoundName.java, javax/naming/LinkException.java, javax/naming/LinkRef.java, javax/naming/NameClassPair.java, javax/naming/Reference.java, javax/naming/ReferralException.java, javax/naming/directory/Attribute.java, javax/naming/directory/AttributeModificationException.java, javax/naming/directory/Attributes.java, javax/naming/directory/DirContext.java, javax/naming/directory/ModificationItem.java, javax/naming/directory/SearchControls.java, javax/naming/directory/SearchResult.java, javax/naming/event/EventContext.java, javax/naming/event/EventDirContext.java, javax/naming/event/NamespaceChangeListener.java, javax/naming/event/NamingExceptionEvent.java, javax/naming/event/NamingListener.java, javax/naming/event/ObjectChangeListener.java, javax/naming/ldap/Control.java, javax/naming/ldap/ExtendedResponse.java, javax/naming/ldap/HasControls.java, javax/naming/ldap/LdapContext.java, javax/naming/ldap/UnsolicitedNotification.java, javax/naming/ldap/UnsolicitedNotificationEvent.java, javax/naming/ldap/UnsolicitedNotificationListener.java, javax/naming/spi/DirectoryManager.java, javax/naming/spi/ResolveResult.java, javax/naming/spi/Resolver.java, javax/security/auth/callback/Callback.java, javax/security/auth/callback/CallbackHandler.java, javax/security/auth/callback/ChoiceCallback.java, javax/security/auth/callback/ConfirmationCallback.java, javax/security/auth/callback/LanguageCallback.java, javax/security/auth/callback/NameCallback.java, javax/security/auth/callback/PasswordCallback.java, javax/security/auth/callback/TextInputCallback.java, javax/security/auth/callback/TextOutputCallback.java, javax/security/auth/callback/UnsupportedCallbackException.java, javax/security/sasl/Sasl.java, javax/security/sasl/SaslServerFactory.java, javax/swing/DefaultBoundedRangeModel.java, javax/swing/JComponent.java, javax/swing/JList.java, javax/swing/JProgressBar.java, javax/swing/JRadioButton.java, javax/swing/JTextArea.java, javax/swing/JTextField.java, javax/swing/JToggleButton.java, javax/swing/JTree.java, javax/swing/SpinnerListModel.java, javax/swing/event/EventListenerList.java, javax/swing/text/JTextComponent.java, javax/swing/text/StringContent.java, javax/swing/text/Utilities.java, javax/swing/undo/UndoManager.java, javax/swing/undo/UndoableEditSupport.java, javax/transaction/HeuristicCommitException.java, javax/transaction/HeuristicMixedException.java, javax/transaction/HeuristicRollbackException.java, javax/transaction/InvalidTransactionException.java, javax/transaction/NotSupportedException.java, javax/transaction/RollbackException.java, javax/transaction/Status.java, javax/transaction/Synchronization.java, javax/transaction/SystemException.java, javax/transaction/Transaction.java, javax/transaction/TransactionManager.java, javax/transaction/TransactionRequiredException.java, javax/transaction/TransactionRolledbackException.java, javax/transaction/UserTransaction.java, javax/transaction/xa/XAException.java, javax/transaction/xa/XAResource.java, javax/transaction/xa/Xid.java, javax/xml/XMLConstants.java, javax/xml/datatype/DatatypeConfigurationException.java, javax/xml/datatype/DatatypeConstants.java, javax/xml/datatype/DatatypeFactory.java, javax/xml/datatype/Duration.java, javax/xml/datatype/XMLGregorianCalendar.java, javax/xml/namespace/NamespaceContext.java, javax/xml/namespace/QName.java, javax/xml/parsers/DocumentBuilder.java, javax/xml/parsers/DocumentBuilderFactory.java, javax/xml/parsers/FactoryConfigurationError.java, javax/xml/parsers/ParserConfigurationException.java, javax/xml/parsers/SAXParser.java, javax/xml/parsers/SAXParserFactory.java, javax/xml/transform/ErrorListener.java, javax/xml/transform/OutputKeys.java, javax/xml/transform/Result.java, javax/xml/transform/Source.java, javax/xml/transform/SourceLocator.java, javax/xml/transform/Templates.java, javax/xml/transform/Transformer.java, javax/xml/transform/TransformerConfigurationException.java, javax/xml/transform/TransformerException.java, javax/xml/transform/TransformerFactory.java, javax/xml/transform/TransformerFactoryConfigurationError.java, javax/xml/transform/URIResolver.java, javax/xml/transform/dom/DOMLocator.java, javax/xml/transform/dom/DOMResult.java, javax/xml/transform/dom/DOMSource.java, javax/xml/transform/sax/SAXResult.java, javax/xml/transform/sax/SAXSource.java, javax/xml/transform/sax/SAXTransformerFactory.java, javax/xml/transform/sax/TemplatesHandler.java, javax/xml/transform/sax/TransformerHandler.java, javax/xml/transform/stream/StreamResult.java, javax/xml/transform/stream/StreamSource.java, javax/xml/validation/Schema.java, javax/xml/validation/SchemaFactory.java, javax/xml/validation/TypeInfoProvider.java, javax/xml/validation/Validator.java, javax/xml/validation/ValidatorHandler.java, javax/xml/xpath/XPathConstants.java, javax/xml/xpath/XPathException.java, javax/xml/xpath/XPathExpression.java, javax/xml/xpath/XPathExpressionException.java, javax/xml/xpath/XPathFactory.java, javax/xml/xpath/XPathFactoryConfigurationException.java, javax/xml/xpath/XPathFunction.java, javax/xml/xpath/XPathFunctionException.java, javax/xml/xpath/XPathFunctionResolver.java: Fixed usage of @author tag, reworked import statements, removed CVS tags, changed the modifier order and fixed HTML usage in javadocs. From-SVN: r95152
5494 lines
169 KiB
Java
5494 lines
169 KiB
Java
/* Collections.java -- Utility class with methods to operate on collections
|
||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005
|
||
Free Software Foundation, Inc.
|
||
|
||
This file is part of GNU Classpath.
|
||
|
||
GNU Classpath is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2, or (at your option)
|
||
any later version.
|
||
|
||
GNU Classpath is distributed in the hope that it will be useful, but
|
||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||
02111-1307 USA.
|
||
|
||
Linking this library statically or dynamically with other modules is
|
||
making a combined work based on this library. Thus, the terms and
|
||
conditions of the GNU General Public License cover the whole
|
||
combination.
|
||
|
||
As a special exception, the copyright holders of this library give you
|
||
permission to link this library with independent modules to produce an
|
||
executable, regardless of the license terms of these independent
|
||
modules, and to copy and distribute the resulting executable under
|
||
terms of your choice, provided that you also meet, for each linked
|
||
independent module, the terms and conditions of the license of that
|
||
module. An independent module is a module which is not derived from
|
||
or based on this library. If you modify this library, you may extend
|
||
this exception to your version of the library, but you are not
|
||
obligated to do so. If you do not wish to do so, delete this
|
||
exception statement from your version. */
|
||
|
||
|
||
package java.util;
|
||
|
||
import java.io.Serializable;
|
||
|
||
/**
|
||
* Utility class consisting of static methods that operate on, or return
|
||
* Collections. Contains methods to sort, search, reverse, fill and shuffle
|
||
* Collections, methods to facilitate interoperability with legacy APIs that
|
||
* are unaware of collections, a method to return a list which consists of
|
||
* multiple copies of one element, and methods which "wrap" collections to give
|
||
* them extra properties, such as thread-safety and unmodifiability.
|
||
* <p>
|
||
*
|
||
* All methods which take a collection throw a {@link NullPointerException} if
|
||
* that collection is null. Algorithms which can change a collection may, but
|
||
* are not required, to throw the {@link UnsupportedOperationException} that
|
||
* the underlying collection would throw during an attempt at modification.
|
||
* For example,
|
||
* <code>Collections.singleton("").addAll(Collections.EMPTY_SET)</code>
|
||
* does not throw a exception, even though addAll is an unsupported operation
|
||
* on a singleton; the reason for this is that addAll did not attempt to
|
||
* modify the set.
|
||
*
|
||
* @author Original author unknown
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
* @see Collection
|
||
* @see Set
|
||
* @see List
|
||
* @see Map
|
||
* @see Arrays
|
||
* @since 1.2
|
||
* @status updated to 1.4
|
||
*/
|
||
public class Collections
|
||
{
|
||
/**
|
||
* Constant used to decide cutoff for when a non-RandomAccess list should
|
||
* be treated as sequential-access. Basically, quadratic behavior is
|
||
* acceptable for small lists when the overhead is so small in the first
|
||
* place. I arbitrarily set it to 16, so it may need some tuning.
|
||
*/
|
||
private static final int LARGE_LIST_SIZE = 16;
|
||
|
||
/**
|
||
* Determines if a list should be treated as a sequential-access one.
|
||
* Rather than the old method of JDK 1.3 of assuming only instanceof
|
||
* AbstractSequentialList should be sequential, this uses the new method
|
||
* of JDK 1.4 of assuming anything that does NOT implement RandomAccess
|
||
* and exceeds a large (unspecified) size should be sequential.
|
||
*
|
||
* @param l the list to check
|
||
* @return <code>true</code> if it should be treated as sequential-access
|
||
*/
|
||
private static boolean isSequential(List l)
|
||
{
|
||
return ! (l instanceof RandomAccess) && l.size() > LARGE_LIST_SIZE;
|
||
}
|
||
|
||
/**
|
||
* This class is non-instantiable.
|
||
*/
|
||
private Collections()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* An immutable, serializable, empty Set.
|
||
* @see Serializable
|
||
*/
|
||
public static final Set EMPTY_SET = new EmptySet();
|
||
|
||
/**
|
||
* The implementation of {@link #EMPTY_SET}. This class name is required
|
||
* for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class EmptySet extends AbstractSet
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1582296315990362920L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
EmptySet()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* The size: always 0!
|
||
* @return 0.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Returns an iterator that does not iterate.
|
||
* @return A non-iterating iterator.
|
||
*/
|
||
// This is really cheating! I think it's perfectly valid, though.
|
||
public Iterator iterator()
|
||
{
|
||
return EMPTY_LIST.iterator();
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractSet.
|
||
/**
|
||
* The empty set never contains anything.
|
||
* @param o The object to search for.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* This is true only if the given collection is also empty.
|
||
* @param c The collection of objects which are to be compared
|
||
* against the members of this set.
|
||
* @return <code>true</code> if c is empty.
|
||
*/
|
||
public boolean containsAll(Collection c)
|
||
{
|
||
return c.isEmpty();
|
||
}
|
||
|
||
/**
|
||
* Equal only if the other set is empty.
|
||
* @param o The object to compare with this set.
|
||
* @return <code>true</code> if o is an empty instance of <code>Set</code>.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return o instanceof Set && ((Set) o).isEmpty();
|
||
}
|
||
|
||
/**
|
||
* The hashcode is always 0.
|
||
* @return 0.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Always succeeds with a <code>false</code> result.
|
||
* @param o The object to remove.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean remove(Object o)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Always succeeds with a <code>false</code> result.
|
||
* @param c The collection of objects which should
|
||
* all be removed from this set.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean removeAll(Collection c)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Always succeeds with a <code>false</code> result.
|
||
* @param c The collection of objects which should
|
||
* all be retained within this set.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean retainAll(Collection c)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* The array is always empty.
|
||
* @return A new array with a size of 0.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return new Object[0];
|
||
}
|
||
|
||
/**
|
||
* We don't even need to use reflection!
|
||
* @param a An existing array, which can be empty.
|
||
* @return The original array with any existing
|
||
* initial element set to null.
|
||
*/
|
||
public Object[] toArray(Object[] a)
|
||
{
|
||
if (a.length > 0)
|
||
a[0] = null;
|
||
return a;
|
||
}
|
||
|
||
/**
|
||
* The string never changes.
|
||
*
|
||
* @return the string "[]".
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[]";
|
||
}
|
||
} // class EmptySet
|
||
|
||
/**
|
||
* An immutable, serializable, empty List, which implements RandomAccess.
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static final List EMPTY_LIST = new EmptyList();
|
||
|
||
/**
|
||
* The implementation of {@link #EMPTY_LIST}. This class name is required
|
||
* for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class EmptyList extends AbstractList
|
||
implements Serializable, RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 8842843931221139166L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
EmptyList()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* The size is always 0.
|
||
* @return 0.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* No matter the index, it is out of bounds. This
|
||
* method never returns, throwing an exception instead.
|
||
*
|
||
* @param index The index of the element to retrieve.
|
||
* @return the object at the specified index.
|
||
* @throws IndexOutofBoundsException as any given index
|
||
* is outside the bounds of an empty array.
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractList.
|
||
/**
|
||
* Never contains anything.
|
||
* @param o The object to search for.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* This is true only if the given collection is also empty.
|
||
* @param c The collection of objects, which should be compared
|
||
* against the members of this list.
|
||
* @return <code>true</code> if c is also empty.
|
||
*/
|
||
public boolean containsAll(Collection c)
|
||
{
|
||
return c.isEmpty();
|
||
}
|
||
|
||
/**
|
||
* Equal only if the other list is empty.
|
||
* @param o The object to compare against this list.
|
||
* @return <code>true</code> if o is also an empty instance of
|
||
* <code>List</code>.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return o instanceof List && ((List) o).isEmpty();
|
||
}
|
||
|
||
/**
|
||
* The hashcode is always 1.
|
||
* @return 1.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Returns -1.
|
||
* @param o The object to search for.
|
||
* @return -1.
|
||
*/
|
||
public int indexOf(Object o)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Returns -1.
|
||
* @param o The object to search for.
|
||
* @return -1.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Always succeeds with <code>false</code> result.
|
||
* @param o The object to remove.
|
||
* @return -1.
|
||
*/
|
||
public boolean remove(Object o)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Always succeeds with <code>false</code> result.
|
||
* @param c The collection of objects which should
|
||
* all be removed from this list.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean removeAll(Collection c)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Always succeeds with <code>false</code> result.
|
||
* @param c The collection of objects which should
|
||
* all be retained within this list.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean retainAll(Collection c)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* The array is always empty.
|
||
* @return A new array with a size of 0.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return new Object[0];
|
||
}
|
||
|
||
/**
|
||
* We don't even need to use reflection!
|
||
* @param a An existing array, which can be empty.
|
||
* @return The original array with any existing
|
||
* initial element set to null.
|
||
*/
|
||
public Object[] toArray(Object[] a)
|
||
{
|
||
if (a.length > 0)
|
||
a[0] = null;
|
||
return a;
|
||
}
|
||
|
||
/**
|
||
* The string never changes.
|
||
*
|
||
* @return the string "[]".
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[]";
|
||
}
|
||
} // class EmptyList
|
||
|
||
/**
|
||
* An immutable, serializable, empty Map.
|
||
* @see Serializable
|
||
*/
|
||
public static final Map EMPTY_MAP = new EmptyMap();
|
||
|
||
/**
|
||
* The implementation of {@link #EMPTY_MAP}. This class name is required
|
||
* for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class EmptyMap extends AbstractMap
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 6428348081105594320L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
EmptyMap()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* There are no entries.
|
||
* @return The empty set.
|
||
*/
|
||
public Set entrySet()
|
||
{
|
||
return EMPTY_SET;
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractMap.
|
||
/**
|
||
* No entries!
|
||
* @param key The key to search for.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean containsKey(Object key)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* No entries!
|
||
* @param value The value to search for.
|
||
* @return <code>false</code>.
|
||
*/
|
||
public boolean containsValue(Object value)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Equal to all empty maps.
|
||
* @param o The object o to compare against this map.
|
||
* @return <code>true</code> if o is also an empty instance of
|
||
* <code>Map</code>.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return o instanceof Map && ((Map) o).isEmpty();
|
||
}
|
||
|
||
/**
|
||
* No mappings, so this returns null.
|
||
* @param o The key of the object to retrieve.
|
||
* @return null.
|
||
*/
|
||
public Object get(Object o)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* The hashcode is always 0.
|
||
* @return 0.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* No entries.
|
||
* @return The empty set.
|
||
*/
|
||
public Set keySet()
|
||
{
|
||
return EMPTY_SET;
|
||
}
|
||
|
||
/**
|
||
* Remove always succeeds, with null result.
|
||
* @param o The key of the mapping to remove.
|
||
* @return null, as there is never a mapping for o.
|
||
*/
|
||
public Object remove(Object o)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Size is always 0.
|
||
* @return 0.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* No entries. Technically, EMPTY_SET, while more specific than a general
|
||
* Collection, will work. Besides, that's what the JDK uses!
|
||
* @return The empty set.
|
||
*/
|
||
public Collection values()
|
||
{
|
||
return EMPTY_SET;
|
||
}
|
||
|
||
/**
|
||
* The string never changes.
|
||
*
|
||
* @return the string "[]".
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[]";
|
||
}
|
||
} // class EmptyMap
|
||
|
||
|
||
/**
|
||
* Compare two objects with or without a Comparator. If c is null, uses the
|
||
* natural ordering. Slightly slower than doing it inline if the JVM isn't
|
||
* clever, but worth it for removing a duplicate of the search code.
|
||
* Note: This code is also used in Arrays (for sort as well as search).
|
||
*/
|
||
static final int compare(Object o1, Object o2, Comparator c)
|
||
{
|
||
return c == null ? ((Comparable) o1).compareTo(o2) : c.compare(o1, o2);
|
||
}
|
||
|
||
/**
|
||
* Perform a binary search of a List for a key, using the natural ordering of
|
||
* the elements. The list must be sorted (as by the sort() method) - if it is
|
||
* not, the behavior of this method is undefined, and may be an infinite
|
||
* loop. Further, the key must be comparable with every item in the list. If
|
||
* the list contains the key more than once, any one of them may be found.
|
||
* <p>
|
||
*
|
||
* This algorithm behaves in log(n) time for {@link RandomAccess} lists,
|
||
* and uses a linear search with O(n) link traversals and log(n) comparisons
|
||
* with {@link AbstractSequentialList} lists. Note: although the
|
||
* specification allows for an infinite loop if the list is unsorted, it will
|
||
* not happen in this (Classpath) implementation.
|
||
*
|
||
* @param l the list to search (must be sorted)
|
||
* @param key the value to search for
|
||
* @return the index at which the key was found, or -n-1 if it was not
|
||
* found, where n is the index of the first value higher than key or
|
||
* a.length if there is no such value
|
||
* @throws ClassCastException if key could not be compared with one of the
|
||
* elements of l
|
||
* @throws NullPointerException if a null element has compareTo called
|
||
* @see #sort(List)
|
||
*/
|
||
public static int binarySearch(List l, Object key)
|
||
{
|
||
return binarySearch(l, key, null);
|
||
}
|
||
|
||
/**
|
||
* Perform a binary search of a List for a key, using a supplied Comparator.
|
||
* The list must be sorted (as by the sort() method with the same Comparator)
|
||
* - if it is not, the behavior of this method is undefined, and may be an
|
||
* infinite loop. Further, the key must be comparable with every item in the
|
||
* list. If the list contains the key more than once, any one of them may be
|
||
* found. If the comparator is null, the elements' natural ordering is used.
|
||
* <p>
|
||
*
|
||
* This algorithm behaves in log(n) time for {@link RandomAccess} lists,
|
||
* and uses a linear search with O(n) link traversals and log(n) comparisons
|
||
* with {@link AbstractSequentialList} lists. Note: although the
|
||
* specification allows for an infinite loop if the list is unsorted, it will
|
||
* not happen in this (Classpath) implementation.
|
||
*
|
||
* @param l the list to search (must be sorted)
|
||
* @param key the value to search for
|
||
* @param c the comparator by which the list is sorted
|
||
* @return the index at which the key was found, or -n-1 if it was not
|
||
* found, where n is the index of the first value higher than key or
|
||
* a.length if there is no such value
|
||
* @throws ClassCastException if key could not be compared with one of the
|
||
* elements of l
|
||
* @throws NullPointerException if a null element is compared with natural
|
||
* ordering (only possible when c is null)
|
||
* @see #sort(List, Comparator)
|
||
*/
|
||
public static int binarySearch(List l, Object key, Comparator c)
|
||
{
|
||
int pos = 0;
|
||
int low = 0;
|
||
int hi = l.size() - 1;
|
||
|
||
// We use a linear search with log(n) comparisons using an iterator
|
||
// if the list is sequential-access.
|
||
if (isSequential(l))
|
||
{
|
||
ListIterator itr = l.listIterator();
|
||
int i = 0;
|
||
Object o = itr.next(); // Assumes list is not empty (see isSequential)
|
||
boolean forward = true;
|
||
while (low <= hi)
|
||
{
|
||
pos = (low + hi) >> 1;
|
||
if (i < pos)
|
||
{
|
||
if (!forward)
|
||
itr.next(); // Changing direction first.
|
||
for ( ; i != pos; i++, o = itr.next());
|
||
forward = true;
|
||
}
|
||
else
|
||
{
|
||
if (forward)
|
||
itr.previous(); // Changing direction first.
|
||
for ( ; i != pos; i--, o = itr.previous());
|
||
forward = false;
|
||
}
|
||
final int d = compare(key, o, c);
|
||
if (d == 0)
|
||
return pos;
|
||
else if (d < 0)
|
||
hi = pos - 1;
|
||
else
|
||
// This gets the insertion point right on the last loop
|
||
low = ++pos;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
while (low <= hi)
|
||
{
|
||
pos = (low + hi) >> 1;
|
||
final int d = compare(key, l.get(pos), c);
|
||
if (d == 0)
|
||
return pos;
|
||
else if (d < 0)
|
||
hi = pos - 1;
|
||
else
|
||
// This gets the insertion point right on the last loop
|
||
low = ++pos;
|
||
}
|
||
}
|
||
|
||
// If we failed to find it, we do the same whichever search we did.
|
||
return -pos - 1;
|
||
}
|
||
|
||
/**
|
||
* Copy one list to another. If the destination list is longer than the
|
||
* source list, the remaining elements are unaffected. This method runs in
|
||
* linear time.
|
||
*
|
||
* @param dest the destination list
|
||
* @param source the source list
|
||
* @throws IndexOutOfBoundsException if the destination list is shorter
|
||
* than the source list (the destination will be unmodified)
|
||
* @throws UnsupportedOperationException if dest.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void copy(List dest, List source)
|
||
{
|
||
int pos = source.size();
|
||
if (dest.size() < pos)
|
||
throw new IndexOutOfBoundsException("Source does not fit in dest");
|
||
|
||
Iterator i1 = source.iterator();
|
||
ListIterator i2 = dest.listIterator();
|
||
|
||
while (--pos >= 0)
|
||
{
|
||
i2.next();
|
||
i2.set(i1.next());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns an Enumeration over a collection. This allows interoperability
|
||
* with legacy APIs that require an Enumeration as input.
|
||
*
|
||
* @param c the Collection to iterate over
|
||
* @return an Enumeration backed by an Iterator over c
|
||
*/
|
||
public static Enumeration enumeration(Collection c)
|
||
{
|
||
final Iterator i = c.iterator();
|
||
return new Enumeration()
|
||
{
|
||
/**
|
||
* Returns <code>true</code> if there are more elements to
|
||
* be enumerated.
|
||
*
|
||
* @return The result of <code>hasNext()</code>
|
||
* called on the underlying iterator.
|
||
*/
|
||
public final boolean hasMoreElements()
|
||
{
|
||
return i.hasNext();
|
||
}
|
||
|
||
/**
|
||
* Returns the next element to be enumerated.
|
||
*
|
||
* @return The result of <code>next()</code>
|
||
* called on the underlying iterator.
|
||
*/
|
||
public final Object nextElement()
|
||
{
|
||
return i.next();
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Replace every element of a list with a given value. This method runs in
|
||
* linear time.
|
||
*
|
||
* @param l the list to fill.
|
||
* @param val the object to vill the list with.
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation.
|
||
*/
|
||
public static void fill(List l, Object val)
|
||
{
|
||
ListIterator itr = l.listIterator();
|
||
for (int i = l.size() - 1; i >= 0; --i)
|
||
{
|
||
itr.next();
|
||
itr.set(val);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the starting index where the specified sublist first occurs
|
||
* in a larger list, or -1 if there is no matching position. If
|
||
* <code>target.size() > source.size()</code>, this returns -1,
|
||
* otherwise this implementation uses brute force, checking for
|
||
* <code>source.sublist(i, i + target.size()).equals(target)</code>
|
||
* for all possible i.
|
||
*
|
||
* @param source the list to search
|
||
* @param target the sublist to search for
|
||
* @return the index where found, or -1
|
||
* @since 1.4
|
||
*/
|
||
public static int indexOfSubList(List source, List target)
|
||
{
|
||
int ssize = source.size();
|
||
for (int i = 0, j = target.size(); j <= ssize; i++, j++)
|
||
if (source.subList(i, j).equals(target))
|
||
return i;
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Returns the starting index where the specified sublist last occurs
|
||
* in a larger list, or -1 if there is no matching position. If
|
||
* <code>target.size() > source.size()</code>, this returns -1,
|
||
* otherwise this implementation uses brute force, checking for
|
||
* <code>source.sublist(i, i + target.size()).equals(target)</code>
|
||
* for all possible i.
|
||
*
|
||
* @param source the list to search
|
||
* @param target the sublist to search for
|
||
* @return the index where found, or -1
|
||
* @since 1.4
|
||
*/
|
||
public static int lastIndexOfSubList(List source, List target)
|
||
{
|
||
int ssize = source.size();
|
||
for (int i = ssize - target.size(), j = ssize; i >= 0; i--, j--)
|
||
if (source.subList(i, j).equals(target))
|
||
return i;
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Returns an ArrayList holding the elements visited by a given
|
||
* Enumeration. This method exists for interoperability between legacy
|
||
* APIs and the new Collection API.
|
||
*
|
||
* @param e the enumeration to put in a list
|
||
* @return a list containing the enumeration elements
|
||
* @see ArrayList
|
||
* @since 1.4
|
||
*/
|
||
public static ArrayList list(Enumeration e)
|
||
{
|
||
ArrayList l = new ArrayList();
|
||
while (e.hasMoreElements())
|
||
l.add(e.nextElement());
|
||
return l;
|
||
}
|
||
|
||
/**
|
||
* Find the maximum element in a Collection, according to the natural
|
||
* ordering of the elements. This implementation iterates over the
|
||
* Collection, so it works in linear time.
|
||
*
|
||
* @param c the Collection to find the maximum element of
|
||
* @return the maximum element of c
|
||
* @exception NoSuchElementException if c is empty
|
||
* @exception ClassCastException if elements in c are not mutually comparable
|
||
* @exception NullPointerException if null.compareTo is called
|
||
*/
|
||
public static Object max(Collection c)
|
||
{
|
||
return max(c, null);
|
||
}
|
||
|
||
/**
|
||
* Find the maximum element in a Collection, according to a specified
|
||
* Comparator. This implementation iterates over the Collection, so it
|
||
* works in linear time.
|
||
*
|
||
* @param c the Collection to find the maximum element of
|
||
* @param order the Comparator to order the elements by, or null for natural
|
||
* ordering
|
||
* @return the maximum element of c
|
||
* @throws NoSuchElementException if c is empty
|
||
* @throws ClassCastException if elements in c are not mutually comparable
|
||
* @throws NullPointerException if null is compared by natural ordering
|
||
* (only possible when order is null)
|
||
*/
|
||
public static Object max(Collection c, Comparator order)
|
||
{
|
||
Iterator itr = c.iterator();
|
||
Object max = itr.next(); // throws NoSuchElementException
|
||
int csize = c.size();
|
||
for (int i = 1; i < csize; i++)
|
||
{
|
||
Object o = itr.next();
|
||
if (compare(max, o, order) < 0)
|
||
max = o;
|
||
}
|
||
return max;
|
||
}
|
||
|
||
/**
|
||
* Find the minimum element in a Collection, according to the natural
|
||
* ordering of the elements. This implementation iterates over the
|
||
* Collection, so it works in linear time.
|
||
*
|
||
* @param c the Collection to find the minimum element of
|
||
* @return the minimum element of c
|
||
* @throws NoSuchElementException if c is empty
|
||
* @throws ClassCastException if elements in c are not mutually comparable
|
||
* @throws NullPointerException if null.compareTo is called
|
||
*/
|
||
public static Object min(Collection c)
|
||
{
|
||
return min(c, null);
|
||
}
|
||
|
||
/**
|
||
* Find the minimum element in a Collection, according to a specified
|
||
* Comparator. This implementation iterates over the Collection, so it
|
||
* works in linear time.
|
||
*
|
||
* @param c the Collection to find the minimum element of
|
||
* @param order the Comparator to order the elements by, or null for natural
|
||
* ordering
|
||
* @return the minimum element of c
|
||
* @throws NoSuchElementException if c is empty
|
||
* @throws ClassCastException if elements in c are not mutually comparable
|
||
* @throws NullPointerException if null is compared by natural ordering
|
||
* (only possible when order is null)
|
||
*/
|
||
public static Object min(Collection c, Comparator order)
|
||
{
|
||
Iterator itr = c.iterator();
|
||
Object min = itr.next(); // throws NoSuchElementExcception
|
||
int csize = c.size();
|
||
for (int i = 1; i < csize; i++)
|
||
{
|
||
Object o = itr.next();
|
||
if (compare(min, o, order) > 0)
|
||
min = o;
|
||
}
|
||
return min;
|
||
}
|
||
|
||
/**
|
||
* Creates an immutable list consisting of the same object repeated n times.
|
||
* The returned object is tiny, consisting of only a single reference to the
|
||
* object and a count of the number of elements. It is Serializable, and
|
||
* implements RandomAccess. You can use it in tandem with List.addAll for
|
||
* fast list construction.
|
||
*
|
||
* @param n the number of times to repeat the object
|
||
* @param o the object to repeat
|
||
* @return a List consisting of n copies of o
|
||
* @throws IllegalArgumentException if n < 0
|
||
* @see List#addAll(Collection)
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static List nCopies(final int n, final Object o)
|
||
{
|
||
return new CopiesList(n, o);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #nCopies(int, Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class CopiesList extends AbstractList
|
||
implements Serializable, RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 2739099268398711800L;
|
||
|
||
/**
|
||
* The count of elements in this list.
|
||
* @serial the list size
|
||
*/
|
||
private final int n;
|
||
|
||
/**
|
||
* The repeated list element.
|
||
* @serial the list contents
|
||
*/
|
||
private final Object element;
|
||
|
||
/**
|
||
* Constructs the list.
|
||
*
|
||
* @param n the count
|
||
* @param o the object
|
||
* @throws IllegalArgumentException if n < 0
|
||
*/
|
||
CopiesList(int n, Object o)
|
||
{
|
||
if (n < 0)
|
||
throw new IllegalArgumentException();
|
||
this.n = n;
|
||
element = o;
|
||
}
|
||
|
||
/**
|
||
* The size is fixed.
|
||
* @return The size of the list.
|
||
*/
|
||
public int size()
|
||
{
|
||
return n;
|
||
}
|
||
|
||
/**
|
||
* The same element is returned.
|
||
* @param index The index of the element to be returned (irrelevant
|
||
* as the list contains only copies of <code>element</code>).
|
||
* @return The element used by this list.
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
if (index < 0 || index >= n)
|
||
throw new IndexOutOfBoundsException();
|
||
return element;
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractList.
|
||
/**
|
||
* This list only contains one element.
|
||
* @param o The object to search for.
|
||
* @return <code>true</code> if o is the element used by this list.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return n > 0 && equals(o, element);
|
||
}
|
||
|
||
/**
|
||
* The index is either 0 or -1.
|
||
* @param o The object to find the index of.
|
||
* @return 0 if <code>o == element</code>, -1 if not.
|
||
*/
|
||
public int indexOf(Object o)
|
||
{
|
||
return (n > 0 && equals(o, element)) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* The index is either n-1 or -1.
|
||
* @param o The object to find the last index of.
|
||
* @return The last index in the list if <code>o == element</code>,
|
||
* -1 if not.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return equals(o, element) ? n - 1 : -1;
|
||
}
|
||
|
||
/**
|
||
* A subList is just another CopiesList.
|
||
* @param from The starting bound of the sublist.
|
||
* @param to The ending bound of the sublist.
|
||
* @return A list of copies containing <code>from - to</code>
|
||
* elements, all of which are equal to the element
|
||
* used by this list.
|
||
*/
|
||
public List subList(int from, int to)
|
||
{
|
||
if (from < 0 || to > n)
|
||
throw new IndexOutOfBoundsException();
|
||
return new CopiesList(to - from, element);
|
||
}
|
||
|
||
/**
|
||
* The array is easy.
|
||
* @return An array of size n filled with copies of
|
||
* the element used by this list.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
Object[] a = new Object[n];
|
||
Arrays.fill(a, element);
|
||
return a;
|
||
}
|
||
|
||
/**
|
||
* The string is easy to generate.
|
||
* @return A string representation of the list.
|
||
*/
|
||
public String toString()
|
||
{
|
||
StringBuffer r = new StringBuffer("{");
|
||
for (int i = n - 1; --i > 0; )
|
||
r.append(element).append(", ");
|
||
r.append(element).append("}");
|
||
return r.toString();
|
||
}
|
||
} // class CopiesList
|
||
|
||
/**
|
||
* Replace all instances of one object with another in the specified list.
|
||
* The list does not change size. An element e is replaced if
|
||
* <code>oldval == null ? e == null : oldval.equals(e)</code>.
|
||
*
|
||
* @param list the list to iterate over
|
||
* @param oldval the element to replace
|
||
* @param newval the new value for the element
|
||
* @return <code>true</code> if a replacement occurred.
|
||
* @throws UnsupportedOperationException if the list iterator does not allow
|
||
* for the set operation
|
||
* @throws ClassCastException if newval is of a type which cannot be added
|
||
* to the list
|
||
* @throws IllegalArgumentException if some other aspect of newval stops
|
||
* it being added to the list
|
||
* @since 1.4
|
||
*/
|
||
public static boolean replaceAll(List list, Object oldval, Object newval)
|
||
{
|
||
ListIterator itr = list.listIterator();
|
||
boolean replace_occured = false;
|
||
for (int i = list.size(); --i >= 0; )
|
||
if (AbstractCollection.equals(oldval, itr.next()))
|
||
{
|
||
itr.set(newval);
|
||
replace_occured = true;
|
||
}
|
||
return replace_occured;
|
||
}
|
||
|
||
/**
|
||
* Reverse a given list. This method works in linear time.
|
||
*
|
||
* @param l the list to reverse
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void reverse(List l)
|
||
{
|
||
ListIterator i1 = l.listIterator();
|
||
int pos1 = 1;
|
||
int pos2 = l.size();
|
||
ListIterator i2 = l.listIterator(pos2);
|
||
while (pos1 < pos2)
|
||
{
|
||
Object o = i1.next();
|
||
i1.set(i2.previous());
|
||
i2.set(o);
|
||
++pos1;
|
||
--pos2;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get a comparator that implements the reverse of natural ordering. In
|
||
* other words, this sorts Comparable objects opposite of how their
|
||
* compareTo method would sort. This makes it easy to sort into reverse
|
||
* order, by simply passing Collections.reverseOrder() to the sort method.
|
||
* The return value of this method is Serializable.
|
||
*
|
||
* @return a comparator that imposes reverse natural ordering
|
||
* @see Comparable
|
||
* @see Serializable
|
||
*/
|
||
public static Comparator reverseOrder()
|
||
{
|
||
return rcInstance;
|
||
}
|
||
|
||
/**
|
||
* The object for {@link #reverseOrder()}.
|
||
*/
|
||
private static final ReverseComparator rcInstance = new ReverseComparator();
|
||
|
||
/**
|
||
* The implementation of {@link #reverseOrder()}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class ReverseComparator
|
||
implements Comparator, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 7207038068494060240L;
|
||
|
||
/**
|
||
* A private constructor adds overhead.
|
||
*/
|
||
ReverseComparator()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* Compare two objects in reverse natural order.
|
||
*
|
||
* @param a the first object
|
||
* @param b the second object
|
||
* @return <, ==, or > 0 according to b.compareTo(a)
|
||
*/
|
||
public int compare(Object a, Object b)
|
||
{
|
||
return ((Comparable) b).compareTo(a);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Rotate the elements in a list by a specified distance. After calling this
|
||
* method, the element now at index <code>i</code> was formerly at index
|
||
* <code>(i - distance) mod list.size()</code>. The list size is unchanged.
|
||
* <p>
|
||
*
|
||
* For example, suppose a list contains <code>[t, a, n, k, s]</code>. After
|
||
* either <code>Collections.rotate(l, 4)</code> or
|
||
* <code>Collections.rotate(l, -1)</code>, the new contents are
|
||
* <code>[s, t, a, n, k]</code>. This can be applied to sublists to rotate
|
||
* just a portion of the list. For example, to move element <code>a</code>
|
||
* forward two positions in the original example, use
|
||
* <code>Collections.rotate(l.subList(1, 3+1), -1)</code>, which will
|
||
* result in <code>[t, n, k, a, s]</code>.
|
||
* <p>
|
||
*
|
||
* If the list is small or implements {@link RandomAccess}, the
|
||
* implementation exchanges the first element to its destination, then the
|
||
* displaced element, and so on until a circuit has been completed. The
|
||
* process is repeated if needed on the second element, and so forth, until
|
||
* all elements have been swapped. For large non-random lists, the
|
||
* implementation breaks the list into two sublists at index
|
||
* <code>-distance mod size</code>, calls {@link #reverse(List)} on the
|
||
* pieces, then reverses the overall list.
|
||
*
|
||
* @param list the list to rotate
|
||
* @param distance the distance to rotate by; unrestricted in value
|
||
* @throws UnsupportedOperationException if the list does not support set
|
||
* @since 1.4
|
||
*/
|
||
public static void rotate(List list, int distance)
|
||
{
|
||
int size = list.size();
|
||
if (size == 0)
|
||
return;
|
||
distance %= size;
|
||
if (distance == 0)
|
||
return;
|
||
if (distance < 0)
|
||
distance += size;
|
||
|
||
if (isSequential(list))
|
||
{
|
||
reverse(list);
|
||
reverse(list.subList(0, distance));
|
||
reverse(list.subList(distance, size));
|
||
}
|
||
else
|
||
{
|
||
// Determine the least common multiple of distance and size, as there
|
||
// are (distance / LCM) loops to cycle through.
|
||
int a = size;
|
||
int lcm = distance;
|
||
int b = a % lcm;
|
||
while (b != 0)
|
||
{
|
||
a = lcm;
|
||
lcm = b;
|
||
b = a % lcm;
|
||
}
|
||
|
||
// Now, make the swaps. We must take the remainder every time through
|
||
// the inner loop so that we don't overflow i to negative values.
|
||
while (--lcm >= 0)
|
||
{
|
||
Object o = list.get(lcm);
|
||
for (int i = lcm + distance; i != lcm; i = (i + distance) % size)
|
||
o = list.set(i, o);
|
||
list.set(lcm, o);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Shuffle a list according to a default source of randomness. The algorithm
|
||
* used iterates backwards over the list, swapping each element with an
|
||
* element randomly selected from the elements in positions less than or
|
||
* equal to it (using r.nextInt(int)).
|
||
* <p>
|
||
*
|
||
* This algorithm would result in a perfectly fair shuffle (that is, each
|
||
* element would have an equal chance of ending up in any position) if r were
|
||
* a perfect source of randomness. In practice the results are merely very
|
||
* close to perfect.
|
||
* <p>
|
||
*
|
||
* This method operates in linear time. To do this on large lists which do
|
||
* not implement {@link RandomAccess}, a temporary array is used to acheive
|
||
* this speed, since it would be quadratic access otherwise.
|
||
*
|
||
* @param l the list to shuffle
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void shuffle(List l)
|
||
{
|
||
if (defaultRandom == null)
|
||
{
|
||
synchronized (Collections.class)
|
||
{
|
||
if (defaultRandom == null)
|
||
defaultRandom = new Random();
|
||
}
|
||
}
|
||
shuffle(l, defaultRandom);
|
||
}
|
||
|
||
/**
|
||
* Cache a single Random object for use by shuffle(List). This improves
|
||
* performance as well as ensuring that sequential calls to shuffle() will
|
||
* not result in the same shuffle order occurring: the resolution of
|
||
* System.currentTimeMillis() is not sufficient to guarantee a unique seed.
|
||
*/
|
||
private static Random defaultRandom = null;
|
||
|
||
/**
|
||
* Shuffle a list according to a given source of randomness. The algorithm
|
||
* used iterates backwards over the list, swapping each element with an
|
||
* element randomly selected from the elements in positions less than or
|
||
* equal to it (using r.nextInt(int)).
|
||
* <p>
|
||
*
|
||
* This algorithm would result in a perfectly fair shuffle (that is, each
|
||
* element would have an equal chance of ending up in any position) if r were
|
||
* a perfect source of randomness. In practise (eg if r = new Random()) the
|
||
* results are merely very close to perfect.
|
||
* <p>
|
||
*
|
||
* This method operates in linear time. To do this on large lists which do
|
||
* not implement {@link RandomAccess}, a temporary array is used to acheive
|
||
* this speed, since it would be quadratic access otherwise.
|
||
*
|
||
* @param l the list to shuffle
|
||
* @param r the source of randomness to use for the shuffle
|
||
* @throws UnsupportedOperationException if l.listIterator() does not
|
||
* support the set operation
|
||
*/
|
||
public static void shuffle(List l, Random r)
|
||
{
|
||
int lsize = l.size();
|
||
ListIterator i = l.listIterator(lsize);
|
||
boolean sequential = isSequential(l);
|
||
Object[] a = null; // stores a copy of the list for the sequential case
|
||
|
||
if (sequential)
|
||
a = l.toArray();
|
||
|
||
for (int pos = lsize - 1; pos > 0; --pos)
|
||
{
|
||
// Obtain a random position to swap with. pos + 1 is used so that the
|
||
// range of the random number includes the current position.
|
||
int swap = r.nextInt(pos + 1);
|
||
|
||
// Swap the desired element.
|
||
Object o;
|
||
if (sequential)
|
||
{
|
||
o = a[swap];
|
||
a[swap] = i.previous();
|
||
}
|
||
else
|
||
o = l.set(swap, i.previous());
|
||
|
||
i.set(o);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Obtain an immutable Set consisting of a single element. The return value
|
||
* of this method is Serializable.
|
||
*
|
||
* @param o the single element
|
||
* @return an immutable Set containing only o
|
||
* @see Serializable
|
||
*/
|
||
public static Set singleton(Object o)
|
||
{
|
||
return new SingletonSet(o);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #singleton(Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SingletonSet extends AbstractSet
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 3193687207550431679L;
|
||
|
||
|
||
/**
|
||
* The single element; package visible for use in nested class.
|
||
* @serial the singleton
|
||
*/
|
||
final Object element;
|
||
|
||
/**
|
||
* Construct a singleton.
|
||
* @param o the element
|
||
*/
|
||
SingletonSet(Object o)
|
||
{
|
||
element = o;
|
||
}
|
||
|
||
/**
|
||
* The size: always 1!
|
||
* @return 1.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Returns an iterator over the lone element.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
return new Iterator()
|
||
{
|
||
/**
|
||
* Flag to indicate whether or not the element has
|
||
* been retrieved.
|
||
*/
|
||
private boolean hasNext = true;
|
||
|
||
/**
|
||
* Returns <code>true</code> if elements still remain to be
|
||
* iterated through.
|
||
*
|
||
* @return <code>true</code> if the element has not yet been returned.
|
||
*/
|
||
public boolean hasNext()
|
||
{
|
||
return hasNext;
|
||
}
|
||
|
||
/**
|
||
* Returns the element.
|
||
*
|
||
* @return The element used by this singleton.
|
||
* @throws NoSuchElementException if the object
|
||
* has already been retrieved.
|
||
*/
|
||
public Object next()
|
||
{
|
||
if (hasNext)
|
||
{
|
||
hasNext = false;
|
||
return element;
|
||
}
|
||
else
|
||
throw new NoSuchElementException();
|
||
}
|
||
|
||
/**
|
||
* Removes the element from the singleton.
|
||
* As this set is immutable, this will always
|
||
* throw an exception.
|
||
*
|
||
* @throws UnsupportedOperationException as the
|
||
* singleton set doesn't support
|
||
* <code>remove()</code>.
|
||
*/
|
||
public void remove()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
};
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractSet.
|
||
/**
|
||
* The set only contains one element.
|
||
*
|
||
* @param o The object to search for.
|
||
* @return <code>true</code> if o == the element of the singleton.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return equals(o, element);
|
||
}
|
||
|
||
/**
|
||
* This is true if the other collection only contains the element.
|
||
*
|
||
* @param c A collection to compare against this singleton.
|
||
* @return <code>true</code> if c only contains either no elements or
|
||
* elements equal to the element in this singleton.
|
||
*/
|
||
public boolean containsAll(Collection c)
|
||
{
|
||
Iterator i = c.iterator();
|
||
int pos = c.size();
|
||
while (--pos >= 0)
|
||
if (! equals(i.next(), element))
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* The hash is just that of the element.
|
||
*
|
||
* @return The hashcode of the element.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return hashCode(element);
|
||
}
|
||
|
||
/**
|
||
* Returning an array is simple.
|
||
*
|
||
* @return An array containing the element.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return new Object[] {element};
|
||
}
|
||
|
||
/**
|
||
* Obvious string.
|
||
*
|
||
* @return The string surrounded by enclosing
|
||
* square brackets.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[" + element + "]";
|
||
}
|
||
} // class SingletonSet
|
||
|
||
/**
|
||
* Obtain an immutable List consisting of a single element. The return value
|
||
* of this method is Serializable, and implements RandomAccess.
|
||
*
|
||
* @param o the single element
|
||
* @return an immutable List containing only o
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
* @since 1.3
|
||
*/
|
||
public static List singletonList(Object o)
|
||
{
|
||
return new SingletonList(o);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #singletonList(Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SingletonList extends AbstractList
|
||
implements Serializable, RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 3093736618740652951L;
|
||
|
||
/**
|
||
* The single element.
|
||
* @serial the singleton
|
||
*/
|
||
private final Object element;
|
||
|
||
/**
|
||
* Construct a singleton.
|
||
* @param o the element
|
||
*/
|
||
SingletonList(Object o)
|
||
{
|
||
element = o;
|
||
}
|
||
|
||
/**
|
||
* The size: always 1!
|
||
* @return 1.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Only index 0 is valid.
|
||
* @param index The index of the element
|
||
* to retrieve.
|
||
* @return The singleton's element if the
|
||
* index is 0.
|
||
* @throws IndexOutOfBoundsException if
|
||
* index is not 0.
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
if (index == 0)
|
||
return element;
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractList.
|
||
/**
|
||
* The set only contains one element.
|
||
*
|
||
* @param o The object to search for.
|
||
* @return <code>true</code> if o == the singleton element.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return equals(o, element);
|
||
}
|
||
|
||
/**
|
||
* This is true if the other collection only contains the element.
|
||
*
|
||
* @param c A collection to compare against this singleton.
|
||
* @return <code>true</code> if c only contains either no elements or
|
||
* elements equal to the element in this singleton.
|
||
*/
|
||
public boolean containsAll(Collection c)
|
||
{
|
||
Iterator i = c.iterator();
|
||
int pos = c.size();
|
||
while (--pos >= 0)
|
||
if (! equals(i.next(), element))
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Speed up the hashcode computation.
|
||
*
|
||
* @return The hashcode of the list, based
|
||
* on the hashcode of the singleton element.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return 31 + hashCode(element);
|
||
}
|
||
|
||
/**
|
||
* Either the list has it or not.
|
||
*
|
||
* @param o The object to find the first index of.
|
||
* @return 0 if o is the singleton element, -1 if not.
|
||
*/
|
||
public int indexOf(Object o)
|
||
{
|
||
return equals(o, element) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* Either the list has it or not.
|
||
*
|
||
* @param o The object to find the last index of.
|
||
* @return 0 if o is the singleton element, -1 if not.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return equals(o, element) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* Sublists are limited in scope.
|
||
*
|
||
* @param from The starting bound for the sublist.
|
||
* @param to The ending bound for the sublist.
|
||
* @return Either an empty list if both bounds are
|
||
* 0 or 1, or this list if the bounds are 0 and 1.
|
||
* @throws IllegalArgumentException if <code>from > to</code>
|
||
* @throws IndexOutOfBoundsException if either bound is greater
|
||
* than 1.
|
||
*/
|
||
public List subList(int from, int to)
|
||
{
|
||
if (from == to && (to == 0 || to == 1))
|
||
return EMPTY_LIST;
|
||
if (from == 0 && to == 1)
|
||
return this;
|
||
if (from > to)
|
||
throw new IllegalArgumentException();
|
||
throw new IndexOutOfBoundsException();
|
||
}
|
||
|
||
/**
|
||
* Returning an array is simple.
|
||
*
|
||
* @return An array containing the element.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return new Object[] {element};
|
||
}
|
||
|
||
/**
|
||
* Obvious string.
|
||
*
|
||
* @return The string surrounded by enclosing
|
||
* square brackets.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "[" + element + "]";
|
||
}
|
||
} // class SingletonList
|
||
|
||
/**
|
||
* Obtain an immutable Map consisting of a single key-value pair.
|
||
* The return value of this method is Serializable.
|
||
*
|
||
* @param key the single key
|
||
* @param value the single value
|
||
* @return an immutable Map containing only the single key-value pair
|
||
* @see Serializable
|
||
* @since 1.3
|
||
*/
|
||
public static Map singletonMap(Object key, Object value)
|
||
{
|
||
return new SingletonMap(key, value);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #singletonMap(Object)}. This class name
|
||
* is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SingletonMap extends AbstractMap
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -6979724477215052911L;
|
||
|
||
/**
|
||
* The single key.
|
||
* @serial the singleton key
|
||
*/
|
||
private final Object k;
|
||
|
||
/**
|
||
* The corresponding value.
|
||
* @serial the singleton value
|
||
*/
|
||
private final Object v;
|
||
|
||
/**
|
||
* Cache the entry set.
|
||
*/
|
||
private transient Set entries;
|
||
|
||
/**
|
||
* Construct a singleton.
|
||
* @param key the key
|
||
* @param value the value
|
||
*/
|
||
SingletonMap(Object key, Object value)
|
||
{
|
||
k = key;
|
||
v = value;
|
||
}
|
||
|
||
/**
|
||
* There is a single immutable entry.
|
||
*
|
||
* @return A singleton containing the map entry.
|
||
*/
|
||
public Set entrySet()
|
||
{
|
||
if (entries == null)
|
||
entries = singleton(new AbstractMap.BasicMapEntry(k, v)
|
||
{
|
||
/**
|
||
* Sets the value of the map entry to the supplied value.
|
||
* An exception is always thrown, as the map is immutable.
|
||
*
|
||
* @param o The new value.
|
||
* @return The old value.
|
||
* @throws UnsupportedOperationException as setting the value
|
||
* is not supported.
|
||
*/
|
||
public Object setValue(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
});
|
||
return entries;
|
||
}
|
||
|
||
// The remaining methods are optional, but provide a performance
|
||
// advantage by not allocating unnecessary iterators in AbstractMap.
|
||
/**
|
||
* Single entry.
|
||
*
|
||
* @param key The key to look for.
|
||
* @return <code>true</code> if the key is the same as the one used by
|
||
* this map.
|
||
*/
|
||
public boolean containsKey(Object key)
|
||
{
|
||
return equals(key, k);
|
||
}
|
||
|
||
/**
|
||
* Single entry.
|
||
*
|
||
* @param value The value to look for.
|
||
* @return <code>true</code> if the value is the same as the one used by
|
||
* this map.
|
||
*/
|
||
public boolean containsValue(Object value)
|
||
{
|
||
return equals(value, v);
|
||
}
|
||
|
||
/**
|
||
* Single entry.
|
||
*
|
||
* @param key The key of the value to be retrieved.
|
||
* @return The singleton value if the key is the same as the
|
||
* singleton key, null otherwise.
|
||
*/
|
||
public Object get(Object key)
|
||
{
|
||
return equals(key, k) ? v : null;
|
||
}
|
||
|
||
/**
|
||
* Calculate the hashcode directly.
|
||
*
|
||
* @return The hashcode computed from the singleton key
|
||
* and the singleton value.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return hashCode(k) ^ hashCode(v);
|
||
}
|
||
|
||
/**
|
||
* Return the keyset.
|
||
*
|
||
* @return A singleton containing the key.
|
||
*/
|
||
public Set keySet()
|
||
{
|
||
if (keys == null)
|
||
keys = singleton(k);
|
||
return keys;
|
||
}
|
||
|
||
/**
|
||
* The size: always 1!
|
||
*
|
||
* @return 1.
|
||
*/
|
||
public int size()
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Return the values. Technically, a singleton, while more specific than
|
||
* a general Collection, will work. Besides, that's what the JDK uses!
|
||
*
|
||
* @return A singleton containing the value.
|
||
*/
|
||
public Collection values()
|
||
{
|
||
if (values == null)
|
||
values = singleton(v);
|
||
return values;
|
||
}
|
||
|
||
/**
|
||
* Obvious string.
|
||
*
|
||
* @return A string containing the string representations of the key
|
||
* and its associated value.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return "{" + k + "=" + v + "}";
|
||
}
|
||
} // class SingletonMap
|
||
|
||
/**
|
||
* Sort a list according to the natural ordering of its elements. The list
|
||
* must be modifiable, but can be of fixed size. The sort algorithm is
|
||
* precisely that used by Arrays.sort(Object[]), which offers guaranteed
|
||
* nlog(n) performance. This implementation dumps the list into an array,
|
||
* sorts the array, and then iterates over the list setting each element from
|
||
* the array.
|
||
*
|
||
* @param l the List to sort
|
||
* @throws ClassCastException if some items are not mutually comparable
|
||
* @throws UnsupportedOperationException if the List is not modifiable
|
||
* @throws NullPointerException if some element is null
|
||
* @see Arrays#sort(Object[])
|
||
*/
|
||
public static void sort(List l)
|
||
{
|
||
sort(l, null);
|
||
}
|
||
|
||
/**
|
||
* Sort a list according to a specified Comparator. The list must be
|
||
* modifiable, but can be of fixed size. The sort algorithm is precisely that
|
||
* used by Arrays.sort(Object[], Comparator), which offers guaranteed
|
||
* nlog(n) performance. This implementation dumps the list into an array,
|
||
* sorts the array, and then iterates over the list setting each element from
|
||
* the array.
|
||
*
|
||
* @param l the List to sort
|
||
* @param c the Comparator specifying the ordering for the elements, or
|
||
* null for natural ordering
|
||
* @throws ClassCastException if c will not compare some pair of items
|
||
* @throws UnsupportedOperationException if the List is not modifiable
|
||
* @throws NullPointerException if null is compared by natural ordering
|
||
* (only possible when c is null)
|
||
* @see Arrays#sort(Object[], Comparator)
|
||
*/
|
||
public static void sort(List l, Comparator c)
|
||
{
|
||
Object[] a = l.toArray();
|
||
Arrays.sort(a, c);
|
||
ListIterator i = l.listIterator();
|
||
for (int pos = 0, alen = a.length; pos < alen; pos++)
|
||
{
|
||
i.next();
|
||
i.set(a[pos]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Swaps the elements at the specified positions within the list. Equal
|
||
* positions have no effect.
|
||
*
|
||
* @param l the list to work on
|
||
* @param i the first index to swap
|
||
* @param j the second index
|
||
* @throws UnsupportedOperationException if list.set is not supported
|
||
* @throws IndexOutOfBoundsException if either i or j is < 0 or >=
|
||
* list.size()
|
||
* @since 1.4
|
||
*/
|
||
public static void swap(List l, int i, int j)
|
||
{
|
||
l.set(i, l.set(j, l.get(i)));
|
||
}
|
||
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) collection wrapper backed by the
|
||
* given collection. Notice that element access through the iterators
|
||
* is thread-safe, but if the collection can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* Collection c = Collections.synchronizedCollection(new Collection(...));
|
||
* ...
|
||
* synchronized (c)
|
||
* {
|
||
* Iterator i = c.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* Since the collection might be a List or a Set, and those have incompatible
|
||
* equals and hashCode requirements, this relies on Object's implementation
|
||
* rather than passing those calls on to the wrapped collection. The returned
|
||
* Collection implements Serializable, but can only be serialized if
|
||
* the collection it wraps is likewise Serializable.
|
||
*
|
||
* @param c the collection to wrap
|
||
* @return a synchronized view of the collection
|
||
* @see Serializable
|
||
*/
|
||
public static Collection synchronizedCollection(Collection c)
|
||
{
|
||
return new SynchronizedCollection(c);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedCollection(Collection)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
* Package visible, so that collections such as the one for
|
||
* Hashtable.values() can specify which object to synchronize on.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
static class SynchronizedCollection
|
||
implements Collection, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 3053995032091335093L;
|
||
|
||
/**
|
||
* The wrapped collection. Package visible for use by subclasses.
|
||
* @serial the real collection
|
||
*/
|
||
final Collection c;
|
||
|
||
/**
|
||
* The object to synchronize on. When an instance is created via public
|
||
* methods, it will be this; but other uses like SynchronizedMap.values()
|
||
* must specify another mutex. Package visible for use by subclasses.
|
||
* @serial the lock
|
||
*/
|
||
final Object mutex;
|
||
|
||
/**
|
||
* Wrap a given collection.
|
||
* @param c the collection to wrap
|
||
* @throws NullPointerException if c is null
|
||
*/
|
||
SynchronizedCollection(Collection c)
|
||
{
|
||
this.c = c;
|
||
mutex = this;
|
||
if (c == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the
|
||
* collection.
|
||
* @param sync the mutex
|
||
* @param c the collection
|
||
*/
|
||
SynchronizedCollection(Object sync, Collection c)
|
||
{
|
||
this.c = c;
|
||
mutex = sync;
|
||
}
|
||
|
||
/**
|
||
* Adds the object to the underlying collection, first
|
||
* obtaining a lock on the mutex.
|
||
*
|
||
* @param o The object to add.
|
||
* @return <code>true</code> if the collection was modified as a result
|
||
* of this action.
|
||
* @throws UnsupportedOperationException if this collection does not
|
||
* support the add operation.
|
||
* @throws ClassCastException if o cannot be added to this collection due
|
||
* to its type.
|
||
* @throws NullPointerException if o is null and this collection doesn't
|
||
* support the addition of null values.
|
||
* @throws IllegalArgumentException if o cannot be added to this
|
||
* collection for some other reason.
|
||
*/
|
||
public boolean add(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.add(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Adds the objects in col to the underlying collection, first
|
||
* obtaining a lock on the mutex.
|
||
*
|
||
* @param col The collection to take the new objects from.
|
||
* @return <code>true</code> if the collection was modified as a result
|
||
* of this action.
|
||
* @throws UnsupportedOperationException if this collection does not
|
||
* support the addAll operation.
|
||
* @throws ClassCastException if some element of col cannot be added to this
|
||
* collection due to its type.
|
||
* @throws NullPointerException if some element of col is null and this
|
||
* collection does not support the addition of null values.
|
||
* @throws NullPointerException if col itself is null.
|
||
* @throws IllegalArgumentException if some element of col cannot be added
|
||
* to this collection for some other reason.
|
||
*/
|
||
public boolean addAll(Collection col)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.addAll(col);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes all objects from the underlying collection,
|
||
* first obtaining a lock on the mutex.
|
||
*
|
||
* @throws UnsupportedOperationException if this collection does not
|
||
* support the clear operation.
|
||
*/
|
||
public void clear()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
c.clear();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Checks for the existence of o within the underlying
|
||
* collection, first obtaining a lock on the mutex.
|
||
*
|
||
* @param o the element to look for.
|
||
* @return <code>true</code> if this collection contains at least one
|
||
* element e such that <code>o == null ? e == null : o.equals(e)</code>.
|
||
* @throws ClassCastException if the type of o is not a valid type for this
|
||
* collection.
|
||
* @throws NullPointerException if o is null and this collection doesn't
|
||
* support null values.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.contains(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Checks for the existence of each object in cl
|
||
* within the underlying collection, first obtaining
|
||
* a lock on the mutex.
|
||
*
|
||
* @param cl the collection to test for.
|
||
* @return <code>true</code> if for every element o in c, contains(o)
|
||
* would return <code>true</code>.
|
||
* @throws ClassCastException if the type of any element in cl is not a valid
|
||
* type for this collection.
|
||
* @throws NullPointerException if some element of cl is null and this
|
||
* collection does not support null values.
|
||
* @throws NullPointerException if cl itself is null.
|
||
*/
|
||
public boolean containsAll(Collection c1)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.containsAll(c1);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if there are no objects in the underlying
|
||
* collection. A lock on the mutex is obtained before the
|
||
* check is performed.
|
||
*
|
||
* @return <code>true</code> if this collection contains no elements.
|
||
*/
|
||
public boolean isEmpty()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.isEmpty();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a synchronized iterator wrapper around the underlying
|
||
* collection's iterator. A lock on the mutex is obtained before
|
||
* retrieving the collection's iterator.
|
||
*
|
||
* @return An iterator over the elements in the underlying collection,
|
||
* which returns each element in any order.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedIterator(mutex, c.iterator());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes the specified object from the underlying collection,
|
||
* first obtaining a lock on the mutex.
|
||
*
|
||
* @param o The object to remove.
|
||
* @return <code>true</code> if the collection changed as a result of this call, that is,
|
||
* if the collection contained at least one occurrence of o.
|
||
* @throws UnsupportedOperationException if this collection does not
|
||
* support the remove operation.
|
||
* @throws ClassCastException if the type of o is not a valid type
|
||
* for this collection.
|
||
* @throws NullPointerException if o is null and the collection doesn't
|
||
* support null values.
|
||
*/
|
||
public boolean remove(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.remove(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes all elements, e, of the underlying
|
||
* collection for which <code>col.contains(e)</code>
|
||
* returns <code>true</code>. A lock on the mutex is obtained
|
||
* before the operation proceeds.
|
||
*
|
||
* @param col The collection of objects to be removed.
|
||
* @return <code>true</code> if this collection was modified as a result of this call.
|
||
* @throws UnsupportedOperationException if this collection does not
|
||
* support the removeAll operation.
|
||
* @throws ClassCastException if the type of any element in c is not a valid
|
||
* type for this collection.
|
||
* @throws NullPointerException if some element of c is null and this
|
||
* collection does not support removing null values.
|
||
* @throws NullPointerException if c itself is null.
|
||
*/
|
||
public boolean removeAll(Collection col)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.removeAll(col);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Retains all elements, e, of the underlying
|
||
* collection for which <code>col.contains(e)</code>
|
||
* returns <code>true</code>. That is, every element that doesn't
|
||
* exist in col is removed. A lock on the mutex is obtained
|
||
* before the operation proceeds.
|
||
*
|
||
* @param col The collection of objects to be removed.
|
||
* @return <code>true</code> if this collection was modified as a result of this call.
|
||
* @throws UnsupportedOperationException if this collection does not
|
||
* support the removeAll operation.
|
||
* @throws ClassCastException if the type of any element in c is not a valid
|
||
* type for this collection.
|
||
* @throws NullPointerException if some element of c is null and this
|
||
* collection does not support removing null values.
|
||
* @throws NullPointerException if c itself is null.
|
||
*/
|
||
public boolean retainAll(Collection col)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.retainAll(col);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Retrieves the size of the underlying collection.
|
||
* A lock on the mutex is obtained before the collection
|
||
* is accessed.
|
||
*
|
||
* @return The size of the collection.
|
||
*/
|
||
public int size()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.size();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns an array containing each object within the underlying
|
||
* collection. A lock is obtained on the mutex before the collection
|
||
* is accessed.
|
||
*
|
||
* @return An array of objects, matching the collection in size. The
|
||
* elements occur in any order.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.toArray();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Copies the elements in the underlying collection to the supplied
|
||
* array. If <code>a.length < size()</code>, a new array of the
|
||
* same run-time type is created, with a size equal to that of
|
||
* the collection. If <code>a.length > size()</code>, then the
|
||
* elements from 0 to <code>size() - 1</code> contain the elements
|
||
* from this collection. The following element is set to null
|
||
* to indicate the end of the collection objects. However, this
|
||
* only makes a difference if null is not a permitted value within
|
||
* the collection.
|
||
* Before the copying takes place, a lock is obtained on the mutex.
|
||
*
|
||
* @param a An array to copy elements to.
|
||
* @return An array containing the elements of the underlying collection.
|
||
* @throws ArrayStoreException if the type of any element of the
|
||
* collection is not a subtype of the element type of a.
|
||
*/
|
||
public Object[] toArray(Object[] a)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.toArray(a);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a string representation of the underlying collection.
|
||
* A lock is obtained on the mutex before the string is created.
|
||
*
|
||
* @return A string representation of the collection.
|
||
*/
|
||
public String toString()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.toString();
|
||
}
|
||
}
|
||
} // class SynchronizedCollection
|
||
|
||
/**
|
||
* The implementation of the various iterator methods in the
|
||
* synchronized classes. These iterators must "sync" on the same object
|
||
* as the collection they iterate over.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class SynchronizedIterator implements Iterator
|
||
{
|
||
/**
|
||
* The object to synchronize on. Package visible for use by subclass.
|
||
*/
|
||
final Object mutex;
|
||
|
||
/**
|
||
* The wrapped iterator.
|
||
*/
|
||
private final Iterator i;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper, with the specified sync.
|
||
* @param sync the mutex
|
||
* @param i the wrapped iterator
|
||
*/
|
||
SynchronizedIterator(Object sync, Iterator i)
|
||
{
|
||
this.i = i;
|
||
mutex = sync;
|
||
}
|
||
|
||
/**
|
||
* Retrieves the next object in the underlying collection.
|
||
* A lock is obtained on the mutex before the collection is accessed.
|
||
*
|
||
* @return The next object in the collection.
|
||
* @throws NoSuchElementException if there are no more elements
|
||
*/
|
||
public Object next()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return i.next();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if objects can still be retrieved from the iterator
|
||
* using <code>next()</code>. A lock is obtained on the mutex before
|
||
* the collection is accessed.
|
||
*
|
||
* @return <code>true</code> if at least one element is still to be returned by
|
||
* <code>next()</code>.
|
||
*/
|
||
public boolean hasNext()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return i.hasNext();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes the object that was last returned by <code>next()</code>
|
||
* from the underlying collection. Only one call to this method is
|
||
* allowed per call to the <code>next()</code> method, and it does
|
||
* not affect the value that will be returned by <code>next()</code>.
|
||
* Thus, if element n was retrieved from the collection by
|
||
* <code>next()</code>, it is this element that gets removed.
|
||
* Regardless of whether this takes place or not, element n+1 is
|
||
* still returned on the subsequent <code>next()</code> call.
|
||
*
|
||
* @throws IllegalStateException if next has not yet been called or remove
|
||
* has already been called since the last call to next.
|
||
* @throws UnsupportedOperationException if this Iterator does not support
|
||
* the remove operation.
|
||
*/
|
||
public void remove()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
i.remove();
|
||
}
|
||
}
|
||
} // class SynchronizedIterator
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) list wrapper backed by the
|
||
* given list. Notice that element access through the iterators
|
||
* is thread-safe, but if the list can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* List l = Collections.synchronizedList(new List(...));
|
||
* ...
|
||
* synchronized (l)
|
||
* {
|
||
* Iterator i = l.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned List implements Serializable, but can only be serialized if
|
||
* the list it wraps is likewise Serializable. In addition, if the wrapped
|
||
* list implements RandomAccess, this does too.
|
||
*
|
||
* @param l the list to wrap
|
||
* @return a synchronized view of the list
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static List synchronizedList(List l)
|
||
{
|
||
if (l instanceof RandomAccess)
|
||
return new SynchronizedRandomAccessList(l);
|
||
return new SynchronizedList(l);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedList(List)} for sequential
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability. Package visible, so that lists such as Vector.subList()
|
||
* can specify which object to synchronize on.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
static class SynchronizedList extends SynchronizedCollection
|
||
implements List
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -7754090372962971524L;
|
||
|
||
/**
|
||
* The wrapped list; stored both here and in the superclass to avoid
|
||
* excessive casting. Package visible for use by subclass.
|
||
* @serial the wrapped list
|
||
*/
|
||
final List list;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
SynchronizedList(List l)
|
||
{
|
||
super(l);
|
||
list = l;
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the list.
|
||
* @param sync the mutex
|
||
* @param l the list
|
||
*/
|
||
SynchronizedList(Object sync, List l)
|
||
{
|
||
super(sync, l);
|
||
list = l;
|
||
}
|
||
|
||
/**
|
||
* Insert an element into the underlying list at a given position (optional
|
||
* operation). This shifts all existing elements from that position to the
|
||
* end one index to the right. This version of add has no return, since it is
|
||
* assumed to always succeed if there is no exception. Before the
|
||
* addition takes place, a lock is obtained on the mutex.
|
||
*
|
||
* @param index the location to insert the item
|
||
* @param o the object to insert
|
||
* @throws UnsupportedOperationException if this list does not support the
|
||
* add operation
|
||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||
* @throws ClassCastException if o cannot be added to this list due to its
|
||
* type
|
||
* @throws IllegalArgumentException if o cannot be added to this list for
|
||
* some other reason
|
||
* @throws NullPointerException if o is null and this list doesn't support
|
||
* the addition of null values.
|
||
*/
|
||
public void add(int index, Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
list.add(index, o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Add an element to the end of the underlying list (optional operation).
|
||
* If the list imposes restraints on what can be inserted, such as no null
|
||
* elements, this should be documented. A lock is obtained on the mutex before
|
||
* any of the elements are added.
|
||
*
|
||
* @param o the object to add
|
||
* @return <code>true</code>, as defined by Collection for a modified list
|
||
* @throws UnsupportedOperationException if this list does not support the
|
||
* add operation
|
||
* @throws ClassCastException if o cannot be added to this list due to its
|
||
* type
|
||
* @throws IllegalArgumentException if o cannot be added to this list for
|
||
* some other reason
|
||
* @throws NullPointerException if o is null and this list doesn't support
|
||
* the addition of null values.
|
||
*/
|
||
public boolean addAll(int index, Collection c)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.addAll(index, c);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Tests whether the underlying list is equal to the supplied object.
|
||
* The object is deemed to be equal if it is also a <code>List</code>
|
||
* of equal size and with the same elements (i.e. each element, e1,
|
||
* in list, l1, and each element, e2, in l2, must return <code>true</code> for
|
||
* <code>e1 == null ? e2 == null : e1.equals(e2)</code>. Before the
|
||
* comparison is made, a lock is obtained on the mutex.
|
||
*
|
||
* @param o The object to test for equality with the underlying list.
|
||
* @return <code>true</code> if o is equal to the underlying list under the above
|
||
* definition.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.equals(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Retrieves the object at the specified index. A lock
|
||
* is obtained on the mutex before the list is accessed.
|
||
*
|
||
* @param index the index of the element to be returned
|
||
* @return the element at index index in this list
|
||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.get(index);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Obtains a hashcode for the underlying list, first obtaining
|
||
* a lock on the mutex. The calculation of the hashcode is
|
||
* detailed in the documentation for the <code>List</code>
|
||
* interface.
|
||
*
|
||
* @return The hashcode of the underlying list.
|
||
* @see List#hashCode()
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.hashCode();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Obtain the first index at which a given object is to be found in the
|
||
* underlying list. A lock is obtained on the mutex before the list is
|
||
* accessed.
|
||
*
|
||
* @param o the object to search for
|
||
* @return the least integer n such that <code>o == null ? get(n) == null :
|
||
* o.equals(get(n))</code>, or -1 if there is no such index.
|
||
* @throws ClassCastException if the type of o is not a valid
|
||
* type for this list.
|
||
* @throws NullPointerException if o is null and this
|
||
* list does not support null values.
|
||
*/
|
||
|
||
public int indexOf(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.indexOf(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Obtain the last index at which a given object is to be found in this
|
||
* underlying list. A lock is obtained on the mutex before the list
|
||
* is accessed.
|
||
*
|
||
* @return the greatest integer n such that <code>o == null ? get(n) == null
|
||
* : o.equals(get(n))</code>, or -1 if there is no such index.
|
||
* @throws ClassCastException if the type of o is not a valid
|
||
* type for this list.
|
||
* @throws NullPointerException if o is null and this
|
||
* list does not support null values.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.lastIndexOf(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Retrieves a synchronized wrapper around the underlying list's
|
||
* list iterator. A lock is obtained on the mutex before the
|
||
* list iterator is retrieved.
|
||
*
|
||
* @return A list iterator over the elements in the underlying list.
|
||
* The list iterator allows additional list-specific operations
|
||
* to be performed, in addition to those supplied by the
|
||
* standard iterator.
|
||
*/
|
||
public ListIterator listIterator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedListIterator(mutex, list.listIterator());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Retrieves a synchronized wrapper around the underlying list's
|
||
* list iterator. A lock is obtained on the mutex before the
|
||
* list iterator is retrieved. The iterator starts at the
|
||
* index supplied, leading to the element at that index being
|
||
* the first one returned by <code>next()</code>. Calling
|
||
* <code>previous()</code> from this initial position returns
|
||
* index - 1.
|
||
*
|
||
* @param index the position, between 0 and size() inclusive, to begin the
|
||
* iteration from
|
||
* @return A list iterator over the elements in the underlying list.
|
||
* The list iterator allows additional list-specific operations
|
||
* to be performed, in addition to those supplied by the
|
||
* standard iterator.
|
||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||
*/
|
||
public ListIterator listIterator(int index)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedListIterator(mutex, list.listIterator(index));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Remove the element at a given position in the underlying list (optional
|
||
* operation). All remaining elements are shifted to the left to fill the gap.
|
||
* A lock on the mutex is obtained before the element is removed.
|
||
*
|
||
* @param index the position within the list of the object to remove
|
||
* @return the object that was removed
|
||
* @throws UnsupportedOperationException if this list does not support the
|
||
* remove operation
|
||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||
*/
|
||
public Object remove(int index)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.remove(index);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Replace an element of the underlying list with another object (optional
|
||
* operation). A lock is obtained on the mutex before the element is
|
||
* replaced.
|
||
*
|
||
* @param index the position within this list of the element to be replaced
|
||
* @param o the object to replace it with
|
||
* @return the object that was replaced
|
||
* @throws UnsupportedOperationException if this list does not support the
|
||
* set operation.
|
||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||
* @throws ClassCastException if o cannot be added to this list due to its
|
||
* type
|
||
* @throws IllegalArgumentException if o cannot be added to this list for
|
||
* some other reason
|
||
* @throws NullPointerException if o is null and this
|
||
* list does not support null values.
|
||
*/
|
||
public Object set(int index, Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return list.set(index, o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Obtain a List view of a subsection of the underlying list, from fromIndex
|
||
* (inclusive) to toIndex (exclusive). If the two indices are equal, the
|
||
* sublist is empty. The returned list should be modifiable if and only
|
||
* if this list is modifiable. Changes to the returned list should be
|
||
* reflected in this list. If this list is structurally modified in
|
||
* any way other than through the returned list, the result of any subsequent
|
||
* operations on the returned list is undefined. A lock is obtained
|
||
* on the mutex before the creation of the sublist. The returned list
|
||
* is also synchronized, using the same mutex.
|
||
*
|
||
* @param fromIndex the index that the returned list should start from
|
||
* (inclusive)
|
||
* @param toIndex the index that the returned list should go to (exclusive)
|
||
* @return a List backed by a subsection of this list
|
||
* @throws IndexOutOfBoundsException if fromIndex < 0
|
||
* || toIndex > size() || fromIndex > toIndex
|
||
*/
|
||
public List subList(int fromIndex, int toIndex)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedList(mutex, list.subList(fromIndex, toIndex));
|
||
}
|
||
}
|
||
} // class SynchronizedList
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedList(List)} for random-access
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SynchronizedRandomAccessList
|
||
extends SynchronizedList implements RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1530674583602358482L;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
SynchronizedRandomAccessList(List l)
|
||
{
|
||
super(l);
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the
|
||
* collection.
|
||
* @param sync the mutex
|
||
* @param l the list
|
||
*/
|
||
SynchronizedRandomAccessList(Object sync, List l)
|
||
{
|
||
super(sync, l);
|
||
}
|
||
|
||
/**
|
||
* Obtain a List view of a subsection of the underlying list, from fromIndex
|
||
* (inclusive) to toIndex (exclusive). If the two indices are equal, the
|
||
* sublist is empty. The returned list should be modifiable if and only
|
||
* if this list is modifiable. Changes to the returned list should be
|
||
* reflected in this list. If this list is structurally modified in
|
||
* any way other than through the returned list, the result of any subsequent
|
||
* operations on the returned list is undefined. A lock is obtained
|
||
* on the mutex before the creation of the sublist. The returned list
|
||
* is also synchronized, using the same mutex. Random accessibility
|
||
* is also extended to the new list.
|
||
*
|
||
* @param fromIndex the index that the returned list should start from
|
||
* (inclusive)
|
||
* @param toIndex the index that the returned list should go to (exclusive)
|
||
* @return a List backed by a subsection of this list
|
||
* @throws IndexOutOfBoundsException if fromIndex < 0
|
||
* || toIndex > size() || fromIndex > toIndex
|
||
*/
|
||
public List subList(int fromIndex, int toIndex)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedRandomAccessList(mutex,
|
||
list.subList(fromIndex,
|
||
toIndex));
|
||
}
|
||
}
|
||
} // class SynchronizedRandomAccessList
|
||
|
||
/**
|
||
* The implementation of {@link SynchronizedList#listIterator()}. This
|
||
* iterator must "sync" on the same object as the list it iterates over.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SynchronizedListIterator
|
||
extends SynchronizedIterator implements ListIterator
|
||
{
|
||
/**
|
||
* The wrapped iterator, stored both here and in the superclass to
|
||
* avoid excessive casting.
|
||
*/
|
||
private final ListIterator li;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper, with the specified sync.
|
||
* @param sync the mutex
|
||
* @param li the wrapped iterator
|
||
*/
|
||
SynchronizedListIterator(Object sync, ListIterator li)
|
||
{
|
||
super(sync, li);
|
||
this.li = li;
|
||
}
|
||
|
||
/**
|
||
* Insert an element into the underlying list at the current position of
|
||
* the iterator (optional operation). The element is inserted in between
|
||
* the element that would be returned by <code>previous()</code> and the
|
||
* element that would be returned by <code>next()</code>. After the
|
||
* insertion, a subsequent call to next is unaffected, but
|
||
* a call to previous returns the item that was added. The values returned
|
||
* by nextIndex() and previousIndex() are incremented. A lock is obtained
|
||
* on the mutex before the addition takes place.
|
||
*
|
||
* @param o the object to insert into the list
|
||
* @throws ClassCastException if the object is of a type which cannot be added
|
||
* to this list.
|
||
* @throws IllegalArgumentException if some other aspect of the object stops
|
||
* it being added to this list.
|
||
* @throws UnsupportedOperationException if this ListIterator does not
|
||
* support the add operation.
|
||
*/
|
||
public void add(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
li.add(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Tests whether there are elements remaining in the underlying list
|
||
* in the reverse direction. In other words, <code>previous()</code>
|
||
* will not fail with a NoSuchElementException. A lock is obtained
|
||
* on the mutex before the check takes place.
|
||
*
|
||
* @return <code>true</code> if the list continues in the reverse direction
|
||
*/
|
||
public boolean hasPrevious()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.hasPrevious();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Find the index of the element that would be returned by a call to
|
||
* <code>next()</code>. If hasNext() returns <code>false</code>, this
|
||
* returns the list size. A lock is obtained on the mutex before the
|
||
* query takes place.
|
||
*
|
||
* @return the index of the element that would be returned by next()
|
||
*/
|
||
public int nextIndex()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.nextIndex();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Obtain the previous element from the underlying list. Repeated
|
||
* calls to previous may be used to iterate backwards over the entire list,
|
||
* or calls to next and previous may be used together to go forwards and
|
||
* backwards. Alternating calls to next and previous will return the same
|
||
* element. A lock is obtained on the mutex before the object is retrieved.
|
||
*
|
||
* @return the next element in the list in the reverse direction
|
||
* @throws NoSuchElementException if there are no more elements
|
||
*/
|
||
public Object previous()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.previous();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Find the index of the element that would be returned by a call to
|
||
* previous. If hasPrevious() returns <code>false</code>, this returns -1.
|
||
* A lock is obtained on the mutex before the query takes place.
|
||
*
|
||
* @return the index of the element that would be returned by previous()
|
||
*/
|
||
public int previousIndex()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return li.previousIndex();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Replace the element last returned by a call to <code>next()</code> or
|
||
* <code>previous()</code> with a given object (optional operation). This
|
||
* method may only be called if neither <code>add()</code> nor
|
||
* <code>remove()</code> have been called since the last call to
|
||
* <code>next()</code> or <code>previous</code>. A lock is obtained
|
||
* on the mutex before the list is modified.
|
||
*
|
||
* @param o the object to replace the element with
|
||
* @throws ClassCastException the object is of a type which cannot be added
|
||
* to this list
|
||
* @throws IllegalArgumentException some other aspect of the object stops
|
||
* it being added to this list
|
||
* @throws IllegalStateException if neither next or previous have been
|
||
* called, or if add or remove has been called since the last call
|
||
* to next or previous
|
||
* @throws UnsupportedOperationException if this ListIterator does not
|
||
* support the set operation
|
||
*/
|
||
public void set(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
li.set(o);
|
||
}
|
||
}
|
||
} // class SynchronizedListIterator
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) map wrapper backed by the given
|
||
* map. Notice that element access through the collection views and their
|
||
* iterators are thread-safe, but if the map can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* Map m = Collections.synchronizedMap(new Map(...));
|
||
* ...
|
||
* Set s = m.keySet(); // safe outside a synchronized block
|
||
* synchronized (m) // synch on m, not s
|
||
* {
|
||
* Iterator i = s.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned Map implements Serializable, but can only be serialized if
|
||
* the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the map to wrap
|
||
* @return a synchronized view of the map
|
||
* @see Serializable
|
||
*/
|
||
public static Map synchronizedMap(Map m)
|
||
{
|
||
return new SynchronizedMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedMap(Map)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class SynchronizedMap implements Map, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1978198479659022715L;
|
||
|
||
/**
|
||
* The wrapped map.
|
||
* @serial the real map
|
||
*/
|
||
private final Map m;
|
||
|
||
/**
|
||
* The object to synchronize on. When an instance is created via public
|
||
* methods, it will be this; but other uses like
|
||
* SynchronizedSortedMap.subMap() must specify another mutex. Package
|
||
* visible for use by subclass.
|
||
* @serial the lock
|
||
*/
|
||
final Object mutex;
|
||
|
||
/**
|
||
* Cache the entry set.
|
||
*/
|
||
private transient Set entries;
|
||
|
||
/**
|
||
* Cache the key set.
|
||
*/
|
||
private transient Set keys;
|
||
|
||
/**
|
||
* Cache the value collection.
|
||
*/
|
||
private transient Collection values;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param m the map to wrap
|
||
* @throws NullPointerException if m is null
|
||
*/
|
||
SynchronizedMap(Map m)
|
||
{
|
||
this.m = m;
|
||
mutex = this;
|
||
if (m == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the map.
|
||
* @param sync the mutex
|
||
* @param m the map
|
||
*/
|
||
SynchronizedMap(Object sync, Map m)
|
||
{
|
||
this.m = m;
|
||
mutex = sync;
|
||
}
|
||
|
||
/**
|
||
* Clears all the entries from the underlying map. A lock is obtained
|
||
* on the mutex before the map is cleared.
|
||
*
|
||
* @throws UnsupportedOperationException if clear is not supported
|
||
*/
|
||
public void clear()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
m.clear();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the underlying map contains a entry for the given key.
|
||
* A lock is obtained on the mutex before the map is queried.
|
||
*
|
||
* @param key the key to search for.
|
||
* @return <code>true</code> if the underlying map contains the key.
|
||
* @throws ClassCastException if the key is of an inappropriate type.
|
||
* @throws NullPointerException if key is <code>null</code> but the map
|
||
* does not permit null keys.
|
||
*/
|
||
public boolean containsKey(Object key)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.containsKey(key);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the underlying map contains at least one entry with the
|
||
* given value. In other words, returns <code>true</code> if a value v exists where
|
||
* <code>(value == null ? v == null : value.equals(v))</code>. This usually
|
||
* requires linear time. A lock is obtained on the mutex before the map
|
||
* is queried.
|
||
*
|
||
* @param value the value to search for
|
||
* @return <code>true</code> if the map contains the value
|
||
* @throws ClassCastException if the type of the value is not a valid type
|
||
* for this map.
|
||
* @throws NullPointerException if the value is null and the map doesn't
|
||
* support null values.
|
||
*/
|
||
public boolean containsValue(Object value)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.containsValue(value);
|
||
}
|
||
}
|
||
|
||
// This is one of the ickiest cases of nesting I've ever seen. It just
|
||
// means "return a SynchronizedSet, except that the iterator() method
|
||
// returns an SynchronizedIterator whose next() method returns a
|
||
// synchronized wrapper around its normal return value".
|
||
public Set entrySet()
|
||
{
|
||
// Define this here to spare some nesting.
|
||
class SynchronizedMapEntry implements Map.Entry
|
||
{
|
||
final Map.Entry e;
|
||
SynchronizedMapEntry(Object o)
|
||
{
|
||
e = (Map.Entry) o;
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the object, o, implements <code>Map.Entry</code>
|
||
* with the same key and value as the underlying entry. A lock is
|
||
* obtained on the mutex before the comparison takes place.
|
||
*
|
||
* @param o The object to compare with this entry.
|
||
* @return <code>true</code> if o is equivalent to the underlying map entry.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.equals(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the key used in the underlying map entry. A lock is obtained
|
||
* on the mutex before the key is retrieved.
|
||
*
|
||
* @return The key of the underlying map entry.
|
||
*/
|
||
public Object getKey()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.getKey();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the value used in the underlying map entry. A lock is obtained
|
||
* on the mutex before the value is retrieved.
|
||
*
|
||
* @return The value of the underlying map entry.
|
||
*/
|
||
public Object getValue()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.getValue();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Computes the hash code for the underlying map entry.
|
||
* This computation is described in the documentation for the
|
||
* <code>Map</code> interface. A lock is obtained on the mutex
|
||
* before the underlying map is accessed.
|
||
*
|
||
* @return The hash code of the underlying map entry.
|
||
* @see Map#hashCode()
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.hashCode();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Replaces the value in the underlying map entry with the specified
|
||
* object (optional operation). A lock is obtained on the mutex
|
||
* before the map is altered. The map entry, in turn, will alter
|
||
* the underlying map object. The operation is undefined if the
|
||
* <code>remove()</code> method of the iterator has been called
|
||
* beforehand.
|
||
*
|
||
* @param value the new value to store
|
||
* @return the old value
|
||
* @throws UnsupportedOperationException if the operation is not supported.
|
||
* @throws ClassCastException if the value is of the wrong type.
|
||
* @throws IllegalArgumentException if something about the value
|
||
* prevents it from existing in this map.
|
||
* @throws NullPointerException if the map forbids null values.
|
||
*/
|
||
public Object setValue(Object value)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.setValue(value);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a textual representation of the underlying map entry.
|
||
* A lock is obtained on the mutex before the entry is accessed.
|
||
*
|
||
* @return The contents of the map entry in <code>String</code> form.
|
||
*/
|
||
public String toString()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return e.toString();
|
||
}
|
||
}
|
||
} // class SynchronizedMapEntry
|
||
|
||
// Now the actual code.
|
||
if (entries == null)
|
||
synchronized (mutex)
|
||
{
|
||
entries = new SynchronizedSet(mutex, m.entrySet())
|
||
{
|
||
/**
|
||
* Returns an iterator over the set. The iterator has no specific order,
|
||
* unless further specified. A lock is obtained on the set's mutex
|
||
* before the iterator is created. The created iterator is also
|
||
* thread-safe.
|
||
*
|
||
* @return A synchronized set iterator.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
synchronized (super.mutex)
|
||
{
|
||
return new SynchronizedIterator(super.mutex, c.iterator())
|
||
{
|
||
/**
|
||
* Retrieves the next map entry from the iterator.
|
||
* A lock is obtained on the iterator's mutex before
|
||
* the entry is created. The new map entry is enclosed in
|
||
* a thread-safe wrapper.
|
||
*
|
||
* @return A synchronized map entry.
|
||
*/
|
||
public Object next()
|
||
{
|
||
synchronized (super.mutex)
|
||
{
|
||
return new SynchronizedMapEntry(super.next());
|
||
}
|
||
}
|
||
};
|
||
}
|
||
}
|
||
};
|
||
}
|
||
return entries;
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the object, o, is also an instance
|
||
* of <code>Map</code> and contains an equivalent
|
||
* entry set to that of the underlying map. A lock
|
||
* is obtained on the mutex before the objects are
|
||
* compared.
|
||
*
|
||
* @param o The object to compare.
|
||
* @return <code>true</code> if o and the underlying map are equivalent.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.equals(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the value associated with the given key, or null
|
||
* if no such mapping exists. An ambiguity exists with maps
|
||
* that accept null values as a return value of null could
|
||
* be due to a non-existent mapping or simply a null value
|
||
* for that key. To resolve this, <code>containsKey</code>
|
||
* should be used. A lock is obtained on the mutex before
|
||
* the value is retrieved from the underlying map.
|
||
*
|
||
* @param key The key of the required mapping.
|
||
* @return The value associated with the given key, or
|
||
* null if no such mapping exists.
|
||
* @throws ClassCastException if the key is an inappropriate type.
|
||
* @throws NullPointerException if this map does not accept null keys.
|
||
*/
|
||
public Object get(Object key)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.get(key);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Calculates the hash code of the underlying map as the
|
||
* sum of the hash codes of all entries. A lock is obtained
|
||
* on the mutex before the hash code is computed.
|
||
*
|
||
* @return The hash code of the underlying map.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.hashCode();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the underlying map contains no entries.
|
||
* A lock is obtained on the mutex before the map is examined.
|
||
*
|
||
* @return <code>true</code> if the map is empty.
|
||
*/
|
||
public boolean isEmpty()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.isEmpty();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a thread-safe set view of the keys in the underlying map. The
|
||
* set is backed by the map, so that changes in one show up in the other.
|
||
* Modifications made while an iterator is in progress cause undefined
|
||
* behavior. If the set supports removal, these methods remove the
|
||
* underlying mapping from the map: <code>Iterator.remove</code>,
|
||
* <code>Set.remove</code>, <code>removeAll</code>, <code>retainAll</code>,
|
||
* and <code>clear</code>. Element addition, via <code>add</code> or
|
||
* <code>addAll</code>, is not supported via this set. A lock is obtained
|
||
* on the mutex before the set is created.
|
||
*
|
||
* @return A synchronized set containing the keys of the underlying map.
|
||
*/
|
||
public Set keySet()
|
||
{
|
||
if (keys == null)
|
||
synchronized (mutex)
|
||
{
|
||
keys = new SynchronizedSet(mutex, m.keySet());
|
||
}
|
||
return keys;
|
||
}
|
||
|
||
/**
|
||
* Associates the given key to the given value (optional operation). If the
|
||
* underlying map already contains the key, its value is replaced. Be aware
|
||
* that in a map that permits <code>null</code> values, a null return does not
|
||
* always imply that the mapping was created. A lock is obtained on the mutex
|
||
* before the modification is made.
|
||
*
|
||
* @param key the key to map.
|
||
* @param value the value to be mapped.
|
||
* @return the previous value of the key, or null if there was no mapping
|
||
* @throws UnsupportedOperationException if the operation is not supported
|
||
* @throws ClassCastException if the key or value is of the wrong type
|
||
* @throws IllegalArgumentException if something about this key or value
|
||
* prevents it from existing in this map
|
||
* @throws NullPointerException if either the key or the value is null,
|
||
* and the map forbids null keys or values
|
||
* @see #containsKey(Object)
|
||
*/
|
||
public Object put(Object key, Object value)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.put(key, value);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Copies all entries of the given map to the underlying one (optional
|
||
* operation). If the map already contains a key, its value is replaced.
|
||
* A lock is obtained on the mutex before the operation proceeds.
|
||
*
|
||
* @param m the mapping to load into this map
|
||
* @throws UnsupportedOperationException if the operation is not supported
|
||
* @throws ClassCastException if a key or value is of the wrong type
|
||
* @throws IllegalArgumentException if something about a key or value
|
||
* prevents it from existing in this map
|
||
* @throws NullPointerException if the map forbids null keys or values, or
|
||
* if <code>m</code> is null.
|
||
* @see #put(Object, Object)
|
||
*/
|
||
public void putAll(Map map)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
m.putAll(map);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes the mapping for the key, o, if present (optional operation). If
|
||
* the key is not present, this returns null. Note that maps which permit
|
||
* null values may also return null if the key was removed. A prior
|
||
* <code>containsKey()</code> check is required to avoid this ambiguity.
|
||
* Before the mapping is removed, a lock is obtained on the mutex.
|
||
*
|
||
* @param key the key to remove
|
||
* @return the value the key mapped to, or null if not present
|
||
* @throws UnsupportedOperationException if deletion is unsupported
|
||
* @throws NullPointerException if the key is null and this map doesn't
|
||
* support null keys.
|
||
* @throws ClassCastException if the type of the key is not a valid type
|
||
* for this map.
|
||
*/
|
||
public Object remove(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.remove(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Retrieves the size of the underlying map. A lock
|
||
* is obtained on the mutex before access takes place.
|
||
* Maps with a size greater than <code>Integer.MAX_VALUE</code>
|
||
* return <code>Integer.MAX_VALUE</code> instead.
|
||
*
|
||
* @return The size of the underlying map.
|
||
*/
|
||
public int size()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.size();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a textual representation of the underlying
|
||
* map. A lock is obtained on the mutex before the map
|
||
* is accessed.
|
||
*
|
||
* @return The map in <code>String</code> form.
|
||
*/
|
||
public String toString()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return m.toString();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a synchronized collection view of the values in the underlying
|
||
* map. The collection is backed by the map, so that changes in one show up in
|
||
* the other. Modifications made while an iterator is in progress cause
|
||
* undefined behavior. If the collection supports removal, these methods
|
||
* remove the underlying mapping from the map: <code>Iterator.remove</code>,
|
||
* <code>Collection.remove</code>, <code>removeAll</code>,
|
||
* <code>retainAll</code>, and <code>clear</code>. Element addition, via
|
||
* <code>add</code> or <code>addAll</code>, is not supported via this
|
||
* collection. A lock is obtained on the mutex before the collection
|
||
* is created.
|
||
*
|
||
* @return the collection of all values in the underlying map.
|
||
*/
|
||
public Collection values()
|
||
{
|
||
if (values == null)
|
||
synchronized (mutex)
|
||
{
|
||
values = new SynchronizedCollection(mutex, m.values());
|
||
}
|
||
return values;
|
||
}
|
||
} // class SynchronizedMap
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) set wrapper backed by the given
|
||
* set. Notice that element access through the iterator is thread-safe, but
|
||
* if the set can be structurally modified (adding or removing elements)
|
||
* then you should synchronize around the iteration to avoid
|
||
* non-deterministic behavior:<br>
|
||
* <pre>
|
||
* Set s = Collections.synchronizedSet(new Set(...));
|
||
* ...
|
||
* synchronized (s)
|
||
* {
|
||
* Iterator i = s.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned Set implements Serializable, but can only be serialized if
|
||
* the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the set to wrap
|
||
* @return a synchronized view of the set
|
||
* @see Serializable
|
||
*/
|
||
public static Set synchronizedSet(Set s)
|
||
{
|
||
return new SynchronizedSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSet(Set)}. This class
|
||
* name is required for compatibility with Sun's JDK serializability.
|
||
* Package visible, so that sets such as Hashtable.keySet()
|
||
* can specify which object to synchronize on.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
static class SynchronizedSet extends SynchronizedCollection
|
||
implements Set
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 487447009682186044L;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param s the set to wrap
|
||
* @throws NullPointerException if s is null
|
||
*/
|
||
SynchronizedSet(Set s)
|
||
{
|
||
super(s);
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the set.
|
||
* @param sync the mutex
|
||
* @param s the set
|
||
*/
|
||
SynchronizedSet(Object sync, Set s)
|
||
{
|
||
super(sync, s);
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the object, o, is a <code>Set</code>
|
||
* of the same size as the underlying set, and contains
|
||
* each element, e, which occurs in the underlying set.
|
||
* A lock is obtained on the mutex before the comparison
|
||
* takes place.
|
||
*
|
||
* @param o The object to compare against.
|
||
* @return <code>true</code> if o is an equivalent set.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.equals(o);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Computes the hash code for the underlying set as the
|
||
* sum of the hash code of all elements within the set.
|
||
* A lock is obtained on the mutex before the computation
|
||
* occurs.
|
||
*
|
||
* @return The hash code for the underlying set.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return c.hashCode();
|
||
}
|
||
}
|
||
} // class SynchronizedSet
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) sorted map wrapper backed by the
|
||
* given map. Notice that element access through the collection views,
|
||
* subviews, and their iterators are thread-safe, but if the map can be
|
||
* structurally modified (adding or removing elements) then you should
|
||
* synchronize around the iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* SortedMap m = Collections.synchronizedSortedMap(new SortedMap(...));
|
||
* ...
|
||
* Set s = m.keySet(); // safe outside a synchronized block
|
||
* SortedMap m2 = m.headMap(foo); // safe outside a synchronized block
|
||
* Set s2 = m2.keySet(); // safe outside a synchronized block
|
||
* synchronized (m) // synch on m, not m2, s or s2
|
||
* {
|
||
* Iterator i = s.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* i = s2.iterator();
|
||
* while (i.hasNext())
|
||
* bar(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned SortedMap implements Serializable, but can only be
|
||
* serialized if the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the sorted map to wrap
|
||
* @return a synchronized view of the sorted map
|
||
* @see Serializable
|
||
*/
|
||
public static SortedMap synchronizedSortedMap(SortedMap m)
|
||
{
|
||
return new SynchronizedSortedMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSortedMap(SortedMap)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SynchronizedSortedMap extends SynchronizedMap
|
||
implements SortedMap
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -8798146769416483793L;
|
||
|
||
/**
|
||
* The wrapped map; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped map
|
||
*/
|
||
private final SortedMap sm;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param sm the map to wrap
|
||
* @throws NullPointerException if sm is null
|
||
*/
|
||
SynchronizedSortedMap(SortedMap sm)
|
||
{
|
||
super(sm);
|
||
this.sm = sm;
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the map.
|
||
* @param sync the mutex
|
||
* @param sm the map
|
||
*/
|
||
SynchronizedSortedMap(Object sync, SortedMap sm)
|
||
{
|
||
super(sync, sm);
|
||
this.sm = sm;
|
||
}
|
||
|
||
/**
|
||
* Returns the comparator used in sorting the underlying map, or null if
|
||
* it is the keys' natural ordering. A lock is obtained on the mutex
|
||
* before the comparator is retrieved.
|
||
*
|
||
* @return the sorting comparator.
|
||
*/
|
||
public Comparator comparator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return sm.comparator();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the first, lowest sorted, key from the underlying map.
|
||
* A lock is obtained on the mutex before the map is accessed.
|
||
*
|
||
* @return the first key.
|
||
* @throws NoSuchElementException if this map is empty.
|
||
*/
|
||
public Object firstKey()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return sm.firstKey();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a submap containing the keys from the first
|
||
* key (as returned by <code>firstKey()</code>) to
|
||
* the key before that specified. The submap supports all
|
||
* operations supported by the underlying map and all actions
|
||
* taking place on the submap are also reflected in the underlying
|
||
* map. A lock is obtained on the mutex prior to submap creation.
|
||
* This operation is equivalent to <code>subMap(firstKey(), toKey)</code>.
|
||
* The submap retains the thread-safe status of this map.
|
||
*
|
||
* @param toKey the exclusive upper range of the submap.
|
||
* @return a submap from <code>firstKey()</code> to the
|
||
* the key preceding toKey.
|
||
* @throws ClassCastException if toKey is not comparable to the underlying
|
||
* map's contents.
|
||
* @throws IllegalArgumentException if toKey is outside the map's range.
|
||
* @throws NullPointerException if toKey is null. but the map does not allow
|
||
* null keys.
|
||
*/
|
||
public SortedMap headMap(Object toKey)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedMap(mutex, sm.headMap(toKey));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the last, highest sorted, key from the underlying map.
|
||
* A lock is obtained on the mutex before the map is accessed.
|
||
*
|
||
* @return the last key.
|
||
* @throws NoSuchElementException if this map is empty.
|
||
*/
|
||
public Object lastKey()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return sm.lastKey();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a submap containing the keys from fromKey to
|
||
* the key before toKey. The submap supports all
|
||
* operations supported by the underlying map and all actions
|
||
* taking place on the submap are also reflected in the underlying
|
||
* map. A lock is obtained on the mutex prior to submap creation.
|
||
* The submap retains the thread-safe status of this map.
|
||
*
|
||
* @param fromKey the inclusive lower range of the submap.
|
||
* @param toKey the exclusive upper range of the submap.
|
||
* @return a submap from fromKey to the key preceding toKey.
|
||
* @throws ClassCastException if fromKey or toKey is not comparable
|
||
* to the underlying map's contents.
|
||
* @throws IllegalArgumentException if fromKey or toKey is outside the map's
|
||
* range.
|
||
* @throws NullPointerException if fromKey or toKey is null. but the map does
|
||
* not allow null keys.
|
||
*/
|
||
public SortedMap subMap(Object fromKey, Object toKey)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedMap(mutex, sm.subMap(fromKey, toKey));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a submap containing all the keys from fromKey onwards.
|
||
* The submap supports all operations supported by the underlying
|
||
* map and all actions taking place on the submap are also reflected
|
||
* in the underlying map. A lock is obtained on the mutex prior to
|
||
* submap creation. The submap retains the thread-safe status of
|
||
* this map.
|
||
*
|
||
* @param fromKey the inclusive lower range of the submap.
|
||
* @return a submap from fromKey to <code>lastKey()</code>.
|
||
* @throws ClassCastException if fromKey is not comparable to the underlying
|
||
* map's contents.
|
||
* @throws IllegalArgumentException if fromKey is outside the map's range.
|
||
* @throws NullPointerException if fromKey is null. but the map does not allow
|
||
* null keys.
|
||
*/
|
||
public SortedMap tailMap(Object fromKey)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedMap(mutex, sm.tailMap(fromKey));
|
||
}
|
||
}
|
||
} // class SynchronizedSortedMap
|
||
|
||
/**
|
||
* Returns a synchronized (thread-safe) sorted set wrapper backed by the
|
||
* given set. Notice that element access through the iterator and through
|
||
* subviews are thread-safe, but if the set can be structurally modified
|
||
* (adding or removing elements) then you should synchronize around the
|
||
* iteration to avoid non-deterministic behavior:<br>
|
||
* <pre>
|
||
* SortedSet s = Collections.synchronizedSortedSet(new SortedSet(...));
|
||
* ...
|
||
* SortedSet s2 = s.headSet(foo); // safe outside a synchronized block
|
||
* synchronized (s) // synch on s, not s2
|
||
* {
|
||
* Iterator i = s2.iterator();
|
||
* while (i.hasNext())
|
||
* foo(i.next());
|
||
* }
|
||
* </pre><p>
|
||
*
|
||
* The returned SortedSet implements Serializable, but can only be
|
||
* serialized if the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the sorted set to wrap
|
||
* @return a synchronized view of the sorted set
|
||
* @see Serializable
|
||
*/
|
||
public static SortedSet synchronizedSortedSet(SortedSet s)
|
||
{
|
||
return new SynchronizedSortedSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSortedSet(SortedSet)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class SynchronizedSortedSet extends SynchronizedSet
|
||
implements SortedSet
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 8695801310862127406L;
|
||
|
||
/**
|
||
* The wrapped set; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped set
|
||
*/
|
||
private final SortedSet ss;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param ss the set to wrap
|
||
* @throws NullPointerException if ss is null
|
||
*/
|
||
SynchronizedSortedSet(SortedSet ss)
|
||
{
|
||
super(ss);
|
||
this.ss = ss;
|
||
}
|
||
|
||
/**
|
||
* Called only by trusted code to specify the mutex as well as the set.
|
||
* @param sync the mutex
|
||
* @param l the list
|
||
*/
|
||
SynchronizedSortedSet(Object sync, SortedSet ss)
|
||
{
|
||
super(sync, ss);
|
||
this.ss = ss;
|
||
}
|
||
|
||
/**
|
||
* Returns the comparator used in sorting the underlying set, or null if
|
||
* it is the elements' natural ordering. A lock is obtained on the mutex
|
||
* before the comparator is retrieved.
|
||
*
|
||
* @return the sorting comparator.
|
||
*/
|
||
public Comparator comparator()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return ss.comparator();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the first, lowest sorted, element from the underlying set.
|
||
* A lock is obtained on the mutex before the set is accessed.
|
||
*
|
||
* @return the first element.
|
||
* @throws NoSuchElementException if this set is empty.
|
||
*/
|
||
public Object first()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return ss.first();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a subset containing the element from the first
|
||
* element (as returned by <code>first()</code>) to
|
||
* the element before that specified. The subset supports all
|
||
* operations supported by the underlying set and all actions
|
||
* taking place on the subset are also reflected in the underlying
|
||
* set. A lock is obtained on the mutex prior to subset creation.
|
||
* This operation is equivalent to <code>subSet(first(), toElement)</code>.
|
||
* The subset retains the thread-safe status of this set.
|
||
*
|
||
* @param toElement the exclusive upper range of the subset.
|
||
* @return a subset from <code>first()</code> to the
|
||
* the element preceding toElement.
|
||
* @throws ClassCastException if toElement is not comparable to the underlying
|
||
* set's contents.
|
||
* @throws IllegalArgumentException if toElement is outside the set's range.
|
||
* @throws NullPointerException if toElement is null. but the set does not allow
|
||
* null elements.
|
||
*/
|
||
public SortedSet headSet(Object toElement)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedSet(mutex, ss.headSet(toElement));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns the last, highest sorted, element from the underlying set.
|
||
* A lock is obtained on the mutex before the set is accessed.
|
||
*
|
||
* @return the last element.
|
||
* @throws NoSuchElementException if this set is empty.
|
||
*/
|
||
public Object last()
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return ss.last();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a subset containing the elements from fromElement to
|
||
* the element before toElement. The subset supports all
|
||
* operations supported by the underlying set and all actions
|
||
* taking place on the subset are also reflected in the underlying
|
||
* set. A lock is obtained on the mutex prior to subset creation.
|
||
* The subset retains the thread-safe status of this set.
|
||
*
|
||
* @param fromElement the inclusive lower range of the subset.
|
||
* @param toElement the exclusive upper range of the subset.
|
||
* @return a subset from fromElement to the element preceding toElement.
|
||
* @throws ClassCastException if fromElement or toElement is not comparable
|
||
* to the underlying set's contents.
|
||
* @throws IllegalArgumentException if fromElement or toElement is outside the set's
|
||
* range.
|
||
* @throws NullPointerException if fromElement or toElement is null. but the set does
|
||
* not allow null elements.
|
||
*/
|
||
public SortedSet subSet(Object fromElement, Object toElement)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedSet(mutex,
|
||
ss.subSet(fromElement, toElement));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Returns a subset containing all the elements from fromElement onwards.
|
||
* The subset supports all operations supported by the underlying
|
||
* set and all actions taking place on the subset are also reflected
|
||
* in the underlying set. A lock is obtained on the mutex prior to
|
||
* subset creation. The subset retains the thread-safe status of
|
||
* this set.
|
||
*
|
||
* @param fromElement the inclusive lower range of the subset.
|
||
* @return a subset from fromElement to <code>last()</code>.
|
||
* @throws ClassCastException if fromElement is not comparable to the underlying
|
||
* set's contents.
|
||
* @throws IllegalArgumentException if fromElement is outside the set's range.
|
||
* @throws NullPointerException if fromElement is null. but the set does not allow
|
||
* null elements.
|
||
*/
|
||
public SortedSet tailSet(Object fromElement)
|
||
{
|
||
synchronized (mutex)
|
||
{
|
||
return new SynchronizedSortedSet(mutex, ss.tailSet(fromElement));
|
||
}
|
||
}
|
||
} // class SynchronizedSortedSet
|
||
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given collection. This allows
|
||
* "read-only" access, although changes in the backing collection show up
|
||
* in this view. Attempts to modify the collection directly or via iterators
|
||
* will fail with {@link UnsupportedOperationException}. Although this view
|
||
* prevents changes to the structure of the collection and its elements, the values
|
||
* referenced by the objects in the collection can still be modified.
|
||
* <p>
|
||
*
|
||
* Since the collection might be a List or a Set, and those have incompatible
|
||
* equals and hashCode requirements, this relies on Object's implementation
|
||
* rather than passing those calls on to the wrapped collection. The returned
|
||
* Collection implements Serializable, but can only be serialized if
|
||
* the collection it wraps is likewise Serializable.
|
||
*
|
||
* @param c the collection to wrap
|
||
* @return a read-only view of the collection
|
||
* @see Serializable
|
||
*/
|
||
public static Collection unmodifiableCollection(Collection c)
|
||
{
|
||
return new UnmodifiableCollection(c);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableCollection(Collection)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableCollection
|
||
implements Collection, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 1820017752578914078L;
|
||
|
||
/**
|
||
* The wrapped collection. Package visible for use by subclasses.
|
||
* @serial the real collection
|
||
*/
|
||
final Collection c;
|
||
|
||
/**
|
||
* Wrap a given collection.
|
||
* @param c the collection to wrap
|
||
* @throws NullPointerException if c is null
|
||
*/
|
||
UnmodifiableCollection(Collection c)
|
||
{
|
||
this.c = c;
|
||
if (c == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of elements to the underlying collection.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param o the object to add.
|
||
* @return <code>true</code> if the collection was modified as a result of this action.
|
||
* @throws UnsupportedOperationException as an unmodifiable collection does not
|
||
* support the add operation.
|
||
*/
|
||
public boolean add(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of a collection of elements to the underlying
|
||
* collection. This method never returns, throwing an exception instead.
|
||
*
|
||
* @param c the collection to add.
|
||
* @return <code>true</code> if the collection was modified as a result of this action.
|
||
* @throws UnsupportedOperationException as an unmodifiable collection does not
|
||
* support the <code>addAll</code> operation.
|
||
*/
|
||
public boolean addAll(Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the clearing of the underlying collection. This method never
|
||
* returns, throwing an exception instead.
|
||
*
|
||
* @throws UnsupportedOperationException as an unmodifiable collection does
|
||
* not support the <code>clear()</code> operation.
|
||
*/
|
||
public void clear()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Test whether the underlying collection contains a given object as one of its
|
||
* elements.
|
||
*
|
||
* @param o the element to look for.
|
||
* @return <code>true</code> if the underlying collection contains at least
|
||
* one element e such that
|
||
* <code>o == null ? e == null : o.equals(e)</code>.
|
||
* @throws ClassCastException if the type of o is not a valid type for the
|
||
* underlying collection.
|
||
* @throws NullPointerException if o is null and the underlying collection
|
||
* doesn't support null values.
|
||
*/
|
||
public boolean contains(Object o)
|
||
{
|
||
return c.contains(o);
|
||
}
|
||
|
||
/**
|
||
* Test whether the underlying collection contains every element in a given
|
||
* collection.
|
||
*
|
||
* @param c the collection to test for.
|
||
* @return <code>true</code> if for every element o in c, contains(o) would
|
||
* return <code>true</code>.
|
||
* @throws ClassCastException if the type of any element in c is not a valid
|
||
* type for the underlying collection.
|
||
* @throws NullPointerException if some element of c is null and the underlying
|
||
* collection does not support null values.
|
||
* @throws NullPointerException if c itself is null.
|
||
*/
|
||
public boolean containsAll(Collection c1)
|
||
{
|
||
return c.containsAll(c1);
|
||
}
|
||
|
||
/**
|
||
* Tests whether the underlying collection is empty, that is,
|
||
* if size() == 0.
|
||
*
|
||
* @return <code>true</code> if this collection contains no elements.
|
||
*/
|
||
public boolean isEmpty()
|
||
{
|
||
return c.isEmpty();
|
||
}
|
||
|
||
/**
|
||
* Obtain an Iterator over the underlying collection, which maintains
|
||
* its unmodifiable nature.
|
||
*
|
||
* @return an UnmodifiableIterator over the elements of the underlying
|
||
* collection, in any order.
|
||
*/
|
||
public Iterator iterator()
|
||
{
|
||
return new UnmodifiableIterator(c.iterator());
|
||
}
|
||
|
||
/**
|
||
* Blocks the removal of an object from the underlying collection.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param o The object to remove.
|
||
* @return <code>true</code> if the object was removed (i.e. the underlying
|
||
* collection returned 1 or more instances of o).
|
||
* @throws UnsupportedOperationException as an unmodifiable collection
|
||
* does not support the <code>remove()</code> operation.
|
||
*/
|
||
public boolean remove(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the removal of a collection of objects from the underlying
|
||
* collection. This method never returns, throwing an exception
|
||
* instead.
|
||
*
|
||
* @param c The collection of objects to remove.
|
||
* @return <code>true</code> if the collection was modified.
|
||
* @throws UnsupportedOperationException as an unmodifiable collection
|
||
* does not support the <code>removeAll()</code> operation.
|
||
*/
|
||
public boolean removeAll(Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the removal of all elements from the underlying collection,
|
||
* except those in the supplied collection. This method never returns,
|
||
* throwing an exception instead.
|
||
*
|
||
* @param c The collection of objects to retain.
|
||
* @return <code>true</code> if the collection was modified.
|
||
* @throws UnsupportedOperationException as an unmodifiable collection
|
||
* does not support the <code>retainAll()</code> operation.
|
||
*/
|
||
public boolean retainAll(Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Retrieves the number of elements in the underlying collection.
|
||
*
|
||
* @return the number of elements in the collection.
|
||
*/
|
||
public int size()
|
||
{
|
||
return c.size();
|
||
}
|
||
|
||
/**
|
||
* Copy the current contents of the underlying collection into an array.
|
||
*
|
||
* @return an array of type Object[] with a length equal to the size of the
|
||
* underlying collection and containing the elements currently in
|
||
* the underlying collection, in any order.
|
||
*/
|
||
public Object[] toArray()
|
||
{
|
||
return c.toArray();
|
||
}
|
||
|
||
/**
|
||
* Copy the current contents of the underlying collection into an array. If
|
||
* the array passed as an argument has length less than the size of the
|
||
* underlying collection, an array of the same run-time type as a, with a length
|
||
* equal to the size of the underlying collection, is allocated using reflection.
|
||
* Otherwise, a itself is used. The elements of the underlying collection are
|
||
* copied into it, and if there is space in the array, the following element is
|
||
* set to null. The resultant array is returned.
|
||
* Note: The fact that the following element is set to null is only useful
|
||
* if it is known that this collection does not contain any null elements.
|
||
*
|
||
* @param a the array to copy this collection into.
|
||
* @return an array containing the elements currently in the underlying
|
||
* collection, in any order.
|
||
* @throws ArrayStoreException if the type of any element of the
|
||
* collection is not a subtype of the element type of a.
|
||
*/
|
||
public Object[] toArray(Object[] a)
|
||
{
|
||
return c.toArray(a);
|
||
}
|
||
|
||
/**
|
||
* A textual representation of the unmodifiable collection.
|
||
*
|
||
* @return The unmodifiable collection in the form of a <code>String</code>.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return c.toString();
|
||
}
|
||
} // class UnmodifiableCollection
|
||
|
||
/**
|
||
* The implementation of the various iterator methods in the
|
||
* unmodifiable classes.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableIterator implements Iterator
|
||
{
|
||
/**
|
||
* The wrapped iterator.
|
||
*/
|
||
private final Iterator i;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper.
|
||
* @param i the wrapped iterator
|
||
*/
|
||
UnmodifiableIterator(Iterator i)
|
||
{
|
||
this.i = i;
|
||
}
|
||
|
||
/**
|
||
* Obtains the next element in the underlying collection.
|
||
*
|
||
* @return the next element in the collection.
|
||
* @throws NoSuchElementException if there are no more elements.
|
||
*/
|
||
public Object next()
|
||
{
|
||
return i.next();
|
||
}
|
||
/**
|
||
* Tests whether there are still elements to be retrieved from the
|
||
* underlying collection by <code>next()</code>. When this method
|
||
* returns <code>true</code>, an exception will not be thrown on calling
|
||
* <code>next()</code>.
|
||
*
|
||
* @return <code>true</code> if there is at least one more element in the underlying
|
||
* collection.
|
||
*/
|
||
public boolean hasNext()
|
||
{
|
||
return i.hasNext();
|
||
}
|
||
|
||
/**
|
||
* Blocks the removal of elements from the underlying collection by the
|
||
* iterator.
|
||
*
|
||
* @throws UnsupportedOperationException as an unmodifiable collection
|
||
* does not support the removal of elements by its iterator.
|
||
*/
|
||
public void remove()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
} // class UnmodifiableIterator
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given list. This allows
|
||
* "read-only" access, although changes in the backing list show up
|
||
* in this view. Attempts to modify the list directly, via iterators, or
|
||
* via sublists, will fail with {@link UnsupportedOperationException}.
|
||
* Although this view prevents changes to the structure of the list and
|
||
* its elements, the values referenced by the objects in the list can
|
||
* still be modified.
|
||
* <p>
|
||
*
|
||
* The returned List implements Serializable, but can only be serialized if
|
||
* the list it wraps is likewise Serializable. In addition, if the wrapped
|
||
* list implements RandomAccess, this does too.
|
||
*
|
||
* @param l the list to wrap
|
||
* @return a read-only view of the list
|
||
* @see Serializable
|
||
* @see RandomAccess
|
||
*/
|
||
public static List unmodifiableList(List l)
|
||
{
|
||
if (l instanceof RandomAccess)
|
||
return new UnmodifiableRandomAccessList(l);
|
||
return new UnmodifiableList(l);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableList(List)} for sequential
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableList extends UnmodifiableCollection
|
||
implements List
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -283967356065247728L;
|
||
|
||
|
||
/**
|
||
* The wrapped list; stored both here and in the superclass to avoid
|
||
* excessive casting. Package visible for use by subclass.
|
||
* @serial the wrapped list
|
||
*/
|
||
final List list;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
UnmodifiableList(List l)
|
||
{
|
||
super(l);
|
||
list = l;
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of an element to the underlying
|
||
* list at a specific index. This method never returns,
|
||
* throwing an exception instead.
|
||
*
|
||
* @param index The index at which to place the new element.
|
||
* @param o the object to add.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* list doesn't support the <code>add()</code> operation.
|
||
*/
|
||
public void add(int index, Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of a collection of elements to the
|
||
* underlying list at a specific index. This method never
|
||
* returns, throwing an exception instead.
|
||
*
|
||
* @param index The index at which to place the new element.
|
||
* @param c the collections of objects to add.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* list doesn't support the <code>addAll()</code> operation.
|
||
*/
|
||
public boolean addAll(int index, Collection c)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the object, o, is an instance of
|
||
* <code>List</code> with the same size and elements
|
||
* as the underlying list.
|
||
*
|
||
* @param o The object to compare.
|
||
* @return <code>true</code> if o is equivalent to the underlying list.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return list.equals(o);
|
||
}
|
||
|
||
/**
|
||
* Retrieves the element at a given index in the underlying list.
|
||
*
|
||
* @param index the index of the element to be returned
|
||
* @return the element at index index in this list
|
||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||
*/
|
||
public Object get(int index)
|
||
{
|
||
return list.get(index);
|
||
}
|
||
|
||
/**
|
||
* Computes the hash code for the underlying list.
|
||
* The exact computation is described in the documentation
|
||
* of the <code>List</code> interface.
|
||
*
|
||
* @return The hash code of the underlying list.
|
||
* @see List#hashCode()
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return list.hashCode();
|
||
}
|
||
|
||
/**
|
||
* Obtain the first index at which a given object is to be found in the
|
||
* underlying list.
|
||
*
|
||
* @param o the object to search for
|
||
* @return the least integer n such that <code>o == null ? get(n) == null :
|
||
* o.equals(get(n))</code>, or -1 if there is no such index.
|
||
* @throws ClassCastException if the type of o is not a valid
|
||
* type for the underlying list.
|
||
* @throws NullPointerException if o is null and the underlying
|
||
* list does not support null values.
|
||
*/
|
||
public int indexOf(Object o)
|
||
{
|
||
return list.indexOf(o);
|
||
}
|
||
|
||
/**
|
||
* Obtain the last index at which a given object is to be found in the
|
||
* underlying list.
|
||
*
|
||
* @return the greatest integer n such that <code>o == null ? get(n) == null
|
||
* : o.equals(get(n))</code>, or -1 if there is no such index.
|
||
* @throws ClassCastException if the type of o is not a valid
|
||
* type for the underlying list.
|
||
* @throws NullPointerException if o is null and the underlying
|
||
* list does not support null values.
|
||
*/
|
||
public int lastIndexOf(Object o)
|
||
{
|
||
return list.lastIndexOf(o);
|
||
}
|
||
|
||
/**
|
||
* Obtains a list iterator over the underlying list, starting at the beginning
|
||
* and maintaining the unmodifiable nature of this list.
|
||
*
|
||
* @return a <code>UnmodifiableListIterator</code> over the elements of the
|
||
* underlying list, in order, starting at the beginning.
|
||
*/
|
||
public ListIterator listIterator()
|
||
{
|
||
return new UnmodifiableListIterator(list.listIterator());
|
||
}
|
||
|
||
/**
|
||
* Obtains a list iterator over the underlying list, starting at the specified
|
||
* index and maintaining the unmodifiable nature of this list. An initial call
|
||
* to <code>next()</code> will retrieve the element at the specified index,
|
||
* and an initial call to <code>previous()</code> will retrieve the element
|
||
* at index - 1.
|
||
*
|
||
*
|
||
* @param index the position, between 0 and size() inclusive, to begin the
|
||
* iteration from.
|
||
* @return a <code>UnmodifiableListIterator</code> over the elements of the
|
||
* underlying list, in order, starting at the specified index.
|
||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||
*/
|
||
public ListIterator listIterator(int index)
|
||
{
|
||
return new UnmodifiableListIterator(list.listIterator(index));
|
||
}
|
||
|
||
/**
|
||
* Blocks the removal of the element at the specified index.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param index The index of the element to remove.
|
||
* @return the removed element.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* list does not support the <code>remove()</code>
|
||
* operation.
|
||
*/
|
||
public Object remove(int index)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the replacement of the element at the specified index.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param index The index of the element to replace.
|
||
* @param o The new object to place at the specified index.
|
||
* @return the replaced element.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* list does not support the <code>set()</code>
|
||
* operation.
|
||
*/
|
||
public Object set(int index, Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Obtain a List view of a subsection of the underlying list, from
|
||
* fromIndex (inclusive) to toIndex (exclusive). If the two indices
|
||
* are equal, the sublist is empty. The returned list will be
|
||
* unmodifiable, like this list. Changes to the elements of the
|
||
* returned list will be reflected in the underlying list. No structural
|
||
* modifications can take place in either list.
|
||
*
|
||
* @param fromIndex the index that the returned list should start from
|
||
* (inclusive).
|
||
* @param toIndex the index that the returned list should go to (exclusive).
|
||
* @return a List backed by a subsection of the underlying list.
|
||
* @throws IndexOutOfBoundsException if fromIndex < 0
|
||
* || toIndex > size() || fromIndex > toIndex.
|
||
*/
|
||
public List subList(int fromIndex, int toIndex)
|
||
{
|
||
return unmodifiableList(list.subList(fromIndex, toIndex));
|
||
}
|
||
} // class UnmodifiableList
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableList(List)} for random-access
|
||
* lists. This class name is required for compatibility with Sun's JDK
|
||
* serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class UnmodifiableRandomAccessList
|
||
extends UnmodifiableList implements RandomAccess
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -2542308836966382001L;
|
||
|
||
/**
|
||
* Wrap a given list.
|
||
* @param l the list to wrap
|
||
* @throws NullPointerException if l is null
|
||
*/
|
||
UnmodifiableRandomAccessList(List l)
|
||
{
|
||
super(l);
|
||
}
|
||
} // class UnmodifiableRandomAccessList
|
||
|
||
/**
|
||
* The implementation of {@link UnmodifiableList#listIterator()}.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class UnmodifiableListIterator
|
||
extends UnmodifiableIterator implements ListIterator
|
||
{
|
||
/**
|
||
* The wrapped iterator, stored both here and in the superclass to
|
||
* avoid excessive casting.
|
||
*/
|
||
private final ListIterator li;
|
||
|
||
/**
|
||
* Only trusted code creates a wrapper.
|
||
* @param li the wrapped iterator
|
||
*/
|
||
UnmodifiableListIterator(ListIterator li)
|
||
{
|
||
super(li);
|
||
this.li = li;
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of an object to the list underlying this iterator.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param o The object to add.
|
||
* @throws UnsupportedOperationException as the iterator of an unmodifiable
|
||
* list does not support the <code>add()</code> operation.
|
||
*/
|
||
public void add(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Tests whether there are still elements to be retrieved from the
|
||
* underlying collection by <code>previous()</code>. When this method
|
||
* returns <code>true</code>, an exception will not be thrown on calling
|
||
* <code>previous()</code>.
|
||
*
|
||
* @return <code>true</code> if there is at least one more element prior to the
|
||
* current position in the underlying list.
|
||
*/
|
||
public boolean hasPrevious()
|
||
{
|
||
return li.hasPrevious();
|
||
}
|
||
|
||
/**
|
||
* Find the index of the element that would be returned by a call to next.
|
||
* If <code>hasNext()</code> returns <code>false</code>, this returns the list size.
|
||
*
|
||
* @return the index of the element that would be returned by
|
||
* <code>next()</code>.
|
||
*/
|
||
public int nextIndex()
|
||
{
|
||
return li.nextIndex();
|
||
}
|
||
|
||
/**
|
||
* Obtains the previous element in the underlying list.
|
||
*
|
||
* @return the previous element in the list.
|
||
* @throws NoSuchElementException if there are no more prior elements.
|
||
*/
|
||
public Object previous()
|
||
{
|
||
return li.previous();
|
||
}
|
||
|
||
/**
|
||
* Find the index of the element that would be returned by a call to
|
||
* previous. If <code>hasPrevious()</code> returns <code>false</code>,
|
||
* this returns -1.
|
||
*
|
||
* @return the index of the element that would be returned by
|
||
* <code>previous()</code>.
|
||
*/
|
||
public int previousIndex()
|
||
{
|
||
return li.previousIndex();
|
||
}
|
||
|
||
/**
|
||
* Blocks the replacement of an element in the list underlying this
|
||
* iterator. This method never returns, throwing an exception instead.
|
||
*
|
||
* @param o The new object to replace the existing one.
|
||
* @throws UnsupportedOperationException as the iterator of an unmodifiable
|
||
* list does not support the <code>set()</code> operation.
|
||
*/
|
||
public void set(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
} // class UnmodifiableListIterator
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given map. This allows "read-only"
|
||
* access, although changes in the backing map show up in this view.
|
||
* Attempts to modify the map directly, or via collection views or their
|
||
* iterators will fail with {@link UnsupportedOperationException}.
|
||
* Although this view prevents changes to the structure of the map and its
|
||
* entries, the values referenced by the objects in the map can still be
|
||
* modified.
|
||
* <p>
|
||
*
|
||
* The returned Map implements Serializable, but can only be serialized if
|
||
* the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the map to wrap
|
||
* @return a read-only view of the map
|
||
* @see Serializable
|
||
*/
|
||
public static Map unmodifiableMap(Map m)
|
||
{
|
||
return new UnmodifiableMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableMap(Map)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableMap implements Map, Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -1034234728574286014L;
|
||
|
||
/**
|
||
* The wrapped map.
|
||
* @serial the real map
|
||
*/
|
||
private final Map m;
|
||
|
||
/**
|
||
* Cache the entry set.
|
||
*/
|
||
private transient Set entries;
|
||
|
||
/**
|
||
* Cache the key set.
|
||
*/
|
||
private transient Set keys;
|
||
|
||
/**
|
||
* Cache the value collection.
|
||
*/
|
||
private transient Collection values;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param m the map to wrap
|
||
* @throws NullPointerException if m is null
|
||
*/
|
||
UnmodifiableMap(Map m)
|
||
{
|
||
this.m = m;
|
||
if (m == null)
|
||
throw new NullPointerException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the clearing of entries from the underlying map.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* map does not support the <code>clear()</code> operation.
|
||
*/
|
||
public void clear()
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the underlying map contains a mapping for
|
||
* the given key.
|
||
*
|
||
* @param key the key to search for
|
||
* @return <code>true</code> if the map contains the key
|
||
* @throws ClassCastException if the key is of an inappropriate type
|
||
* @throws NullPointerException if key is <code>null</code> but the map
|
||
* does not permit null keys
|
||
*/
|
||
public boolean containsKey(Object key)
|
||
{
|
||
return m.containsKey(key);
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the underlying map contains at least one mapping with
|
||
* the given value. In other words, it returns <code>true</code> if a value v exists where
|
||
* <code>(value == null ? v == null : value.equals(v))</code>. This usually
|
||
* requires linear time.
|
||
*
|
||
* @param value the value to search for
|
||
* @return <code>true</code> if the map contains the value
|
||
* @throws ClassCastException if the type of the value is not a valid type
|
||
* for this map.
|
||
* @throws NullPointerException if the value is null and the map doesn't
|
||
* support null values.
|
||
*/
|
||
public boolean containsValue(Object value)
|
||
{
|
||
return m.containsValue(value);
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable set view of the entries in the underlying map.
|
||
* Each element in the set is a unmodifiable variant of <code>Map.Entry</code>.
|
||
* The set is backed by the map, so that changes in one show up in the other.
|
||
* Modifications made while an iterator is in progress cause undefined
|
||
* behavior. These modifications are again limited to the values of
|
||
* the objects.
|
||
*
|
||
* @return the unmodifiable set view of all mapping entries.
|
||
* @see Map.Entry
|
||
*/
|
||
public Set entrySet()
|
||
{
|
||
if (entries == null)
|
||
entries = new UnmodifiableEntrySet(m.entrySet());
|
||
return entries;
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link UnmodifiableMap#entrySet()}. This class
|
||
* name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static final class UnmodifiableEntrySet extends UnmodifiableSet
|
||
implements Serializable
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = 7854390611657943733L;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param s the set to wrap
|
||
*/
|
||
UnmodifiableEntrySet(Set s)
|
||
{
|
||
super(s);
|
||
}
|
||
|
||
// The iterator must return unmodifiable map entries.
|
||
public Iterator iterator()
|
||
{
|
||
return new UnmodifiableIterator(c.iterator())
|
||
{
|
||
/**
|
||
* Obtains the next element from the underlying set of
|
||
* map entries.
|
||
*
|
||
* @return the next element in the collection.
|
||
* @throws NoSuchElementException if there are no more elements.
|
||
*/
|
||
public Object next()
|
||
{
|
||
final Map.Entry e = (Map.Entry) super.next();
|
||
return new Map.Entry()
|
||
{
|
||
/**
|
||
* Returns <code>true</code> if the object, o, is also a map entry with an
|
||
* identical key and value.
|
||
*
|
||
* @param o the object to compare.
|
||
* @return <code>true</code> if o is an equivalent map entry.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return e.equals(o);
|
||
}
|
||
|
||
/**
|
||
* Returns the key of this map entry.
|
||
*
|
||
* @return the key.
|
||
*/
|
||
public Object getKey()
|
||
{
|
||
return e.getKey();
|
||
}
|
||
|
||
/**
|
||
* Returns the value of this map entry.
|
||
*
|
||
* @return the value.
|
||
*/
|
||
public Object getValue()
|
||
{
|
||
return e.getValue();
|
||
}
|
||
|
||
/**
|
||
* Computes the hash code of this map entry.
|
||
* The computation is described in the <code>Map</code>
|
||
* interface documentation.
|
||
*
|
||
* @return the hash code of this entry.
|
||
* @see Map#hashCode()
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return e.hashCode();
|
||
}
|
||
|
||
/**
|
||
* Blocks the alteration of the value of this map entry.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param value The new value.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* map entry does not support the <code>setValue()</code>
|
||
* operation.
|
||
*/
|
||
public Object setValue(Object value)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Returns a textual representation of the map entry.
|
||
*
|
||
* @return The map entry as a <code>String</code>.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return e.toString();
|
||
}
|
||
};
|
||
}
|
||
};
|
||
}
|
||
} // class UnmodifiableEntrySet
|
||
|
||
/**
|
||
* Returns <code>true</code> if the object, o, is also an instance
|
||
* of <code>Map</code> with an equal set of map entries.
|
||
*
|
||
* @param o The object to compare.
|
||
* @return <code>true</code> if o is an equivalent map.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return m.equals(o);
|
||
}
|
||
|
||
/**
|
||
* Returns the value associated with the supplied key or
|
||
* null if no such mapping exists. An ambiguity can occur
|
||
* if null values are accepted by the underlying map.
|
||
* In this case, <code>containsKey()</code> can be used
|
||
* to separate the two possible cases of a null result.
|
||
*
|
||
* @param key The key to look up.
|
||
* @return the value associated with the key, or null if key not in map.
|
||
* @throws ClassCastException if the key is an inappropriate type.
|
||
* @throws NullPointerException if this map does not accept null keys.
|
||
* @see #containsKey(Object)
|
||
*/
|
||
public Object get(Object key)
|
||
{
|
||
return m.get(key);
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of a new entry to the underlying map.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param key The new key.
|
||
* @param value The new value.
|
||
* @return the previous value of the key, or null if there was no mapping.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* map does not support the <code>put()</code> operation.
|
||
*/
|
||
public Object put(Object key, Object value)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Computes the hash code for the underlying map, as the sum
|
||
* of the hash codes of all entries.
|
||
*
|
||
* @return The hash code of the underlying map.
|
||
* @see Map.Entry#hashCode()
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return m.hashCode();
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the underlying map contains no entries.
|
||
*
|
||
* @return <code>true</code> if the map is empty.
|
||
*/
|
||
public boolean isEmpty()
|
||
{
|
||
return m.isEmpty();
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable set view of the keys in the underlying map.
|
||
* The set is backed by the map, so that changes in one show up in the other.
|
||
* Modifications made while an iterator is in progress cause undefined
|
||
* behavior. These modifications are again limited to the values of
|
||
* the keys.
|
||
*
|
||
* @return the set view of all keys.
|
||
*/
|
||
public Set keySet()
|
||
{
|
||
if (keys == null)
|
||
keys = new UnmodifiableSet(m.keySet());
|
||
return keys;
|
||
}
|
||
|
||
/**
|
||
* Blocks the addition of the entries in the supplied map.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param m The map, the entries of which should be added
|
||
* to the underlying map.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* map does not support the <code>putAll</code> operation.
|
||
*/
|
||
public void putAll(Map m)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
/**
|
||
* Blocks the removal of an entry from the map.
|
||
* This method never returns, throwing an exception instead.
|
||
*
|
||
* @param o The key of the entry to remove.
|
||
* @return The value the key was associated with, or null
|
||
* if no such mapping existed. Null is also returned
|
||
* if the removed entry had a null key.
|
||
* @throws UnsupportedOperationException as an unmodifiable
|
||
* map does not support the <code>remove</code> operation.
|
||
*/
|
||
public Object remove(Object o)
|
||
{
|
||
throw new UnsupportedOperationException();
|
||
}
|
||
|
||
|
||
/**
|
||
* Returns the number of key-value mappings in the underlying map.
|
||
* If there are more than Integer.MAX_VALUE mappings, Integer.MAX_VALUE
|
||
* is returned.
|
||
*
|
||
* @return the number of mappings.
|
||
*/
|
||
public int size()
|
||
{
|
||
return m.size();
|
||
}
|
||
|
||
/**
|
||
* Returns a textual representation of the map.
|
||
*
|
||
* @return The map in the form of a <code>String</code>.
|
||
*/
|
||
public String toString()
|
||
{
|
||
return m.toString();
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable collection view of the values in the underlying map.
|
||
* The collection is backed by the map, so that changes in one show up in the other.
|
||
* Modifications made while an iterator is in progress cause undefined
|
||
* behavior. These modifications are again limited to the values of
|
||
* the keys.
|
||
*
|
||
* @return the collection view of all values.
|
||
*/
|
||
public Collection values()
|
||
{
|
||
if (values == null)
|
||
values = new UnmodifiableCollection(m.values());
|
||
return values;
|
||
}
|
||
} // class UnmodifiableMap
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given set. This allows
|
||
* "read-only" access, although changes in the backing set show up
|
||
* in this view. Attempts to modify the set directly or via iterators
|
||
* will fail with {@link UnsupportedOperationException}.
|
||
* Although this view prevents changes to the structure of the set and its
|
||
* entries, the values referenced by the objects in the set can still be
|
||
* modified.
|
||
* <p>
|
||
*
|
||
* The returned Set implements Serializable, but can only be serialized if
|
||
* the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the set to wrap
|
||
* @return a read-only view of the set
|
||
* @see Serializable
|
||
*/
|
||
public static Set unmodifiableSet(Set s)
|
||
{
|
||
return new UnmodifiableSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableSet(Set)}. This class
|
||
* name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableSet extends UnmodifiableCollection
|
||
implements Set
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -9215047833775013803L;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param s the set to wrap
|
||
* @throws NullPointerException if s is null
|
||
*/
|
||
UnmodifiableSet(Set s)
|
||
{
|
||
super(s);
|
||
}
|
||
|
||
/**
|
||
* Returns <code>true</code> if the object, o, is also an instance of
|
||
* <code>Set</code> of the same size and with the same entries.
|
||
*
|
||
* @return <code>true</code> if o is an equivalent set.
|
||
*/
|
||
public boolean equals(Object o)
|
||
{
|
||
return c.equals(o);
|
||
}
|
||
|
||
/**
|
||
* Computes the hash code of this set, as the sum of the
|
||
* hash codes of all elements within the set.
|
||
*
|
||
* @return the hash code of the set.
|
||
*/
|
||
public int hashCode()
|
||
{
|
||
return c.hashCode();
|
||
}
|
||
} // class UnmodifiableSet
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given sorted map. This allows
|
||
* "read-only" access, although changes in the backing map show up in this
|
||
* view. Attempts to modify the map directly, via subviews, via collection
|
||
* views, or iterators, will fail with {@link UnsupportedOperationException}.
|
||
* Although this view prevents changes to the structure of the map and its
|
||
* entries, the values referenced by the objects in the map can still be
|
||
* modified.
|
||
* <p>
|
||
*
|
||
* The returned SortedMap implements Serializable, but can only be
|
||
* serialized if the map it wraps is likewise Serializable.
|
||
*
|
||
* @param m the map to wrap
|
||
* @return a read-only view of the map
|
||
* @see Serializable
|
||
*/
|
||
public static SortedMap unmodifiableSortedMap(SortedMap m)
|
||
{
|
||
return new UnmodifiableSortedMap(m);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #unmodifiableSortedMap(SortedMap)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableSortedMap extends UnmodifiableMap
|
||
implements SortedMap
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -8806743815996713206L;
|
||
|
||
/**
|
||
* The wrapped map; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped map
|
||
*/
|
||
private final SortedMap sm;
|
||
|
||
/**
|
||
* Wrap a given map.
|
||
* @param sm the map to wrap
|
||
* @throws NullPointerException if sm is null
|
||
*/
|
||
UnmodifiableSortedMap(SortedMap sm)
|
||
{
|
||
super(sm);
|
||
this.sm = sm;
|
||
}
|
||
|
||
/**
|
||
* Returns the comparator used in sorting the underlying map,
|
||
* or null if it is the keys' natural ordering.
|
||
*
|
||
* @return the sorting comparator.
|
||
*/
|
||
public Comparator comparator()
|
||
{
|
||
return sm.comparator();
|
||
}
|
||
|
||
/**
|
||
* Returns the first (lowest sorted) key in the map.
|
||
*
|
||
* @return the first key.
|
||
* @throws NoSuchElementException if this map is empty.
|
||
*/
|
||
public Object firstKey()
|
||
{
|
||
return sm.firstKey();
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable view of the portion of the map strictly less
|
||
* than toKey. The view is backed by the underlying map, so changes in
|
||
* one show up in the other. The submap supports all optional operations
|
||
* of the original. This operation is equivalent to
|
||
* <code>subMap(firstKey(), toKey)</code>.
|
||
* <p>
|
||
*
|
||
* The returned map throws an IllegalArgumentException any time a key is
|
||
* used which is out of the range of toKey. Note that the endpoint, toKey,
|
||
* is not included; if you want this value to be included, pass its successor
|
||
* object in to toKey. For example, for Integers, you could request
|
||
* <code>headMap(new Integer(limit.intValue() + 1))</code>.
|
||
*
|
||
* @param toKey the exclusive upper range of the submap.
|
||
* @return the submap.
|
||
* @throws ClassCastException if toKey is not comparable to the map contents.
|
||
* @throws IllegalArgumentException if this is a subMap, and toKey is out
|
||
* of range.
|
||
* @throws NullPointerException if toKey is null but the map does not allow
|
||
* null keys.
|
||
*/
|
||
public SortedMap headMap(Object toKey)
|
||
{
|
||
return new UnmodifiableSortedMap(sm.headMap(toKey));
|
||
}
|
||
|
||
/**
|
||
* Returns the last (highest sorted) key in the map.
|
||
*
|
||
* @return the last key.
|
||
* @throws NoSuchElementException if this map is empty.
|
||
*/
|
||
public Object lastKey()
|
||
{
|
||
return sm.lastKey();
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable view of the portion of the map greater than or
|
||
* equal to fromKey, and strictly less than toKey. The view is backed by
|
||
* the underlying map, so changes in one show up in the other. The submap
|
||
* supports all optional operations of the original.
|
||
* <p>
|
||
*
|
||
* The returned map throws an IllegalArgumentException any time a key is
|
||
* used which is out of the range of fromKey and toKey. Note that the
|
||
* lower endpoint is included, but the upper is not; if you want to
|
||
* change the inclusion or exclusion of an endpoint, pass its successor
|
||
* object in instead. For example, for Integers, you could request
|
||
* <code>subMap(new Integer(lowlimit.intValue() + 1),
|
||
* new Integer(highlimit.intValue() + 1))</code> to reverse
|
||
* the inclusiveness of both endpoints.
|
||
*
|
||
* @param fromKey the inclusive lower range of the submap.
|
||
* @param toKey the exclusive upper range of the submap.
|
||
* @return the submap.
|
||
* @throws ClassCastException if fromKey or toKey is not comparable to
|
||
* the map contents.
|
||
* @throws IllegalArgumentException if this is a subMap, and fromKey or
|
||
* toKey is out of range.
|
||
* @throws NullPointerException if fromKey or toKey is null but the map
|
||
* does not allow null keys.
|
||
*/
|
||
public SortedMap subMap(Object fromKey, Object toKey)
|
||
{
|
||
return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey));
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable view of the portion of the map greater than or
|
||
* equal to fromKey. The view is backed by the underlying map, so changes
|
||
* in one show up in the other. The submap supports all optional operations
|
||
* of the original.
|
||
* <p>
|
||
*
|
||
* The returned map throws an IllegalArgumentException any time a key is
|
||
* used which is out of the range of fromKey. Note that the endpoint, fromKey, is
|
||
* included; if you do not want this value to be included, pass its successor object in
|
||
* to fromKey. For example, for Integers, you could request
|
||
* <code>tailMap(new Integer(limit.intValue() + 1))</code>.
|
||
*
|
||
* @param fromKey the inclusive lower range of the submap
|
||
* @return the submap
|
||
* @throws ClassCastException if fromKey is not comparable to the map
|
||
* contents
|
||
* @throws IllegalArgumentException if this is a subMap, and fromKey is out
|
||
* of range
|
||
* @throws NullPointerException if fromKey is null but the map does not allow
|
||
* null keys
|
||
*/
|
||
public SortedMap tailMap(Object fromKey)
|
||
{
|
||
return new UnmodifiableSortedMap(sm.tailMap(fromKey));
|
||
}
|
||
} // class UnmodifiableSortedMap
|
||
|
||
/**
|
||
* Returns an unmodifiable view of the given sorted set. This allows
|
||
* "read-only" access, although changes in the backing set show up
|
||
* in this view. Attempts to modify the set directly, via subsets, or via
|
||
* iterators, will fail with {@link UnsupportedOperationException}.
|
||
* Although this view prevents changes to the structure of the set and its
|
||
* entries, the values referenced by the objects in the set can still be
|
||
* modified.
|
||
* <p>
|
||
*
|
||
* The returns SortedSet implements Serializable, but can only be
|
||
* serialized if the set it wraps is likewise Serializable.
|
||
*
|
||
* @param s the set to wrap
|
||
* @return a read-only view of the set
|
||
* @see Serializable
|
||
*/
|
||
public static SortedSet unmodifiableSortedSet(SortedSet s)
|
||
{
|
||
return new UnmodifiableSortedSet(s);
|
||
}
|
||
|
||
/**
|
||
* The implementation of {@link #synchronizedSortedMap(SortedMap)}. This
|
||
* class name is required for compatibility with Sun's JDK serializability.
|
||
*
|
||
* @author Eric Blake (ebb9@email.byu.edu)
|
||
*/
|
||
private static class UnmodifiableSortedSet extends UnmodifiableSet
|
||
implements SortedSet
|
||
{
|
||
/**
|
||
* Compatible with JDK 1.4.
|
||
*/
|
||
private static final long serialVersionUID = -4929149591599911165L;
|
||
|
||
/**
|
||
* The wrapped set; stored both here and in the superclass to avoid
|
||
* excessive casting.
|
||
* @serial the wrapped set
|
||
*/
|
||
private SortedSet ss;
|
||
|
||
/**
|
||
* Wrap a given set.
|
||
* @param ss the set to wrap
|
||
* @throws NullPointerException if ss is null
|
||
*/
|
||
UnmodifiableSortedSet(SortedSet ss)
|
||
{
|
||
super(ss);
|
||
this.ss = ss;
|
||
}
|
||
|
||
/**
|
||
* Returns the comparator used in sorting the underlying set,
|
||
* or null if it is the elements' natural ordering.
|
||
*
|
||
* @return the sorting comparator
|
||
*/
|
||
public Comparator comparator()
|
||
{
|
||
return ss.comparator();
|
||
}
|
||
|
||
/**
|
||
* Returns the first (lowest sorted) element in the underlying
|
||
* set.
|
||
*
|
||
* @return the first element.
|
||
* @throws NoSuchElementException if the set is empty.
|
||
*/
|
||
public Object first()
|
||
{
|
||
return ss.first();
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable view of the portion of the set strictly
|
||
* less than toElement. The view is backed by the underlying set,
|
||
* so changes in one show up in the other. The subset supports
|
||
* all optional operations of the original. This operation
|
||
* is equivalent to <code>subSet(first(), toElement)</code>.
|
||
* <p>
|
||
*
|
||
* The returned set throws an IllegalArgumentException any time an element is
|
||
* used which is out of the range of toElement. Note that the endpoint, toElement,
|
||
* is not included; if you want this value included, pass its successor object in to
|
||
* toElement. For example, for Integers, you could request
|
||
* <code>headSet(new Integer(limit.intValue() + 1))</code>.
|
||
*
|
||
* @param toElement the exclusive upper range of the subset
|
||
* @return the subset.
|
||
* @throws ClassCastException if toElement is not comparable to the set
|
||
* contents.
|
||
* @throws IllegalArgumentException if this is a subSet, and toElement is out
|
||
* of range.
|
||
* @throws NullPointerException if toElement is null but the set does not
|
||
* allow null elements.
|
||
*/
|
||
public SortedSet headSet(Object toElement)
|
||
{
|
||
return new UnmodifiableSortedSet(ss.headSet(toElement));
|
||
}
|
||
|
||
/**
|
||
* Returns the last (highest sorted) element in the underlying
|
||
* set.
|
||
*
|
||
* @return the last element.
|
||
* @throws NoSuchElementException if the set is empty.
|
||
*/
|
||
public Object last()
|
||
{
|
||
return ss.last();
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable view of the portion of the set greater than or
|
||
* equal to fromElement, and strictly less than toElement. The view is backed by
|
||
* the underlying set, so changes in one show up in the other. The subset
|
||
* supports all optional operations of the original.
|
||
* <p>
|
||
*
|
||
* The returned set throws an IllegalArgumentException any time an element is
|
||
* used which is out of the range of fromElement and toElement. Note that the
|
||
* lower endpoint is included, but the upper is not; if you want to
|
||
* change the inclusion or exclusion of an endpoint, pass its successor
|
||
* object in instead. For example, for Integers, you can request
|
||
* <code>subSet(new Integer(lowlimit.intValue() + 1),
|
||
* new Integer(highlimit.intValue() + 1))</code> to reverse
|
||
* the inclusiveness of both endpoints.
|
||
*
|
||
* @param fromElement the inclusive lower range of the subset.
|
||
* @param toElement the exclusive upper range of the subset.
|
||
* @return the subset.
|
||
* @throws ClassCastException if fromElement or toElement is not comparable
|
||
* to the set contents.
|
||
* @throws IllegalArgumentException if this is a subSet, and fromElement or
|
||
* toElement is out of range.
|
||
* @throws NullPointerException if fromElement or toElement is null but the
|
||
* set does not allow null elements.
|
||
*/
|
||
public SortedSet subSet(Object fromElement, Object toElement)
|
||
{
|
||
return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement));
|
||
}
|
||
|
||
/**
|
||
* Returns a unmodifiable view of the portion of the set greater than or equal to
|
||
* fromElement. The view is backed by the underlying set, so changes in one show up
|
||
* in the other. The subset supports all optional operations of the original.
|
||
* <p>
|
||
*
|
||
* The returned set throws an IllegalArgumentException any time an element is
|
||
* used which is out of the range of fromElement. Note that the endpoint,
|
||
* fromElement, is included; if you do not want this value to be included, pass its
|
||
* successor object in to fromElement. For example, for Integers, you could request
|
||
* <code>tailSet(new Integer(limit.intValue() + 1))</code>.
|
||
*
|
||
* @param fromElement the inclusive lower range of the subset
|
||
* @return the subset.
|
||
* @throws ClassCastException if fromElement is not comparable to the set
|
||
* contents.
|
||
* @throws IllegalArgumentException if this is a subSet, and fromElement is
|
||
* out of range.
|
||
* @throws NullPointerException if fromElement is null but the set does not
|
||
* allow null elements.
|
||
*/
|
||
public SortedSet tailSet(Object fromElement)
|
||
{
|
||
return new UnmodifiableSortedSet(ss.tailSet(fromElement));
|
||
}
|
||
} // class UnmodifiableSortedSet
|
||
} // class Collections
|