1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.util; 19 20import java.io.IOException; 21import java.io.ObjectInputStream; 22import java.io.ObjectOutputStream; 23import java.io.Serializable; 24 25/** 26 * TreeSet is an implementation of SortedSet. All optional operations (adding 27 * and removing) are supported. The elements can be any objects which are 28 * comparable to each other either using their natural order or a specified 29 * Comparator. 30 * 31 * @since 1.2 32 */ 33public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, 34 Cloneable, Serializable { 35 36 private static final long serialVersionUID = -2479143000061671589L; 37 38 /** Keys are this set's elements. Values are always Boolean.TRUE */ 39 private transient NavigableMap<E, Object> backingMap; 40 41 private transient NavigableSet<E> descendingSet; 42 43 TreeSet(NavigableMap<E, Object> map) { 44 backingMap = map; 45 } 46 47 /** 48 * Constructs a new empty instance of {@code TreeSet} which uses natural 49 * ordering. 50 */ 51 public TreeSet() { 52 backingMap = new TreeMap<E, Object>(); 53 } 54 55 /** 56 * Constructs a new instance of {@code TreeSet} which uses natural ordering 57 * and containing the unique elements in the specified collection. 58 * 59 * @param collection 60 * the collection of elements to add. 61 * @throws ClassCastException 62 * when an element in the collection does not implement the 63 * Comparable interface, or the elements in the collection 64 * cannot be compared. 65 */ 66 public TreeSet(Collection<? extends E> collection) { 67 this(); 68 addAll(collection); 69 } 70 71 /** 72 * Constructs a new empty instance of {@code TreeSet} which uses the 73 * specified comparator. 74 * 75 * @param comparator 76 * the comparator to use. 77 */ 78 public TreeSet(Comparator<? super E> comparator) { 79 backingMap = new TreeMap<E, Object>(comparator); 80 } 81 82 /** 83 * Constructs a new instance of {@code TreeSet} containing the elements of 84 * the specified SortedSet and using the same Comparator. 85 * 86 * @param set 87 * the SortedSet of elements to add. 88 */ 89 public TreeSet(SortedSet<E> set) { 90 this(set.comparator()); 91 Iterator<E> it = set.iterator(); 92 while (it.hasNext()) { 93 add(it.next()); 94 } 95 } 96 97 /** 98 * Adds the specified object to this {@code TreeSet}. 99 * 100 * @param object 101 * the object to add. 102 * @return {@code true} when this {@code TreeSet} did not already contain 103 * the object, {@code false} otherwise. 104 * @throws ClassCastException 105 * when the object cannot be compared with the elements in this 106 * {@code TreeSet}. 107 * @throws NullPointerException 108 * when the object is null and the comparator cannot handle 109 * null. 110 */ 111 @Override 112 public boolean add(E object) { 113 return backingMap.put(object, Boolean.TRUE) == null; 114 } 115 116 /** 117 * Adds the objects in the specified collection to this {@code TreeSet}. 118 * 119 * @param collection 120 * the collection of objects to add. 121 * @return {@code true} if this {@code TreeSet} was modified, {@code false} 122 * otherwise. 123 * @throws ClassCastException 124 * when an object in the collection cannot be compared with the 125 * elements in this {@code TreeSet}. 126 * @throws NullPointerException 127 * when an object in the collection is null and the comparator 128 * cannot handle null. 129 */ 130 @Override 131 public boolean addAll(Collection<? extends E> collection) { 132 return super.addAll(collection); 133 } 134 135 /** 136 * Removes all elements from this {@code TreeSet}, leaving it empty. 137 * 138 * @see #isEmpty 139 * @see #size 140 */ 141 @Override 142 public void clear() { 143 backingMap.clear(); 144 } 145 146 /** 147 * Returns a new {@code TreeSet} with the same elements, size and comparator 148 * as this {@code TreeSet}. 149 * 150 * @return a shallow copy of this {@code TreeSet}. 151 * @see java.lang.Cloneable 152 */ 153 @SuppressWarnings("unchecked") 154 @Override 155 public Object clone() { 156 try { 157 TreeSet<E> clone = (TreeSet<E>) super.clone(); 158 if (backingMap instanceof TreeMap) { 159 clone.backingMap = (NavigableMap<E, Object>) ((TreeMap<E, Object>) backingMap) 160 .clone(); 161 } else { 162 clone.backingMap = new TreeMap<E, Object>(backingMap); 163 } 164 return clone; 165 } catch (CloneNotSupportedException e) { 166 throw new AssertionError(e); 167 } 168 } 169 170 /** 171 * Returns the comparator used to compare elements in this {@code TreeSet}. 172 * 173 * @return a Comparator or null if the natural ordering is used 174 */ 175 public Comparator<? super E> comparator() { 176 return backingMap.comparator(); 177 } 178 179 /** 180 * Searches this {@code TreeSet} for the specified object. 181 * 182 * @param object 183 * the object to search for. 184 * @return {@code true} if {@code object} is an element of this 185 * {@code TreeSet}, {@code false} otherwise. 186 * @throws ClassCastException 187 * when the object cannot be compared with the elements in this 188 * {@code TreeSet}. 189 * @throws NullPointerException 190 * when the object is null and the comparator cannot handle 191 * null. 192 */ 193 @Override 194 public boolean contains(Object object) { 195 return backingMap.containsKey(object); 196 } 197 198 /** 199 * Returns true if this {@code TreeSet} has no element, otherwise false. 200 * 201 * @return true if this {@code TreeSet} has no element. 202 * @see #size 203 */ 204 @Override 205 public boolean isEmpty() { 206 return backingMap.isEmpty(); 207 } 208 209 /** 210 * Returns an Iterator on the elements of this {@code TreeSet}. 211 * 212 * @return an Iterator on the elements of this {@code TreeSet}. 213 * @see Iterator 214 */ 215 @Override 216 public Iterator<E> iterator() { 217 return backingMap.keySet().iterator(); 218 } 219 220 /** 221 * {@inheritDoc} 222 * 223 * @see java.util.NavigableSet#descendingIterator() 224 * @since 1.6 225 */ 226 public Iterator<E> descendingIterator() { 227 return descendingSet().iterator(); 228 } 229 230 /** 231 * Removes an occurrence of the specified object from this {@code TreeSet}. 232 * 233 * @param object 234 * the object to remove. 235 * @return {@code true} if this {@code TreeSet} was modified, {@code false} 236 * otherwise. 237 * @throws ClassCastException 238 * when the object cannot be compared with the elements in this 239 * {@code TreeSet}. 240 * @throws NullPointerException 241 * when the object is null and the comparator cannot handle 242 * null. 243 */ 244 @Override 245 public boolean remove(Object object) { 246 return backingMap.remove(object) != null; 247 } 248 249 /** 250 * Returns the number of elements in this {@code TreeSet}. 251 * 252 * @return the number of elements in this {@code TreeSet}. 253 */ 254 @Override 255 public int size() { 256 return backingMap.size(); 257 } 258 259 /** 260 * Returns the first element in this set. 261 * @exception NoSuchElementException when this TreeSet is empty 262 */ 263 public E first() { 264 return backingMap.firstKey(); 265 } 266 267 /** 268 * Returns the last element in this set. 269 * @exception NoSuchElementException when this TreeSet is empty 270 */ 271 public E last() { 272 return backingMap.lastKey(); 273 } 274 275 /** 276 * {@inheritDoc} 277 * 278 * @see java.util.NavigableSet#pollFirst() 279 * @since 1.6 280 */ 281 public E pollFirst() { 282 Map.Entry<E, Object> entry = backingMap.pollFirstEntry(); 283 return (entry == null) ? null : entry.getKey(); 284 } 285 286 /** 287 * {@inheritDoc} 288 * 289 * @see java.util.NavigableSet#pollLast() 290 * @since 1.6 291 */ 292 public E pollLast() { 293 Map.Entry<E, Object> entry = backingMap.pollLastEntry(); 294 return (entry == null) ? null : entry.getKey(); 295 } 296 297 /** 298 * {@inheritDoc} 299 * 300 * @see java.util.NavigableSet#higher(java.lang.Object) 301 * @since 1.6 302 */ 303 public E higher(E e) { 304 return backingMap.higherKey(e); 305 } 306 307 /** 308 * {@inheritDoc} 309 * 310 * @see java.util.NavigableSet#lower(java.lang.Object) 311 * @since 1.6 312 */ 313 public E lower(E e) { 314 return backingMap.lowerKey(e); 315 } 316 317 /** 318 * {@inheritDoc} 319 * 320 * @see java.util.NavigableSet#ceiling(java.lang.Object) 321 * @since 1.6 322 */ 323 public E ceiling(E e) { 324 return backingMap.ceilingKey(e); 325 } 326 327 /** 328 * {@inheritDoc} 329 * 330 * @see java.util.NavigableSet#floor(java.lang.Object) 331 * @since 1.6 332 */ 333 public E floor(E e) { 334 return backingMap.floorKey(e); 335 } 336 337 /** 338 * {@inheritDoc} 339 * 340 * @see java.util.NavigableSet#descendingSet() 341 * @since 1.6 342 */ 343 public NavigableSet<E> descendingSet() { 344 return (descendingSet != null) ? descendingSet 345 : (descendingSet = new TreeSet<E>(backingMap.descendingMap())); 346 } 347 348 /** 349 * {@inheritDoc} 350 * 351 * @see java.util.NavigableSet#subSet(Object, boolean, Object, boolean) 352 * @since 1.6 353 */ 354 @SuppressWarnings("unchecked") 355 public NavigableSet<E> subSet(E start, boolean startInclusive, E end, 356 boolean endInclusive) { 357 Comparator<? super E> c = backingMap.comparator(); 358 int compare = (c == null) ? ((Comparable<E>) start).compareTo(end) : c 359 .compare(start, end); 360 if (compare <= 0) { 361 return new TreeSet<E>(backingMap.subMap(start, startInclusive, end, 362 endInclusive)); 363 } 364 throw new IllegalArgumentException(); 365 } 366 367 /** 368 * {@inheritDoc} 369 * 370 * @see java.util.NavigableSet#headSet(Object, boolean) 371 * @since 1.6 372 */ 373 @SuppressWarnings("unchecked") 374 public NavigableSet<E> headSet(E end, boolean endInclusive) { 375 // Check for errors 376 Comparator<? super E> c = backingMap.comparator(); 377 if (c == null) { 378 ((Comparable<E>) end).compareTo(end); 379 } else { 380 c.compare(end, end); 381 } 382 return new TreeSet<E>(backingMap.headMap(end, endInclusive)); 383 } 384 385 /** 386 * {@inheritDoc} 387 * 388 * @see java.util.NavigableSet#tailSet(Object, boolean) 389 * @since 1.6 390 */ 391 @SuppressWarnings("unchecked") 392 public NavigableSet<E> tailSet(E start, boolean startInclusive) { 393 // Check for errors 394 Comparator<? super E> c = backingMap.comparator(); 395 if (c == null) { 396 ((Comparable<E>) start).compareTo(start); 397 } else { 398 c.compare(start, start); 399 } 400 return new TreeSet<E>(backingMap.tailMap(start, startInclusive)); 401 } 402 403 /** 404 * Returns a {@code SortedSet} of the specified portion of this {@code TreeSet} which 405 * contains elements greater or equal to the start element but less than the 406 * end element. The returned SortedSet is backed by this TreeSet so changes 407 * to one are reflected by the other. 408 * 409 * @param start 410 * the start element 411 * @param end 412 * the end element 413 * @return a subset where the elements are greater or equal to 414 * <code>start</code> and less than <code>end</code> 415 * 416 * @exception ClassCastException 417 * when the start or end object cannot be compared with the 418 * elements in this TreeSet 419 * @exception NullPointerException 420 * when the start or end object is null and the comparator 421 * cannot handle null 422 */ 423 @SuppressWarnings("unchecked") 424 public SortedSet<E> subSet(E start, E end) { 425 return subSet(start, true, end, false); 426 } 427 428 /** 429 * Returns a {@code SortedSet} of the specified portion of this {@code TreeSet} which 430 * contains elements less than the end element. The returned SortedSet is 431 * backed by this TreeSet so changes to one are reflected by the other. 432 * 433 * @param end 434 * the end element 435 * @return a subset where the elements are less than <code>end</code> 436 * 437 * @exception ClassCastException 438 * when the end object cannot be compared with the elements 439 * in this TreeSet 440 * @exception NullPointerException 441 * when the end object is null and the comparator cannot 442 * handle null 443 */ 444 @SuppressWarnings("unchecked") 445 public SortedSet<E> headSet(E end) { 446 return headSet(end, false); 447 } 448 449 /** 450 * Returns a {@code SortedSet} of the specified portion of this {@code TreeSet} which 451 * contains elements greater or equal to the start element. The returned 452 * SortedSet is backed by this TreeSet so changes to one are reflected by 453 * the other. 454 * 455 * @param start 456 * the start element 457 * @return a subset where the elements are greater or equal to 458 * <code>start</code> 459 * 460 * @exception ClassCastException 461 * when the start object cannot be compared with the elements 462 * in this TreeSet 463 * @exception NullPointerException 464 * when the start object is null and the comparator cannot 465 * handle null 466 */ 467 @SuppressWarnings("unchecked") 468 public SortedSet<E> tailSet(E start) { 469 return tailSet(start, true); 470 } 471 472 private void writeObject(ObjectOutputStream stream) throws IOException { 473 stream.defaultWriteObject(); 474 stream.writeObject(backingMap.comparator()); 475 int size = backingMap.size(); 476 stream.writeInt(size); 477 if (size > 0) { 478 Iterator<E> it = backingMap.keySet().iterator(); 479 while (it.hasNext()) { 480 stream.writeObject(it.next()); 481 } 482 } 483 } 484 485 @SuppressWarnings("unchecked") 486 private void readObject(ObjectInputStream stream) throws IOException, 487 ClassNotFoundException { 488 stream.defaultReadObject(); 489 TreeMap<E, Object> map = new TreeMap<E, Object>( 490 (Comparator<? super E>) stream.readObject()); 491 int size = stream.readInt(); 492 if (size > 0) { 493 for (int i=0; i<size; i++) { 494 E elem = (E)stream.readObject(); 495 map.put(elem, Boolean.TRUE); 496 } 497 } 498 backingMap = map; 499 } 500} 501