グアバ19:何が新しいの?

1概要

Google Guava は、Java開発を容易にするユーティリティをライブラリに提供します。このチュートリアルでは、https://github.com/google/guava/wiki/Release19[Guava 19リリース]で導入された新機能について説明します。

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

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

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

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

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

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.WHITESPACE CharMatcher.JAVA LETTER OR DIGIT__などの一致定数があります。

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

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

  • 2.2。 Throwables ** の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の記事、リンク:/whats-new-in-guava-18[Guava 18の新機能]では、 FluentIterable を調べました。 FluentIterable ImmutableMultiSet に変換する必要がある場合は、 toMultiset() メソッドが使用されます。

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

Multiset は、 Set と同様に、順序に依存しない等価性をサポートするコレクションです。 Set Multiset の主な違いは、 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));

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

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

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

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

範囲[2,3]が完全に私たちの範囲[1,17]に収まるので、これは true を返します。

Range.greaterThan() Range.lessThan() Range.atLeast() Range.atMost() など、間隔の操作に役立ついくつかのメソッドがあります。最初の2つは開始間隔を追加し、最後の2つは終了間隔を追加します。例えば:

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

これはあなたの RangeSet に新しい区間(22、∞)を追加します、なぜならそれは他の区間との関連がないからです。

asDescendingSetOfRanges RangeSet 用)や asDescendingMapOfRanges __RangeSet 用)などの新しいメソッドを使用すると、 RangeSet Set または Map__に変換できます。

* 3.3。 Lists.cartesianProduct(List …​) Lists.cartesianProduct(List <List>>) ** を追加しました

デカルト積は、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です(これは LinkedHashMap のソースで確認できます)。負荷率が HashMap (デフォルトでは0.75)に達すると、 HashMap はサイズを2倍にしてサイズを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);

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

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 <HashFunction>) ** を追加しました

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 では、この回避策を使用して、特別なコードを使わずにジェネリック型を処理したりクエリしたりできます。

この例では、 ArrayList <String> ArrayList <Integer> から代入できない場合でも、 TypeToken メソッド isAssignableFrom がないと、 true が返されることがわかります。

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

ArrayList List のサブタイプなので、期待どおり結果は 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では、増え続けるライブラリに多くの便利な追加や改良が加えられました。それはあなたの次のプロジェクトで使うために検討する価値があります。

この記事のコードサンプルはhttps://github.com/eugenp/tutorials/tree/master/guava-modules/guava-19[GitHub repository]にあります。