1. 概要

Google Guava は、Java開発を容易にするユーティリティをライブラリに提供します。 このチュートリアルでは、Guava19リリースで導入された新機能を見ていきます。

2. common.baseパッケージの変更

2.1. CharMatcher静的メソッドを追加しました

CharMatcher は、その名前が示すように、文字列が一連の要件に一致するかどうかを確認するために使用されます。

String inputString = "someString789";
boolean result = CharMatcher.javaLetterOrDigit().matchesAllOf(inputString);

上記の例では、resulttrueになります。

CharMatcher は、文字列を変換する必要がある場合にも使用できます。

String number = "8 123 456 123";
String result = CharMatcher.whitespace().collapseFrom(number, '-');

上記の例では、resultは「8-123-456-123」になります。

CharMatcher を使用すると、特定の文字列内の文字の出現回数をカウントできます。

String number = "8 123 456 123";
int result = CharMatcher.digit().countIn(number);

上記の例では、resultは10になります。

以前のバージョンのGuavaには、CharMatcher.WHITESPACECharMatcher.JAVA_LETTER_OR_DIGITなどのマッチャー定数があります。

Guava 19では、これらは同等のメソッド( CharMatcher.whitespace()および CharMatcher.javaLetterOrDigit())に置き換えられました。 これは、CharMatcherが使用されるときに作成されるクラスの数を減らすために変更されました。

静的ファクトリメソッドを使用すると、必要な場合にのみクラスを作成できます。 将来のリリースでは、マッチャー定数は非推奨になり、削除される予定です。

2.2。 lazyStackTrace の方法スローアブル

このメソッドは、提供された Throwable のスタックトレース要素(行)のListを返します。 一部のみが必要な場合は、完全なスタックトレース( Throwable.getStackTrace())を反復処理するよりも高速になりますが、完全なスタックトレースを反復処理する場合は低速になる可能性があります。

IllegalArgumentException e = new IllegalArgumentException("Some argument is incorrect");
List<StackTraceElement> stackTraceElements = Throwables.lazyStackTrace(e);

3. common.collectパッケージの変更

3.1. FluentIterable.toMultiset()を追加しました

前回のBaeldungの記事、 Guava 18 の新機能では、FluentIterableについて説明しました。 toMultiset()メソッドは、FluentIterableImmutableMultiSetに変換する必要がある場合に使用されます。

User[] usersArray = {new User(1L, "John", 45), new User(2L, "Max", 15)};
ImmutableMultiset<User> users = FluentIterable.of(usersArray).toMultiset();

Multiset は、 Set のようなコレクションであり、順序に依存しない等式をサポートします。 SetMultisetの主な違いは、Multisetに重複する要素が含まれている可能性があることです。 Multiset は、等しい要素を同じ単一要素のオカレンスとして格納するため、 Multiset.count(java.lang.Object)を呼び出して、特定のオブジェクトのオカレンスの総数を取得できます。

いくつかの例を見てみましょう。

List<String> userNames = Arrays.asList("David", "Eugen", "Alex", "Alex", "David", "David", "David");

Multiset<String> userNamesMultiset = HashMultiset.create(userNames);

assertEquals(7, userNamesMultiset.size());
assertEquals(4, userNamesMultiset.count("David"));
assertEquals(2, userNamesMultiset.count("Alex"));
assertEquals(1, userNamesMultiset.count("Eugen"));
assertThat(userNamesMultiset.elementSet(), anyOf(containsInAnyOrder("Alex", "David", "Eugen")));

重複する要素の数を簡単に判別できます。これは、標準のJavaコレクションよりもはるかにクリーンです。

3.2. RangeSet.asDescendingSetOfRanges()および asDescendingMapOfRanges()を追加しました

RangeSet は、空でない範囲(間隔)で動作するために使用されます。 RangeSet は、切断された空でない範囲のセットとして説明できます。 RangeSet に新しい空でない範囲を追加すると、接続されているすべての範囲がマージされ、空の範囲は無視されます。

新しい範囲を構築するために使用できるいくつかのメソッドを見てみましょう: Range.closed() Range.openClosed() Range.closedOpen() Range.open()

それらの違いは、オープンレンジにはエンドポイントが含まれないことです。 それらは数学で異なる呼称を持っています。 オープンインターバルは「(」または「)」で示され、クローズドレンジは「[」または「]」で示されます。

