001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4; 018 019import java.util.Collection; 020import java.util.Iterator; 021import java.util.Set; 022 023/** 024 * Defines a collection that counts the number of times an object appears in 025 * the collection. 026 * <p> 027 * Suppose you have a Bag that contains {@code {a, a, b, c}}. 028 * Calling {@link #getCount(Object)} on {@code a} would return 2, while 029 * calling {@link #uniqueSet()} would return {@code {a, b, c}}. 030 * </p> 031 * <p> 032 * <em>NOTE: This interface violates the {@link Collection} contract.</em> 033 * The behavior specified in many of these methods is <em>not</em> the same 034 * as the behavior specified by {@code Collection}. 035 * The non-compliant methods are clearly marked with "(Violation)". 036 * Exercise caution when using a bag as a {@code Collection}. 037 * </p> 038 * <p> 039 * This violation resulted from the original specification of this interface. 040 * In an ideal world, the interface would be changed to fix the problems, however 041 * it has been decided to maintain backwards compatibility instead. 042 * </p> 043 * 044 * @param <E> the type of elements in this bag 045 * @since 2.0 046 */ 047public interface Bag<E> extends Collection<E> { 048 049 /** 050 * <em>(Violation)</em> 051 * Adds one copy of the specified object to the Bag. 052 * <p> 053 * If the object is already in the {@link #uniqueSet()} then increment its 054 * count as reported by {@link #getCount(Object)}. Otherwise add it to the 055 * {@link #uniqueSet()} and report its count as 1. 056 * </p> 057 * <p> 058 * Since this method always increases the size of the bag, 059 * according to the {@link Collection#add(Object)} contract, it 060 * should always return {@code true}. Since it sometimes returns 061 * {@code false}, this method violates the contract. 062 * </p> 063 * 064 * @param object the object to add 065 * @return {@code true} if the object was not already in the {@code uniqueSet} 066 */ 067 @Override 068 boolean add(E object); 069 070 /** 071 * Adds {@code nCopies} copies of the specified object to the Bag. 072 * <p> 073 * If the object is already in the {@link #uniqueSet()} then increment its 074 * count as reported by {@link #getCount(Object)}. Otherwise add it to the 075 * {@link #uniqueSet()} and report its count as {@code nCopies}. 076 * </p> 077 * 078 * @param object the object to add 079 * @param nCopies the number of copies to add 080 * @return {@code true} if the object was not already in the {@code uniqueSet} 081 * @throws ClassCastException if the class of the specified element prevents it from being added to this collection 082 */ 083 boolean add(E object, int nCopies); 084 085 /** 086 * <em>(Violation)</em> 087 * Returns {@code true} if the bag contains all elements in 088 * the given collection, respecting cardinality. That is, if the 089 * given collection {@code coll} contains {@code n} copies 090 * of a given object, calling {@link #getCount(Object)} on that object must 091 * be {@code >= n} for all {@code n} in {@code coll}. 092 * 093 * <p> 094 * The {@link Collection#containsAll(Collection)} method specifies 095 * that cardinality should <em>not</em> be respected; this method should 096 * return true if the bag contains at least one of every object contained 097 * in the given collection. 098 * </p> 099 * 100 * @param coll the collection to check against 101 * @return {@code true} if the Bag contains all the collection 102 */ 103 @Override 104 boolean containsAll(Collection<?> coll); 105 106 /** 107 * Returns the number of occurrences (cardinality) of the given 108 * object currently in the bag. If the object does not exist in the 109 * bag, return 0. 110 * 111 * @param object the object to search for 112 * @return the number of occurrences of the object, zero if not found 113 */ 114 int getCount(Object object); 115 116 /** 117 * Returns an {@link Iterator} over the entire set of members, 118 * including copies due to cardinality. This iterator is fail-fast 119 * and will not tolerate concurrent modifications. 120 * 121 * @return iterator over all elements in the Bag 122 */ 123 @Override 124 Iterator<E> iterator(); 125 126 /** 127 * <em>(Violation)</em> 128 * Removes all occurrences of the given object from the bag. 129 * <p> 130 * This will also remove the object from the {@link #uniqueSet()}. 131 * </p> 132 * <p> 133 * According to the {@link Collection#remove(Object)} method, 134 * this method should only remove the <em>first</em> occurrence of the 135 * given object, not <em>all</em> occurrences. 136 * </p> 137 * 138 * @param object the object to remove 139 * @return {@code true} if this call changed the collection 140 */ 141 @Override 142 boolean remove(Object object); 143 144 /** 145 * Removes {@code nCopies} copies of the specified object from the Bag. 146 * <p> 147 * If the number of copies to remove is greater than the actual number of 148 * copies in the Bag, no error is thrown. 149 * </p> 150 * 151 * @param object the object to remove 152 * @param nCopies the number of copies to remove 153 * @return {@code true} if this call changed the collection 154 */ 155 boolean remove(Object object, int nCopies); 156 157 /** 158 * <em>(Violation)</em> 159 * Remove all elements represented in the given collection, 160 * respecting cardinality. That is, if the given collection 161 * {@code coll} contains {@code n} copies of a given object, 162 * the bag will have {@code n} fewer copies, assuming the bag 163 * had at least {@code n} copies to begin with. 164 * 165 * <p> 166 * The {@link Collection#removeAll(Collection)} method specifies 167 * that cardinality should <em>not</em> be respected; this method should 168 * remove <em>all</em> occurrences of every object contained in the 169 * given collection. 170 * </p> 171 * 172 * @param coll the collection to remove 173 * @return {@code true} if this call changed the collection 174 */ 175 @Override 176 boolean removeAll(Collection<?> coll); 177 178 /** 179 * <em>(Violation)</em> 180 * Remove any members of the bag that are not in the given 181 * collection, respecting cardinality. That is, if the given 182 * collection {@code coll} contains {@code n} copies of a 183 * given object and the bag has {@code m > n} copies, then 184 * delete {@code m - n} copies from the bag. In addition, if 185 * {@code e} is an object in the bag but 186 * {@code !coll.contains(e)}, then remove {@code e} and any 187 * of its copies. 188 * 189 * <p> 190 * The {@link Collection#retainAll(Collection)} method specifies 191 * that cardinality should <em>not</em> be respected; this method should 192 * keep <em>all</em> occurrences of every object contained in the 193 * given collection. 194 * </p> 195 * 196 * @param coll the collection to retain 197 * @return {@code true} if this call changed the collection 198 */ 199 @Override 200 boolean retainAll(Collection<?> coll); 201 202 /** 203 * Returns the total number of items in the bag across all types. 204 * 205 * @return the total size of the Bag 206 */ 207 @Override 208 int size(); 209 210 /** 211 * Returns a {@link Set} of unique elements in the Bag. 212 * <p> 213 * Uniqueness constraints are the same as those in {@link java.util.Set}. 214 * </p> 215 * 216 * @return the Set of unique Bag elements 217 */ 218 Set<E> uniqueSet(); 219 220 // The following is not part of the formal Bag interface, however where possible 221 // Bag implementations should follow these comments. 222// /** 223// * Compares this Bag to another. 224// * This Bag equals another Bag if it contains the same number of occurrences of 225// * the same elements. 226// * This equals definition is compatible with the Set interface. 227// * 228// * @param obj the Bag to compare to 229// * @return true if equal 230// */ 231// boolean equals(Object obj); 232// 233// /** 234// * Gets a hash code for the Bag compatible with the definition of equals. 235// * The hash code is defined as the sum total of a hash code for each element. 236// * The per element hash code is defined as 237// * {@code (e==null ? 0 : e.hashCode()) ^ noOccurrences)}. 238// * This hash code definition is compatible with the Set interface. 239// * 240// * @return the hash code of the Bag 241// */ 242// int hashCode(); 243 244}