首页 > 编程知识 正文

drop partition,list分区

时间:2023-05-04 18:50:40 阅读:176140 作者:2635

Guava中的lists.partition(list,size )方法懒惰分区/懒惰分区背景前几天,同事使用此方法无意中进入查看源代码。 源代码如下所示。 但是,他发现自己已经在idea工具debug上运行完了lists.partition (list,size )

lists.partition(list,size )的源代码如下所示。

@gwtcompatible(emulated=true ) publicfinalclasslists……publicstatictlistlisttpartition ) listtlist,int size ) checheck check check 返回(listinstanceofrandomaccess )? newrandomaccesspartition(list,size ) : new partition (list,size ); } privatestaticclasspartitiontextendsabstractlistlistt { finallisttlist; final int size; partition(listtlist,int size ) { this.list=list; this.size=size; } @ overridepubliclisttget (intindex ) checkelementindex (index,size ); int start=index * size; intend=math.min(startsize,list.size ) ); returnlist.Sublist(start,end ); } @Override public int size () returnintmath.divide (list.size )、size、RoundingMode.CEILING ); } @Override public boolean isEmpty () { return list.isEmpty ); } privatestaticclassrandomaccesspartitiontextendspartitiontimplementsrandomaccess { randomaccesspartition,intspartition} (… ()

从上面粘贴的代码和Guava的源代码中,我们发现自从创建Partition类以来没有执行任何操作。 为什么?

显示为什么调用toString。

看看idea---setting---debugger---Java就知道了。

在中,跟随代码后,您发现toString方法在AbstractCollection类中被重写。 代码如下所示。

public string tostring ((iterator EIT=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 () (returnsb.append ) ) ') ) ).toString ); sb.append (,)、)、)、append )、); }刚才不是说了要调用toString方法吗? 那个问题是应该显示一个数组,不应该显示size ?

应该显示数组,不应该显示size

在上面的屏幕截图中,您可以看到选中了几个复选框。 其中有enablealternativeviewforcollectionsclasses . 把这个删掉吧。 让我们看看执行的结果。

p>

通过结果,我们发现现在显示的是数组了。看来Enable alternative view for Collections classes这个选项是专门针对集合来显示的。

如何是懒划分/懒分区

懒划分/懒分区意思就是当我们真正使用的时候才会去划分。下面分析下如何来懒划分的。验证demo如下:

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

我们看下forEach的源码如下:

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

看到这里是否有点懵逼。这里套了一层循环,没有显示调用分区呢?这个需要对for循环深入研究才行。我们可以通过简单写一个for循环后查看字节码看看底层到底是如何实现循环的。简单的for循环如下:

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

通过javap -c Test2.class反解析字节码后如下图:

从图中这些关键字信息

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;

这说明了我们for循环底层上还是通过迭代器来实现的。我们也可以看出依次调用iterator()->hasNext()->next()。

从开篇源码看出Guava中Partition的继承关系,发现当底层循环的时候调用iterator()方法是其实是调用AbstractList#iterator()方法,AbstractList#iterator()涉及源码如下

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

通过上面的源码,发现当调用hasNext()方法的时候会调用size()方法。然size()方法就是我们Guava中这段代码

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

当调用next()方法的时候,先是调用子类实现的get(i)方法,子类也就是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); }

到此已基本分析完成了。

总结

我们在学习任何知识点的时候都要好好分析,想想,为什么要这样设计?设计的好处是什么?还有就是知识的串联。

比如for 循环。如果不深入研究,你也不知道为啥会调用iterator等一系列的方法。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。