たとえば、(0,5)は「0より大きく5より小さい任意の値」を意味し、(0,5]は「0より大きく5以下の任意の値」を意味します。

RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10));

ここでは、 RangeSetに範囲[1、10]を追加しました。 そして今、私たちは新しい範囲を追加することによってそれを拡張したいと思います:

rangeSet.add(Range.closed(5, 15));

これらの2つの範囲は5で接続されていることがわかります。したがって、 RangeSet は、それらを新しい単一の範囲[1、15]にマージします。

rangeSet.add(Range.closedOpen(10, 17));

これらの範囲は10で接続されているため、マージされて、クローズドオープン範囲になります[1,17]。 contains メソッドを使用して、値が範囲に含まれているかどうかを確認できます。

rangeSet.contains(15);

範囲[1,17)には15が含まれているため、これはtrueを返します。 別の値を試してみましょう:

rangeSet.contains(17);

範囲[1,17)には上限エンドポイント17が含まれていないため、これはfalseを返します。 encloses メソッドを使用して、範囲が他の範囲を囲んでいるかどうかを確認することもできます。

rangeSet.encloses(Range.closed(2, 3));

範囲[2,3]が完全に範囲[1,17)内にあるため、これはtrueを返します。

Range.greaterThan() Range.lessThan() Range.atLeast()[X155Xなど、間隔を指定して操作するのに役立つメソッドが他にもいくつかあります。 ]、 Range.atMost()。 最初の2つは開いた間隔を追加し、最後の2つは閉じた間隔を追加します。 例えば:

rangeSet.add(Range.greaterThan(22));

これにより、 RangeSet に新しい間隔(22、+∞)が追加されます。これは、他の間隔との接続がないためです。

asDescendingSetOfRanges RangeSet の場合)や asDescendingMapOfRanges RangeSet の場合)などの新しいメソッドを使用して、を変換できます。 RangeSetSetまたはMapに設定します。

3.3. 追加した Lists.cartesianProduct(リスト…) Lists.cartesianProduct(リスト >)

デカルト積は、2つ以上のコレクションの可能なすべての組み合わせを返します。

List<String> first = Lists.newArrayList("value1", "value2");
List<String> second = Lists.newArrayList("value3", "value4");

List<List<String>> cartesianProduct = Lists.cartesianProduct(first, second);

List<String> pair1 = Lists.newArrayList("value2", "value3");
List<String> pair2 = Lists.newArrayList("value2", "value4");
List<String> pair3 = Lists.newArrayList("value1", "value3");
List<String> pair4 = Lists.newArrayList("value1", "value4");

assertThat(cartesianProduct, anyOf(containsInAnyOrder(pair1, pair2, pair3, pair4)));

この例からわかるように、結果のリストには、提供されたリストのすべての可能な組み合わせが含まれます。

3.4. Maps.newLinkedHashMapWithExpectedSize(int)を追加しました

標準のLinkedHashMapの初期サイズは16です(これは LinkedInHashMap のソースで確認できます)。 HashMap (デフォルトでは0.75)の負荷率に達すると、HashMapは再ハッシュしてサイズを2倍にします。 ただし、 HashMap が多くのキーと値のペアを処理することがわかっている場合は、16より大きい初期サイズを指定して、繰り返しの再ハッシュを回避できます。

LinkedHashMap<Object, Object> someLinkedMap = Maps.newLinkedHashMapWithExpectedSize(512);

3.5. Multisets.removeOccurrences(Multiset、Multiset)を再追加しました

このメソッドは、Multisetで指定されたオカレンスを削除するために使用されます。

Multiset<String> multisetToModify = HashMultiset.create();
Multiset<String> occurrencesToRemove = HashMultiset.create();

multisetToModify.add("John");
multisetToModify.add("Max");
multisetToModify.add("Alex");

occurrencesToRemove.add("Alex");
occurrencesToRemove.add("John");

Multisets.removeOccurrences(multisetToModify, occurrencesToRemove);

この操作の後、multisetToModifyには「Max」のみが残ります。

multisetToModify に特定の要素の複数のインスタンスが含まれ、occurrencesToRemove にその要素のインスタンスが1つしかない場合、removeOccurrencesは1つのインスタンスのみを削除することに注意してください。

4. common.hashパッケージの変更

4.1. Hashing.sha384()を追加しました

Hashing.sha384()メソッドは、SHA-384アルゴリズムを実装するハッシュ関数を返します。

