class inherits unrelated defaults for spliterator() from types java.util.Set and java.util.List
Asked Answered
E

3

19

I have class that implements Set and List. Programs works fine in Java6 and Java7

public class SetList<V> implements Set<V>, List<V>
{
  ....
}

With Java 8 , this does not compile. Error is

java: class trials.SetList inherits unrelated defaults for spliterator() from types java.util.Set and java.util.List

java/util/Set.java:394

 ...
@Override
default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.DISTINCT);
}

java/util/List.java

...
@Override
default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.ORDERED);
}

Does it mean I cannot have class that implement both Set and List in Java 8? (It looks like time has come to pay our technical debts.)

Expectorate answered 30/3, 2014 at 17:2 Comment(7)
Provide your own implementation of spliterator().Ossuary
How can a class implement both Set and List? They have contraditory contracts. This sounds like a really bad idea.Hiatus
@Sotirios Delimanolis - thanks , that is probably the answer.Expectorate
It will fix the compilation problem, but the issue is really what @JBNizet is talking about.Ossuary
@ JB Nizet : Thanks. I guess fixing the real problem is better than the fixing the 'compilation' part.Expectorate
You can't correctly implement both Set and List in any version of Java.Hyperostosis
@ Louis Wasserman : I agree. I am looking at changing the class to two different classes -- SortedSet and UniqueListExpectorate
F
12

While it is unusual that a class implements both List and Set, there are some situations, where a Set can also support being a somewhat limited List.

Personally, I prefer to declare an asList() method in these cases, instead of implementing both List and Set at the same time. Something like this:

public class SetList<V> implements Set<V> {
    public List<V> asList(){
        // return a list representation of this Set
    }
}

On the other hand, if you already have an existing class, that implements both List and Set, then the simplest solution for your problem is perhaps to explicitly call one of the super spliterator()methods:

public class SetList<V> implements Set<V>, List<V> {
    @Override
    public Spliterator<V> spliterator() {
        return List.super.spliterator();
    }
}
Freckle answered 31/3, 2014 at 13:17 Comment(0)
E
12

This is Diamond Problem that occurs with Multiple inheritance.

The "diamond problem" (sometimes referred to as the "deadly diamond of death") is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of C?

In Java , compile error prevents this problem. To resolve this, you should provide your own implementation.

Enalda answered 17/9, 2016 at 7:20 Comment(0)
V
0

In my case, I am using multiple underlying Lists and Sets in my ListSet class.

Since I happen to already implement the size() and iterator() methods (Using Guava Iterators.concat) the easiest solution was to use the Spliterators.spliterator() overload accepting an Iterator and size.

/**
 * A custom list container that combines a set of unchangeable items with a list of changeable ones.
 * An iterator {@link #iterator()} is available that will iterate first through the unchangeable
 * items and then through the changeable ones. {@link #size()} is the total combined size and
 * {@link #get(int)} can return either an item from the unchangeable list or the changeable one.
 *
 * @param <E>
 */
class ListSet<E> implements List<E>, Set<E> {
    @NonNull
    private final ImmutableList<E> mConstantItemsList;
    @NonNull
    private final ImmutableSet<E> mConstantItemsSet;
    @NonNull
    private final List<E> mVariableItems;

    ListSet(Set<E> constantItems) {
        mConstantItemsSet = ImmutableSet.copyOf(constantItems);
        mConstantItemsList = ImmutableList.copyOf(constantItems);
        mVariableItems = Lists.newArrayList();
    }

    @NonNull
    @Override
    public Iterator<E> iterator() {
        return Iterators.concat(mConstantItemsList.iterator(), mVariableItems.iterator());
    }

    @Override
    public int size() {
        return mConstantItemsList.size() + mVariableItems.size();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public Spliterator<E> spliterator() {
        return Spliterators.spliterator(iterator(), size(), Spliterator.ORDERED | Spliterator.DISTINCT);
    }
}


Valery answered 12/5, 2021 at 16:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.