More Related Content
Similar to コレクションフレームワーク関連セッション(JavaOne & Devoxx報告会 2022 発表資料) (20)
More from NTT DATA Technology & Innovation (20)
コレクションフレームワーク関連セッション(JavaOne & Devoxx報告会 2022 発表資料)
- 1. © 2022 NTT DATA Corporation
コレクションフレームワーク関連セッション
JavaOne & Devoxx報告会 2022
株式会社NTTデータ 阪田 浩一
2022年11月11日
• 想定視聴者: Javaのコレクションフレームワークのクラスを使ったことがあればどなたもOK!
- 2. © 2022 NTT DATA Corporation 2
自己紹介
• 株式会社NTTデータ 所属
• JVMがとにかく好き
• JavaOne 2015から毎回参加
• Javaチャンピオン
• OpenJDK Author
• 通算パッチ 10数個
• Oracle ACE Pro (Java分野)
Koichi Sakata
阪田 浩一
jyukutyo
- 3. © 2022 NTT DATA Corporation 3
このセッションで話すこと
コレクションフレームワークが関係する2セッション
- 4. © 2022 NTT DATA Corporation 4
このセッションで話すこと
コレクションフレームワークが関係する2セッション
• Sequenced Collections [LRN1422]
• The Sincerest Form of Flattery [LRN1426]
- 5. © 2022 NTT DATA Corporation 5
Sequenced Collections
[LRN1422]
- 6. © 2022 NTT DATA Corporation 6
JEP 431: Sequenced Collections
https://openjdk.org/jeps/431
順序ありのコレクションを定義するインタフェースを追加する
- 7. © 2022 NTT DATA Corporation 7
JEP 431: Sequenced Collections
https://openjdk.org/jeps/431
順序ありのコレクションを定義するインタフェースを追加する
APIを2つ追加する
• コレクションの最初、最後の要素を取得する統一的なAPI
• 順序を逆にする統一的なAPI
- 8. © 2022 NTT DATA Corporation 8
JEP 431: Sequenced Collections
https://openjdk.org/jeps/431
順序ありのコレクションを定義するインタフェースを追加する
APIを2つ追加する
• コレクションの最初、最後の要素を取得する統一的なAPI
• 順序を逆にする統一的なAPI
このJEPはCandidateステータスのため
ドラフト実装をもとにディスカッション中
• https://github.com/openjdk/jdk/pull/7387
- 9. © 2022 NTT DATA Corporation 9
スピーカー
Stuart Marksさん
Oracle社の方
このJEP 431のオーナー
IDEでのコードを使った説明のみのためスライドはなし
• 記憶に加え JEPの記述とドラフトPRのコードを元にレポートします
- 10. © 2022 NTT DATA Corporation 10
コレクションフレームワークの課題
順序ありコレクションとしてListとDequeがあるが
共通のインタフェースはCollectionで順序なしになる
順序ありのコレクションを表すのに この2つは具体的過ぎる
- 11. © 2022 NTT DATA Corporation 11
コレクションフレームワークの課題
順序ありコレクションとしてListとDequeがあるが
共通のインタフェースはCollectionで順序なしになる
順序ありのコレクションを表すのに この2つは具体的過ぎる
Setを例に挙げると SetとHashSetは順序なし
LinkedHashSetとSortedSetは順序あり
使いづらい わかりづらい
加えてunmodifiableSet()すると順序は失われる
- 12. © 2022 NTT DATA Corporation 12
コレクションフレームワークの課題
順序ありコレクションとしてListとDequeがあるが
共通のインタフェースはCollectionで順序なしになる
順序ありのコレクションを表すのに この2つは具体的過ぎる
Setを例に挙げると SetとHashSetは順序なし
LinkedHashSetとSortedSetは順序あり
使いづらい わかりづらい
加えてunmodifiableSet()すると順序は失われる
最初と最後の要素を取得する操作に統一性がない
降順(逆順)で反復する操作に統一性がない
- 13. © 2022 NTT DATA Corporation 13
最初と最後の要素を取得する操作に統一性がない
型 最初の要素取得 最後の要素取得
List list.get(0) list.get(list.size()- 1)
Deque deque.getFirst() deque.getLast()
SortedSet sortedSet.first() sortedSet.last()
LinkedHashSet
linkedHashSet.iterator()
.next()
なし
- 14. © 2022 NTT DATA Corporation 14
降順で反復する操作に統一性がない
// NavigableSetだとdescendingSet()で降順のビューを取得できる
for (var e : navSet.descendingSet())
process(e);
// Dequeは降順イテレータが使える
for (var it = deque.descendingIterator(); it.hasNext();) {
var e = it.next();
process(e);
}
// ListだとListIteratorを使う
for (var it = list.listIterator(list.size()); it.hasPrevious();) {
var e = it.previous();
process(e);
}
// LinkedHashSetだと他のコレクションクラスにコピーするしかない
- 15. © 2022 NTT DATA Corporation 15
降順で反復する操作に統一性がない
// NavigableSetだとdescendingSet()で降順のビューを取得できる
for (var e : navSet.descendingSet())
process(e);
// Dequeは降順イテレータが使える
for (var it = deque.descendingIterator(); it.hasNext();) {
var e = it.next();
process(e);
}
// ListだとListIteratorを使う
for (var it = list.listIterator(list.size()); it.hasPrevious();) {
var e = it.previous();
process(e);
}
// LinkedHashSetだと他のコレクションクラスにコピーするしかない
加えてSetが返ってくるから
stream()を呼んで
Stream APIを使うことも
IteratorからStream取得は
Spliteratorsに渡して…
と手間がかかる
- 16. © 2022 NTT DATA Corporation 16
新しいインタフェースの導入
https://openjdk.org/jeps/431
- 17. © 2022 NTT DATA Corporation 17
SequencedCollectionインタフェース
interface SequencedCollection<E> extends Collection<E> {
// 新規追加メソッド
SequencedCollection<E> reversed();
// Dequeから昇格したメソッド
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
set.reversed().stream()
とできる
- 18. © 2022 NTT DATA Corporation 18
SequencedSetインタフェース
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
SequencedSet<E> reversed();
}
// 比較のためSequencedCollectionインタフェースを再掲
interface SequencedCollection<E> extends Collection<E> {
SequencedCollection<E> reversed();
}
共変戻り値でオーバーライド
している
- 19. © 2022 NTT DATA Corporation 19
SequencedMapインタフェース
interface SequencedMap<K,V> extends Map<K,V> {
// 新規追加メソッド
SequencedMap<K,V> reversed();
SequencedSet<K> sequencedKeySet();
SequencedCollection<V> sequencedValues();
SequencedSet<Entry<K,V>> sequencedEntrySet();
V putFirst(K, V);
V putLast(K, V);
// SortedMapとNavigableMapから昇格したメソッド
Entry<K, V> firstEntry();
Entry<K, V> lastEntry();
K firstKey();
K lastKey();
Entry<K, V> pollFirstEntry();
Entry<K, V> pollLastEntry();
}
- 20. © 2022 NTT DATA Corporation 20
Collectionsクラスへの追加メソッド
static <T> SequencedCollection<T>
unmodifiableSequencedCollection(SequencedCollection<? extends T> c)
static <T> SequencedSet<T>
unmodifiableSequencedSet(SequencedSet<? extends T> s)
static <K,V> SequencedMap<K,V>
unmodifiableSequencedMap(SequencedMap<? extends K, ? extends V> m)
戻り値の実際の型はUnmodifiableSequenced[Collection|Set|Map]となる
- 22. © 2022 NTT DATA Corporation 22
SequencedCollection#reversed()
戻り値は降順に並び替えた新しいコレクションではない
ReverseOrder...Viewクラスのインスタンスを返す
• ReverseOrderListView、ReverseOrderSortedSetViewなど
• 元のコレクションを内部に保持し 各操作を降順で扱う
- 23. © 2022 NTT DATA Corporation 23
SequencedCollection#reversed()
戻り値は降順に並び替えた新しいコレクションではない
ReverseOrder...Viewクラスのインスタンスを返す
• ReverseOrderListView、ReverseOrderSortedSetViewなど
• 元のコレクションを内部に保持し 各操作を降順で扱う
// 一部抜粋
class ReverseOrderListView<E> implements List<E> {
final List<E> base;
public E get(int i) {
return base.get(base.size() - i - 1);
}
...
}
- 24. © 2022 NTT DATA Corporation 24
SequencedCollection#reversed()
ReverseOrder...Viewクラスのインスタンスを返す
• 元のコレクションを内部に保持し 各操作を降順で扱う
• よって 元のコレクション 降順のコレクション どちらかを変更しても
両方とも変更したコレクションとなる
// 一部抜粋
class ReverseOrderListView<E> implements List<E> {
final List<E> base;
public E get(int i) {
return base.get(base.size() - i - 1);
}
...
}
- 25. © 2022 NTT DATA Corporation 25
セッションの感想
現状はたしかに不便 一貫性がないと気づいた
• Javaに慣れきってこうした側面が見えていない自分が見えた
- 26. © 2022 NTT DATA Corporation 26
The Sincerest Form of Flattery
[LRN1426]
- 27. © 2022 NTT DATA Corporation 27
スピーカー
Maurice Naftalinさん
Javaチャンピオン
『Java Generics and Collections』(2006)の共著者
パターンマッチの部分のみJose Paumardさん
- 28. © 2022 NTT DATA Corporation 28
セッションタイトルの謎
The Sincerest Form of Flattery
(日本語訳) もっとも誠実なお世辞
- 29. © 2022 NTT DATA Corporation 29
セッションの内容
Javaが関数型言語から学び追加した機能について
Scalaと比較しながら確認する
- 30. © 2022 NTT DATA Corporation 30
タイトルと内容がどう関連するのかわからなかった
タイトル: The Sincerest Form of Flattery
(日本語訳) もっとも誠実なお世辞
内容: Javaが関数型言語から学び追加した機能について
Scalaと比較しながら確認する
- 31. © 2022 NTT DATA Corporation 31
有名な文章の一部
“Imitation is the sincerest form of flattery that
mediocrity can pay to greatness.”
(日本語訳) 模倣は凡人が偉大さに対して送ることができる
もっとも誠実なお世辞である
― オスカー・ワイルド
- 32. © 2022 NTT DATA Corporation 32
セッションタイトルの謎解き
意地悪な視点でタイトルと内容を照合すると
凡庸な言語であるJavaによる
先を行っている言語としての関数型(Scala) の機能の
模倣についてのセッション
- 33. © 2022 NTT DATA Corporation 33
関数型言語のエレガントで数学的にも正しい機能
高階関数
• Lisp 1958年
パラメータ多相
• ML 1975年
パターンマッチ
• Caml 1985年
ただし実用的と言えないところもあった
- 34. © 2022 NTT DATA Corporation 34
Pizza言語
Javaにこの3つの機能を加えたプログラミング言語
高階関数
パラメータ多相
パターンマッチ
https://pizzacompiler.sourceforge.net/
- 35. © 2022 NTT DATA Corporation 35
Pizzaコードでのパラメータ多相
class StoreSomething<A> {
A something;
StoreSomething(A something) {
this.something = something;
}
A get() {
return something;
}
}
interface Set<A implements Comparable> {
boolean contains(A x);
Set<A> include(A x);
}
- 36. © 2022 NTT DATA Corporation 36
1997年ごろ
https://dl.acm.org/doi/10.1145/263699.263715
- 37. © 2022 NTT DATA Corporation 37
https://www.oreilly.com/library/view/java-generics-and/0596527756/
- 38. © 2022 NTT DATA Corporation 38
PizzaからJavaのジェネリクスへ
Pizza
(1997)
GJ: Generic
Java
(1998)
Java 5
(2004)
Scala
(2003)
https://homepages.inf.ed.ac.uk/wadler/gj/Documents/gj-tutorial.pdf
- 39. © 2022 NTT DATA Corporation 39
GJからJava 5のジェネリクスへ
GJの時点でジェネリクスのほぼすべての機能があった
• ワイルドカードを除く
1998年からJava 5の2004年まで
なぜ6年かかったかは不明?とのこと
• ワイルドカードの実装追加していたにせよ長い?
http://www.bracha.org/wildcards.pdf
- 40. © 2022 NTT DATA Corporation 40
ScalaとJavaでの取り組み方の違い
高階関数
パラメータ多相
パターンマッチ
• Scalaはこれらの機能を一気に入れた (後方互換不要なのもある)
• Javaは1つずつ入れている (後方互換性を保ちつつ)
- 2004年にジェネリクス
- 2014年にラムダ式
- パターンマッチは追加中
- 41. © 2022 NTT DATA Corporation 41
セッション後半はそれぞれの詳細
ジェネリクス
• erasure イレージャ
• variance(変性): 共変や反変
• Scalaの場合
ラムダ式
• Javaで型システムを変更せずに関数を取り込むには
• Scalaの場合
パターンマッチ
• パターンとは
• Scalaの場合
- 42. © 2022 NTT DATA Corporation 42
本セッションでは時間のため1つだけ紹介
ジェネリクス
• erasure イレージャ
• variance(変性): 共変や反変
• Scalaの場合
ラムダ式
• Javaで型システムを変更せずに関数を取り込むには
• Scalaの場合
パターンマッチ
• パターンとは
• Scalaの場合
ビギナーの方向けの
内容です
- 43. © 2022 NTT DATA Corporation 43
Javaの配列は共変
// Arrays.sort(Object[] a)を考える
Integer[] a = { 1, 2, 3 };
Arrays.sort(a);
String[] b = { "Alice", "Bob", "Carol" };
Arrays.sort(b);
// Integer配列型もString配列型もObject配列型のサブタイプ
- 45. © 2022 NTT DATA Corporation 45
ジェネリクスの設計方針
List<Integer>はList<Number>のサブタイプではない
- 46. © 2022 NTT DATA Corporation 46
ジェネリクスの設計方針
境界型パラメータで共変サブタイピングを実現
- 47. © 2022 NTT DATA Corporation 47
ジェネリクスの設計方針
ワイルドカードで反変サプタイピングを実現
• List<? super Number>はList<Number>のスーパータイプ
混乱した方は
Effective Java 第3版
項目31を読んでみましょう
- 48. © 2022 NTT DATA Corporation 48
Scalaの場合
変位指定アノテーションがある
• [+A] [-A] [A]
たとえばScalaのリストはList[+A]で共変である
abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
val cats: List[Cat] = List(Cat("Alice"), Cat("Bob"))
val animals: List[Animal] = cats // OK
- 49. © 2022 NTT DATA Corporation 49
セッションの感想
各機能の意味や使用方法は知っていても
歴史的経緯はあまり知らなかったので興味深かった
ジェネリクスについて機能面には習熟していても
そのバックボーンについては知らないことが多いと気づいた
- 50. © 2022 NTT DATA Corporation
本資料に記載されている会社名、商品名、又はサービス名は、各社の登録商標又は商標です。