int inputData = 15;
        
HashFunction hashFunction = Hashing.sha384();
HashCode hashCode = hashFunction.hashInt(inputData);

SHA-384の15は、「0904b6277381dcfbddd…2240a621b2b5e3cda8」です。

4.2. 追加した Hashing.concatenating(HashFunction、HashFunction、HashFunction…) Hashing.concatenating(Iterable )。

Hashing.concatenating メソッドを使用して、一連のハッシュ関数の結果を連結します。

int inputData = 15;

HashFunction crc32Function = Hashing.crc32();
HashCode crc32HashCode = crc32Function.hashInt(inputData);

HashFunction hashFunction = Hashing.concatenating(Hashing.crc32(), Hashing.crc32());
HashCode concatenatedHashCode = hashFunction.hashInt(inputData);

結果のconcatenatedHashCodeは、「4acf27794acf2779」になります。これは、それ自体と連結された crc32HashCode (「4acf2779」)と同じです。

この例では、わかりやすくするために単一のハッシュアルゴリズムを使用しました。 ただし、これは特に便利ではありません。 2つのハッシュ関数を組み合わせると、ハッシュを強化する必要がある場合に役立ちます。ハッシュは、2つのハッシュが壊れた場合にのみ壊れる可能性があるためです。 ほとんどの場合、2つの異なるハッシュ関数を使用します。

5. common.reflectパッケージの変更

5.1. TypeToken.isSubtypeOfを追加しました

TypeToken は、実行時でもジェネリック型を操作および照会するために使用され、型消去による問題を回避します。

Javaは実行時にオブジェクトのジェネリック型情報を保持しないため、特定のオブジェクトがジェネリック型であるかどうかを知ることはできません。 しかし、リフレクションの助けを借りて、一般的なタイプのメソッドまたはクラスを検出できます。 TypeToken はこの回避策を使用して、余分なコードなしで汎用型を操作および照会できるようにします。

この例では、 TypeToken 方法 isAssignableFrom 、 戻ります真実それでも配列リストから割り当てることはできません配列リスト

ArrayList<String> stringList = new ArrayList<>();
ArrayList<Integer> intList = new ArrayList<>();
boolean isAssignableFrom = stringList.getClass().isAssignableFrom(intList.getClass());

この問題を解決するために、TypeTokenを使用してこれを確認できます。

TypeToken<ArrayList<String>> listString = new TypeToken<ArrayList<String>>() { };
TypeToken<ArrayList<Integer>> integerString = new TypeToken<ArrayList<Integer>>() { };

boolean isSupertypeOf = listString.isSupertypeOf(integerString);

この例では、isSupertypeOfはfalseを返します。

以前のバージョンのGuavaには、この目的のためのメソッド isAssignableFrom がありましたが、Guava 19の時点では、isSupertypeOfを優先して非推奨になっています。 さらに、メソッド isSubtypeOf(TypeToken)を使用して、クラスが別のクラスのサブタイプであるかどうかを判別できます。

TypeToken<ArrayList<String>> stringList = new TypeToken<ArrayList<String>>() { };
TypeToken<List> list = new TypeToken<List>() { };

boolean isSubtypeOf = stringList.isSubtypeOf(list);

ArrayListListのサブタイプであるため、期待どおり、結果はtrueになります。

6. common.ioパッケージの変更

6.1. ByteSource.sizeIfKnown()を追加しました

このメソッドは、データストリームを開かずに、ソースのサイズをバイト単位で返します(決定できる場合)。

ByteSource charSource = Files.asByteSource(file);
Optional<Long> size = charSource.sizeIfKnown();

6.2. CharSource.length()を追加しました

以前のバージョンのGuavaには、CharSourceの長さを決定する方法がありませんでした。 これで、この目的に CharSource.length()を使用できます。

6.3. CharSource.lengthIfKnown()を追加しました

ByteSource、の場合と同じですが、 CharSource.lengthIfKnown()を使用すると、ファイルの長さを文字で決定できます。

CharSource charSource = Files.asCharSource(file, Charsets.UTF_8);
Optional<Long> length = charSource.lengthIfKnown();

7. 結論

Guava 19は、成長するライブラリに多くの便利な追加と改善を導入しました。 次のプロジェクトでの使用を検討する価値は十分にあります。

この記事のコードサンプルは、GitHubリポジトリで入手できます。