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

StackOverflow https://stackoverflow.com/questions/22746948

  •  24-06-2023
  •  | 
  •  

Question

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.)

Was it helpful?

Solution

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();
    }
}

OTHER TIPS

This is Diamond Problem that causes in 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. For resolving this You should implement yours one

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);
    }
}


Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top