简体   繁体   中英

why java.util.Set can't return any value?

java.util.Set specifies only methods that return all records (via Iterator or array).

Why is there no option to return any value from Set?

It has a lot of sense in the real life. For example, I have a bowl of strawberries and I want to take just one of them. I totally don't care which one.

Why I can't do the same in java?

This is not answerable. You'd have to ask the original designers of the Java collections framework.

One plausible reason is that methods with non-deterministic behavior tend to be problematic:

  • They make unit testing harder.
  • They make bugs harder to track down.
  • They are more easily misunderstood and misused by programmers who haven't bothered to read the API documentation.

For hashtable-based set organizations, the behavior a "get some element" method is going to be non-deterministic, or at least difficult to determine / predict.

By the way, you can trivially get some element of a non-empty set as follows:

Object someObject = someSet.iterator().next();

Getting a truly (pseudo-)random element is a bit more tricky / expensive because you can't index the elements of a set. (You need to extract all of the set elements into an array ...)


On revisiting this, I realized that there is another reason. It is simply that Set is based on the mathematical notion of a set, and the elements of a set in mathematics have no order. It is simply meaningless to talk about the first element of a mathematical set.

A java.util.Set is an unordered collection; you can see it as a bag that contains things, but not in any particular order. It would not make sense to have a get(int index) method, because elements in a set don't have an index.

The designers of the standard Java library didn't include a method to get a random element from a Set . If you want to know why, that's something you can only speculate about. Maybe they didn't think it was necessary, or maybe they didn't even think about it.

It's easy to write a method yourself that gets a random element out of a Set .

If you don't care about the index of the elements, try using Queue instead of Set.

    Queue q = new ArrayDeque();
    q.element(); // retrieves the first object but doesn't remove
    q.poll(); // retrieves and removes first object

While a plain Set is in no particular, SortedSet and NavigableSet provide a guaranteed order and methods which support this. You can use first() and last()

SortedSet<E> set = ...
E e1 = set.first(); // a value
E e2 = set.last(); // also a value.

Actually the iterator is a lot better then using get(position) (which is something you can do on a java.util.List ). It allows for collection modifications during the iterations for one thing. The reason you don't have them in sets is probably because most of them don't guarantee order of insertion. You can always do something like new ArrayList<?>(mySet).get(position)

If you are not concerned with performance you can create a new type and back the data in an arraylist.

( Please note before donwvoting this is just an naive implementation of the idea and not the proposed final solution )

import ...

public class PickableSet<E> extends AbstractSet<E>{

    private final List<E> arrayList = new ArrayList<E>();
    private final Set<E>  hashSet   = new HashSet<E>();
    private final Random  random    = new Random();

    public boolean add( E e ) {
        return hashSet.add( e ) && arrayList.add( e );
    }
    public int size() {
        return arrayList.size();
    }
    public Iterator<E> iterator() {
        return hashSet.iterator();
    }

    public E pickOne() {
        return arrayList.get( random.nextInt( arrayList.size() ) );
    }
}

Of course, since you're using a different interface you'll have to cast to invoke the method:

Set<String> set = new PickableSet<String>();
set.add("one");
set.add("other");
String oneOfThem = ((PickableSet)set).pickOne();

ie https://gist.github.com/1986763

Well, you can with a little bit of work like this

    Set<String> s = new HashSet<String>();
    Random r = new Random();
    String res = s.toArray(new String[0])[r.nextInt(s.toArray().length)];

This grabs a randomly selected object from the set.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM