Lists.partitionでグアバ(リスト、サイズ)メソッド怠惰なパーティショニング/パーティションの怠惰
背景
同僚数日前には、以下のソースコード、ソースコードを表示しないように行くことに注意してください、この方法を使用するには、その後、彼は、デバッグ・ツールを実行することにより、アイデアを見つけLists.partition(List, size)
、直接サイズの実物大の線より下にあること:呼び出した後、単にソースコードの表示を読んでいませんこれらああの大きさは、ちょうどなぜその考え方を知りませんか?
Lists.partition(List, size)
ソースとして、次のとおりです。
@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);
}
}
.....
}
分析
このような状況があるなぜ問題を発見し、私たちは分析する必要がありますか?
発見後に作成された投稿コードとグアバソース、上記された貫通パーティションのクラスは何の関係も持っていません。なぜ?
なぜ呼び出しのtoStringを表示しますか?
設定 - - デバッガ - を見て、アイデアは、javaを見ることができます。
その後、私たちはコードをたどる中で見つけAbstractCollection
、次のように、クラスのtoStringメソッドを書き換えます:
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(' ');
}
}
ただ、それはtoStringメソッドを呼び出します言わないのですか?質問があるというサイズを表示するべきではない配列を表示する必要がありますか?
これは、配列のサイズを表示すべきではありません表示されるはずです
我々はチェックボックスがいくつか確認されていることを確認することができます上のスクリーンショットでは、などのコレクションクラスの代替ビューを有効にします。さて、今私たちは、このを取り除くでしょう。下に示すような結果の実装を見てください:
その結果によって、我々は今、ディスプレイが配列であることがわかります。コレクションが表示されるため、このオプションは、具体的にコレクションクラスの代替ビューを有効にするようです。
どのように怠惰な部門/パーティション怠惰です
怠惰な私たちは、実際に分割するために使用することレイジー部門/パーティション手段。以下の分析の下で怠惰を分割する方法。次のようにデモを確認します。
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ループを書くことができますサイクルを実現する方法です。ループ用のシンプルな、次のように:
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 /イテレータ。
45:invokeinterface#6、1 // InterfaceMethodのJava / utilに/ Iterator.hasNext :()Z
54:invokeinterface#7、1 // InterfaceMethodのJava / utilに/ Iterator.next :()Ljava /ラング/オブジェクト。
ループのためのこのショー私たちは、基礎となるイテレータによって達成されます。また、ターンの呼び出しでそれを見ることができますiterator()->hasNext()->next()
。
ソースコードを開いてからパーティションの継承に見られるグアバ、コールはサイクルの底ときときことを見出し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()メソッドを呼び出していることがわかりました。コードでただし、サイズ()メソッド、我々グアバ
public int size() {
return IntMath.divide(list.size(), size, RoundingMode.CEILING);
}
()メソッドの次の呼び出しは、(i)は、サブクラスを実装取得するための最初の呼び出しは、サブクラスは、コードグアバのとき
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ループ。一連のメソッドがイテレータの呼び出しのような理由なしでの綿密な研究ならば、あなたは知りません。