The fastest and most efficient way is to make A \ SubA a view on A, i.e. not holding own references to the elements, but being backed by A and SubA. This is similar to difference from Guava Sets.
Of course changes to A and SubA after creating that view must be taken into account, which can be an advantage or disadvantage, depending on your situation.
Exemplary implementation for arbitrary Lists (i.e. in your case, use new ImmutableSubarrayList<E>(Arrays.asList(A),Arrays.asList(SubA))
:
import java.util.AbstractSequentialList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
public class ImmutableSubarrayList<E extends Comparable<E>> extends AbstractSequentialList<E>{
final List<E> a, subA;
final int size;
public ImmutableSubarrayList(List<E> aParam, List<E> subAParam){
super();
a = aParam;
subA = subAParam;
assert a.containsAll(subA) : "second list may only contain elements from first list";
// Iterate over a, because a.size()-subA.size() may not be correct if a contains equal elements.
int sizeTemp = 0;
for (E element : a){
if (!subA.contains(element)){
sizeTemp++;
}
}
size = sizeTemp;
}
public int size() {
return size;
}
public ListIterator<E> listIterator(final int firstIndex) {
//create a ListIterator that parallely
// iterates over a and subA, only returning the elements in a that are not in subA
assert (firstIndex >=0 && firstIndex <= ImmutableSubarrayList.this.size()) : "parameter was "
+firstIndex+" but should be betwen 0 and "+ImmutableSubarrayList.this.size();
return new ListIterator<E>() {
private final ListIterator<E> aIter = a.listIterator();
private final ListIterator<E> subAIter = subA.listIterator();
private int nextIndex = 0;
{
for (int lv = 0; lv < firstIndex; lv++ ){
next();
}
}
@Override
public boolean hasNext() {
return nextIndex < size;
}
@Override
public void add(E arg0) {
throw new UnsupportedOperationException("The list being iteratred over is immutable");
}
@Override
public boolean hasPrevious() {
return nextIndex > 0;
}
@Override
public int nextIndex() {
return nextIndex;
}
@Override
public E next() {
if (!hasNext()){
throw new NoSuchElementException();
}
nextIndex++;
return findNextElement();
}
@Override
public E previous() {
if (!hasPrevious()){
throw new NoSuchElementException();
}
nextIndex--;
return findPreviousElement();
}
@Override
public int previousIndex() {
return nextIndex-1;
}
@Override
public void set(E arg0) {
throw new UnsupportedOperationException("The list being iteratred over is immutable");
}
@Override
public void remove() {
throw new UnsupportedOperationException("The list being iteratred over is immutable");
}
private E findNextElement() {
E potentialNextElement = aIter.next();
while (subAIter.hasNext()){
E nextElementToBeAvoided = subAIter.next();
subAIter.previous();
assert (potentialNextElement.compareTo(nextElementToBeAvoided) > 0) :
"nextElementToBeAvoided should not be smaller than potentialNextElement";
while (potentialNextElement.compareTo(nextElementToBeAvoided) == 0){
potentialNextElement = aIter.next();
}
subAIter.next();
}
return potentialNextElement;
}
//in lack of lambdas: clone of findNextElement()
private E findPreviousElement() {
E potentialPreviousElement = aIter.previous();
while (subAIter.hasPrevious()){
E previousElementToBeAvoided = subAIter.previous();
subAIter.previous();
assert (potentialPreviousElement.compareTo(previousElementToBeAvoided) < 0) :
"previousElementToBeAvoided should not be greater than potentialPreviousElement";
while (potentialPreviousElement.compareTo(previousElementToBeAvoided) == 0){
potentialPreviousElement = aIter.previous();
}
subAIter.previous();
}
return potentialPreviousElement;
}
};
}
}