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}</code>. 028 * Calling {@link #getCount(Object)} on <code>a</code> would return 2, while 029 * calling {@link #uniqueSet()} would return <code>{a, b, c}</code>. 030 * <p> 031 * <i>NOTE: This interface violates the {@link Collection} contract.</i> 032 * The behavior specified in many of these methods is <i>not</i> the same 033 * as the behavior specified by <code>Collection</code>. 034 * The noncompliant methods are clearly marked with "(Violation)". 035 * Exercise caution when using a bag as a <code>Collection</code>. 036 * <p> 037 * This violation resulted from the original specification of this interface. 038 * In an ideal world, the interface would be changed to fix the problems, however 039 * it has been decided to maintain backwards compatibility instead. 040 * 041 * @param <E> the type of elements in this bag 042 * @since 2.0 043 */ 044public interface Bag<E> extends Collection<E> { 045 046 /** 047 * Returns the number of occurrences (cardinality) of the given 048 * object currently in the bag. If the object does not exist in the 049 * bag, return 0. 050 * 051 * @param object the object to search for 052 * @return the number of occurrences of the object, zero if not found 053 */ 054 int getCount(Object object); 055 056 /** 057 * <i>(Violation)</i> 058 * Adds one copy of the specified object to the Bag. 059 * <p> 060 * If the object is already in the {@link #uniqueSet()} then increment its 061 * count as reported by {@link #getCount(Object)}. Otherwise add it to the 062 * {@link #uniqueSet()} and report its count as 1. 063 * <p> 064 * Since this method always increases the size of the bag, 065 * according to the {@link Collection#add(Object)} contract, it 066 * should always return <code>true</code>. Since it sometimes returns 067 * <code>false</code>, this method violates the contract. 068 * 069 * @param object the object to add 070 * @return <code>true</code> if the object was not already in the <code>uniqueSet</code> 071 */ 072 @Override 073 boolean add(E object); 074 075 /** 076 * Adds <code>nCopies</code> copies of the specified object to the Bag. 077 * <p> 078 * If the object is already in the {@link #uniqueSet()} then increment its 079 * count as reported by {@link #getCount(Object)}. Otherwise add it to the 080 * {@link #uniqueSet()} and report its count as <code>nCopies</code>. 081 * 082 * @param object the object to add 083 * @param nCopies the number of copies to add 084 * @return <code>true</code> if the object was not already in the <code>uniqueSet</code> 085 */ 086 boolean add(E object, int nCopies); 087 088 /** 089 * <i>(Violation)</i> 090 * Removes all occurrences of the given object from the bag. 091 * <p> 092 * This will also remove the object from the {@link #uniqueSet()}. 093 * <p> 094 * According to the {@link Collection#remove(Object)} method, 095 * this method should only remove the <i>first</i> occurrence of the 096 * given object, not <i>all</i> occurrences. 097 * 098 * @param object the object to remove 099 * @return <code>true</code> if this call changed the collection 100 */ 101 @Override 102 boolean remove(Object object); 103 104 /** 105 * Removes <code>nCopies</code> copies of the specified object from the Bag. 106 * <p> 107 * If the number of copies to remove is greater than the actual number of 108 * copies in the Bag, no error is thrown. 109 * 110 * @param object the object to remove 111 * @param nCopies the number of copies to remove 112 * @return <code>true</code> if this call changed the collection 113 */ 114 boolean remove(Object object, int nCopies); 115 116 /** 117 * Returns a {@link Set} of unique elements in the Bag. 118 * <p> 119 * Uniqueness constraints are the same as those in {@link java.util.Set}. 120 * 121 * @return the Set of unique Bag elements 122 */ 123 Set<E> uniqueSet(); 124 125 /** 126 * Returns the total number of items in the bag across all types. 127 * 128 * @return the total size of the Bag 129 */ 130 @Override 131 int size(); 132 133 /** 134 * <i>(Violation)</i> 135 * Returns <code>true</code> if the bag contains all elements in 136 * the given collection, respecting cardinality. That is, if the 137 * given collection <code>coll</code> contains <code>n</code> copies 138 * of a given object, calling {@link #getCount(Object)} on that object must 139 * be <code>>= n</code> for all <code>n</code> in <code>coll</code>. 140 * <p> 141 * The {@link Collection#containsAll(Collection)} method specifies 142 * that cardinality should <i>not</i> be respected; this method should 143 * return true if the bag contains at least one of every object contained 144 * in the given collection. 145 * 146 * @param coll the collection to check against 147 * @return <code>true</code> if the Bag contains all the collection 148 */ 149 @Override 150 boolean containsAll(Collection<?> coll); 151 152 /** 153 * <i>(Violation)</i> 154 * Remove all elements represented in the given collection, 155 * respecting cardinality. That is, if the given collection 156 * <code>coll</code> contains <code>n</code> copies of a given object, 157 * the bag will have <code>n</code> fewer copies, assuming the bag 158 * had at least <code>n</code> copies to begin with. 159 * 160 * <p>The {@link Collection#removeAll(Collection)} method specifies 161 * that cardinality should <i>not</i> be respected; this method should 162 * remove <i>all</i> occurrences of every object contained in the 163 * given collection. 164 * 165 * @param coll the collection to remove 166 * @return <code>true</code> if this call changed the collection 167 */ 168 @Override 169 boolean removeAll(Collection<?> coll); 170 171 /** 172 * <i>(Violation)</i> 173 * Remove any members of the bag that are not in the given 174 * collection, respecting cardinality. That is, if the given 175 * collection <code>coll</code> contains <code>n</code> copies of a 176 * given object and the bag has <code>m > n</code> copies, then 177 * delete <code>m - n</code> copies from the bag. In addition, if 178 * <code>e</code> is an object in the bag but 179 * <code>!coll.contains(e)</code>, then remove <code>e</code> and any 180 * of its copies. 181 * 182 * <p>The {@link Collection#retainAll(Collection)} method specifies 183 * that cardinality should <i>not</i> be respected; this method should 184 * keep <i>all</i> occurrences of every object contained in the 185 * given collection. 186 * 187 * @param coll the collection to retain 188 * @return <code>true</code> if this call changed the collection 189 */ 190 @Override 191 boolean retainAll(Collection<?> coll); 192 193 /** 194 * Returns an {@link Iterator} over the entire set of members, 195 * including copies due to cardinality. This iterator is fail-fast 196 * and will not tolerate concurrent modifications. 197 * 198 * @return iterator over all elements in the Bag 199 */ 200 @Override 201 Iterator<E> iterator(); 202 203 // The following is not part of the formal Bag interface, however where possible 204 // Bag implementations should follow these comments. 205// /** 206// * Compares this Bag to another. 207// * This Bag equals another Bag if it contains the same number of occurrences of 208// * the same elements. 209// * This equals definition is compatible with the Set interface. 210// * 211// * @param obj the Bag to compare to 212// * @return true if equal 213// */ 214// boolean equals(Object obj); 215// 216// /** 217// * Gets a hash code for the Bag compatible with the definition of equals. 218// * The hash code is defined as the sum total of a hash code for each element. 219// * The per element hash code is defined as 220// * <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>. 221// * This hash code definition is compatible with the Set interface. 222// * 223// * @return the hash code of the Bag 224// */ 225// int hashCode(); 226 227}