    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 &gt;= 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 &gt; 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}