Guava in Lists.partition (List, size) method lazy partitioning / partitions lazy

Guava in Lists.partition (List, size) method lazy partitioning / partitions lazy

background

A few days ago a colleague to use this method, be careful not to go in to view the source code, source code below, and then he found the idea by executing the debug tool Lists.partition(List, size)that line directly on the real size of a size below: After the call simply do not read the source code display size of these ah, just do not know why that thinking?

Lists.partition(List, size)Source as follows:

@GwtCompatible(emulated = true)
public final class Lists {
    .....
  public static <T> List<List<T>> partition(List<T> list, int size) {
    checkNotNull(list);
    checkArgument(size > 0);
    return (list instanceof RandomAccess)
        ? new RandomAccessPartition<>(list, size)
        : new Partition<>(list, size);
  }
  private static class Partition<T> extends AbstractList<List<T>> {
    final List<T> list;
    final int size;
    Partition(List<T> list, int size) {
      this.list = list;
      this.size = size;
    }
    @Override
    public List<T> get(int index) {
      checkElementIndex(index, size());
      int start = index * size;
      int end = Math.min(start + size, list.size());
      return list.subList(start, end);
    }
    @Override
    public int size() {
      return IntMath.divide(list.size(), size, RoundingMode.CEILING);
    }
    @Override
    public boolean isEmpty() {
      return list.isEmpty();
    }
  }
  private static class RandomAccessPartition<T> extends Partition<T> implements RandomAccess {
    RandomAccessPartition(List<T> list, int size) {
      super(list, size);
    }
  }
    .....
}

analysis

Found the problem, we should analyze why there is this situation?

Through the above posted code and Guava source, created after the discovery is a Partition class got nothing to do. why?

Show why call toString?

idea by looking at the - setting - Debugger - java can see.

After that we follow the code found in AbstractCollectionrewriting the toString methods in the class, as follows:

    public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

Just do not say it will call toString method? That the question is should display an array should not display size?

It should display an array should not display size

In the screenshot above we can see that the check box is checked several, including a Enable alternative view for Collections classes. Well now we will get rid of this. Look at the implementation of the results as shown below:

By result, we now find that the display is an array. It seems Enable alternative view for Collections classes This option is specifically for the collection to be displayed.

How is lazy division / partition lazy

Lazy division / partition means that lazy when we will actually use to divide. How to divide the lazy under the following analysis. Verify demo as follows:

public class Test {
    public static void main(String[] args) {
        List<String> alist= Lists.newArrayList("12","a","34");
        List<List<String>> sList = Lists.partition(alist, 2);
        sList.forEach(e -> {
            System.out.println(sList);
        });
    }
}

We look forEach source code as follows:

public interface Iterable<T> {
    ....
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    ....

}

See if this little ignorant force. Here sets a layer of circulation, it does not appear to call partition it? The need for in-depth study of the job cycle. We can write a for loop by simply viewing the underlying byte code to see in the end is how to achieve the cycle. Simple for loop as follows:

public class Test2 {
    public static void main(String[] args) {
        List<Integer> il = Lists.newArrayList(12,1,3,4);
        for (Integer i : il) {}
    }
}

By javap -c Test2.class After the reaction below parsed byte code:

The keyword information from the chart

38: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;

45: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z

54: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;

This shows us for a loop is achieved through the underlying iterator. We can also see that in turn calls iterator()->hasNext()->next().

Guava seen in Partition inheritance from opening the source code, found that when the bottom of the cycle when the call iterator()is to actually call the AbstractList#iterator()method AbstractList#iterator()involves the following source

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    ...
    public Iterator<E> iterator() {
        return new Itr();
    }
    ...
   private class Itr implements Iterator<E> {   
        int cursor = 0;
        int lastRet = -1;
        int expectedModCount = modCount;
        public boolean hasNext() {
            return cursor != size();
        }
        public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}

Through the above source, we found that when calling hasNext () method is invoked when the size () method. However, size () method in the code that we Guava

public int size() {
    return IntMath.divide(list.size(), size, RoundingMode.CEILING);
}

When the call next () method, the first call to get (i) implement the subclass, the subclass is in the code Guava

public List<T> get(int index) {
      checkElementIndex(index, size());
      int start = index * size;
      int end = Math.min(start + size, list.size());
      return list.subList(start, end);
    }

This analysis has been basically completed.

to sum up

We have a good analysis when you learn any knowledge of, think about why this design? What good design is? There is a series of knowledge.

For example, the for loop. If no in-depth study, you do not know why a series of methods such as iterator calls.

Guess you like

Origin www.cnblogs.com/lanweijava/p/11900442.html