50 - Goldman Sachs

TECHNOLOGY
DIVISION
GS CollectionsとJava 8
実用的で流暢なAPIで楽しい開発を!
ゴールドマン・サックス
テクノロジー部 ヴァイス・プレジデント
伊藤博志
JJUG CCC 2015 Spring
#ccc_f3
1
TECHNOLOGY
DIVISION
ゴールドマン・サックスのエンジニアリング
2
TECHNOLOGY
DIVISION
ゴールドマン・サックスのエンジニアリング
ゴールドマン・サックスとは
投資銀行業務、証券業務および投資運用業務を中心に、企業、金融機関、政府機関、富
裕層など多岐にわたるお客様を対象に幅広い金融サービスを提供している世界有数の金
融機関です。1869年に創業、ニューヨークを本拠地として、世界の主要な金融市場に拠点
を擁しています。
ゴールドマン・サックス エンジニアリング
複雑な問題へのソリューションの構築、時代を変えるテクノロジーの創出、ビジネスと金融
マーケットをグローバルに牽引するシステム開発を行っています。
http://www.goldmansachs.com/japan/what-we-do/engineering/index.html
3
TECHNOLOGY
DIVISION
ゴールドマン・サックスのエンジニアリング
4
Agenda
•
•
•
•
TECHNOLOGY
DIVISION
イントロダクション
古き良き時代の再到来
Java 8のStream APIは大海原への入り口
大海原(GS Collections)を探検してみよう
–
–
–
–
API
流暢さ
メモリ効率
メソッド参照
• フレームワークの比較
5
GS Collectionsとは?
TECHNOLOGY
DIVISION
• ゴールドマン・サックスの開発したオープンソースコレク
ションフレームワーク
– 2004年より開発を開始
– GitHubにて公開 (Apache 2.0 License)
• github.com/goldmansachs/gs-collections
• GS Collections Kata
– 2007年に開発されたトレーニング教材
– 1,500人以上のGS Javaエンジニアが受講
– GitHubにて公開 (Apache 2.0 License)
• github.com/goldmansachs/gs-collections-kata
6
古き良き時代
1997 – ケント・ベックのSmalltalk
ベストプラクティスパターン
• do:
• select:
• reject:
• collect:
• detect:
• detect:ifNone:
• inject:into:
•…
(Dr. Seuss API)
TECHNOLOGY
DIVISION
2007 – 実装パターン(ケント・ベック)
• Map
• List
• Set
• コレクションのイテレーショ
ンパターンが消える
• 残ったのは型のみ
7
良き時代の再到来
Pattern in Classic Java
Pattern in GS Collections w/ Lambdas
list detect: [:each | each > 50].
list select: [:each | each > 50].
List<Integer> result = new ArrayList<>();
for (Integer each : list)
if (each > 50)
result.add(each);
list.select(each -> each > 50);
list reject: [:each | each > 50].
List<Integer> result = new ArrayList<>();
for (Integer each : list)
if (each <= 50)
result.add(v);
list.reject(each -> each > 50);
list anySatisfy: [:each | each > 50].
for (Integer each : list)
if (each > 50)
return true;
return false;
list.anySatisfy(each -> each > 50);
list allSatisfy: [:each | each > 50].
for (Integer each : list)
if (each <= 50)
return false;
return true;
list.allSatisfy(each -> each > 50);
list collect: [:e | e printString].
List<String> result = new ArrayList<>();
for (Integer each : list)
result.add(each.toString());
list.collect(Object::toString);
list inject: 3 into: [:x :y | x + y].
int result = 3;
for (Integer each : list)
result = result + each;
list.injectInto(3, Integer::sum);
inject
into
collect
all
satisfy
any
satisfy
reject
detect
for (Integer each : list)
if (each > 50)
return each;
return null;
select
Pattern in Smalltalk-80
TECHNOLOGY
DIVISION
list.detect(each -> each > 50);
8
遅延実行
TECHNOLOGY
DIVISION
findAny
filter
filter
boolean all =
list.asLazy().allSatisfy(e -> e > 50);
inject
into
collect
boolean any =
list.asLazy().anySatisfy(e -> e > 50);
LazyIterable<String> result =
list.asLazy().collect(Object::toString);
Integer result =
list.asLazy().injectInto(3, Integer::sum);
any
Match
Stream<Integer> result =
list.stream().filter(e -> e <= 50);
boolean any =
list.stream().anyMatch(e -> e > 50);
all
Match
LazyIterable<Integer> result =
list.asLazy().reject(e -> e > 50);
boolean all =
list.stream().allMatch(e -> e > 50);
map
Stream<Integer> result =
list.stream().filter(e -> e > 50);
Stream<String> result =
list.stream().map(Object::toString);
reduce
detect
LazyIterable<Integer> result =
list.asLazy().select(e -> e > 50);
any
satisfy
Integer result = list.stream()
.filter(e -> e > 50).findFirst().orElse(null);
all
satisfy
Integer result = list.asLazy()
.detectIfNone(e -> e > 50, () -> null);
select
Java 8 Streams
reject
GS Collections LazyIterable
Integer result =
list.stream().reduce(3, Integer::sum);
9
TECHNOLOGY
DIVISION
GS Collectionsの即時実行 vs Stream APIの遅延実行
findAny
filter
MutableList<Integer> result =
list.reject(e -> e > 50);
filter
List<Integer> result =
list.stream().filter(e -> e <= 50).collect(Collectors.toList());
boolean result =
list.stream().allMatch(e -> e > 50);
inject
into
MutableList<String> result =
list.collect(Object::toString);
Integer result =
list.injectInto(3, Integer::sum);
map
boolean all =
list.allSatisfy(e -> e > 50);
List<String> result =
list.stream().map(Object::toString).collect(Collectors.toList());
reduce
boolean result =
list.stream().anyMatch(e -> e > 50);
collect
boolean any =
list.anySatisfy(e -> e > 50);
any
Match
List<Integer> result =
list.stream().filter(e -> e > 50).collect(Collectors.toList());
all
Match
detect
MutableList<Integer> result =
list.select(e -> e > 50);
any
satisfy
Integer result =
list.stream().filter(e -> e > 50).findFirst().orElse(null);
all
satisfy
Integer result =
list.detect(e -> e > 50);
select
Java 8 Streams
reject
Eager GS Collections
Integer result =
list.stream().reduce(3, Integer::sum);
10
Java 8 Stream API
•
•
•
•
•
TECHNOLOGY
DIVISION
機能豊富な関数型APIを提供する素晴らしいフレームワーク
デフォルトで遅延実行のイテレーション
直列と並列のサポート
3種類のプリミティブ型をサポートするStream
Collectorの実装による拡張可能性
Java 8のStream APIは大海原への入り口!
11
GS Collectionsの豊富な機能
TECHNOLOGY
DIVISION
大海原を探検してみよう
• コレクションの即時実行イテレーションパターン
• より豊富なイテレーションパターン
– zip(), chunk(), partition(), makeString(), tap() 他多数
• コレクションプロトコルにおける共変型の戻り値
• 新しいコレクション型
– Bag, SortedBag, BiMap, Multimap
• メモリ効率のよいSetとMapの実装
• プリミティブ型のコンテナ
• イミュータブルなコンテナ
12
Agenda
•
•
•
•
TECHNOLOGY
DIVISION
イントロダクション
古き良き時代の再到来
Java 8のStream APIは大海原への入り口
大海原(GS Collections)を探検してみよう
–
–
–
–
API
流暢さ
メモリ効率
メソッド参照
• フレームワークの比較
13
海は広ければ広いほうがいい!
Java 8
GS Collections
Stream vs. LazyIterable Interfaces
5
9
Functional Interfaces
46
298
Object Container Interfaces
11
75
Primitive Container Interfaces
0
309
Stream vs. RichIterable API
47
109
Primitive Stream vs. Iterable API
48 x 3 = 144
38 x 8 = 304
LOC (Streams vs. GSC w/o code gen)
~15k
~400k
TECHNOLOGY
DIVISION
14
より多くのイテレーションパターン
•
•
•
•
•
•
•
TECHNOLOGY
DIVISION
flatCollect
partition
makeString / appendString
groupBy
aggregateBy
sumOf
sumBy
15
ユーティリティは無用!
TECHNOLOGY
DIVISION
• Utility
– 後方互換性を保った状態で新しい機能が容易に追加
できる
• API
–
–
–
–
–
新しい機能が容易に発見できる
容易に最適化できる
可読性が良い
特定の戻り値により理解がしやすい
動詞 vs 動名詞
16
Joining vs. MakeString
TECHNOLOGY
DIVISION
String joined =
things.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
String joined =
things.makeString(", ");
17
SummingInt vs. SumOfInt
TECHNOLOGY
DIVISION
int total =
employees.stream()
.collect(
Collectors.summingInt(Employee::getSalary));
long total =
employees.sumOfInt(Employee::getSalary);
18
GroupingBy vs. GroupBy
TECHNOLOGY
DIVISION
Map<Department, List<Employee>> byDept =
employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment));
Multimap<Department, Employee> byDept =
employees.groupBy(Employee::getDepartment);
19
TECHNOLOGY
DIVISION
GroupingBy/SummingBy vs. SumBy
Map<Department, Integer> totalByDept =
employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
ObjectLongMap<Department> totalByDept =
employees.sumByInt(
Employee::getDepartment,
Employee::getSalary);
20
PartitioningBy vs. Partition
TECHNOLOGY
DIVISION
Map<Boolean, List<Student>> passingFailing =
students.stream()
.collect(Collectors.partitioningBy(
s -> s.getGrade() >= PASS_THRESHOLD));
PartitionList<Student> passingFailing =
students.partition(
s -> s.getGrade() >= PASS_THRESHOLD);
21
スタックを見てみると?
TECHNOLOGY
DIVISION
Stream API
GS Collections
22
Agenda
•
•
•
•
TECHNOLOGY
DIVISION
イントロダクション
古き良き時代の再到来
Java 8のStream APIは大海原への入り口
大海原(GS Collections)を探検してみよう
–
–
–
–
API
流暢さ
メモリ効率
メソッド参照
• フレームワークの比較
23
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
http://docs.oracle.com/javase/tutorial/collections/algorithms/
• 辞書内のすべてのWordオブジェクトからスタート
• それぞれアルファグラムごとにグルーピング
– アルファグラムとは自身の文字をソートしたもの
– alerts  aelrst
– stelar  aelrst
• アナグラムが少なくとも8個存在するグループをフィルタ
• グループをアナグラムの数でソート(降順)
• 下記のフォーマットでプリント
11: [alerts, alters, artels, estral, laster, ratels,
salter, slater, staler, stelar, talers]
24
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.stream()
.collect(Collectors.groupingBy(Alphagram::new))
.values()
.stream()
.filter(each -> each.size() >= SIZE_THRESHOLD)
.sorted(Comparator.<List<?>>comparingInt(List::size).reversed())
.map(each -> each.size() + ": " + each)
.forEach(System.out::println);
25
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
26
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
Type: MutableListMultimap<Alphagram, String>
27
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
Type: RichIterable<RichIterable<String>>
28
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
Type: RichIterable<RichIterable<String>>
29
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
Type: MutableList<RichIterable<String>>
30
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
Type: LazyIterable<RichIterable<String>>
31
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
Type: LazyIterable<String>
32
アナグラム・チュートリアル
TECHNOLOGY
DIVISION
this.getWords()
.groupBy(Alphagram::new)
.multiValuesView()
.select(each -> each.size() >= SIZE_THRESHOLD)
.toSortedListBy(RichIterable::size)
.asReversed()
.collect(each -> each.size() + ": " + each)
.each(System.out::println);
11: [alerts, alters, artels, estral, laster, ratels, salter,
slater, staler, stelar, talers]
33
Parallel Lazy Iteration
TECHNOLOGY
DIVISION
Stream<Address> addresses =
people.parallelStream()
.map(Person::getAddress);
ParallelListIterable<Address> addresses =
people.asParallel(executor, batchSize)
.collect(Person::getAddress);
http://www.infoq.com/presentations/java-streams-scala-parallel-collections
34
Agenda
•
•
•
•
TECHNOLOGY
DIVISION
イントロダクション
古き良き時代の再到来
Java 8のStream APIは大海原への入り口
大海原(GS Collections)を探検してみよう
–
–
–
–
API
流暢さ
メモリ効率
メソッド参照
• フレームワークの比較
35
Mapのメモリ消費量の比較
TECHNOLOGY
DIVISION
45
40
JDK HashMap
35
Size (Mb)
30
25
GSC
UnifiedMap
Trove
THashMap
20
15
10
5
0
Elements
36
メモリの最適化
TECHNOLOGY
DIVISION
JDK HashMap
•
•
•
•
Entry はkey, value, next, hashを持つ
keyとvalueを配列に持ったほうが省スペース
平均して半分のメモリスペース
Map.entrySet()に注目
– 抽象性の破綻
• MapがEntryのテーブルとして実装されていることを仮定
– O(1)ではなくO(n)
– 代わりにforEachKeyValue()を使うべき
37
Setのメモリ消費量の比較
TECHNOLOGY
DIVISION
Size (Mb)
60
50
JDK HashSet
40
GSC UnifiedSet
30
Trove
THashSet
20
10
0
Elements
38
メモリの最適化
TECHNOLOGY
DIVISION
JDK HashSet
•
•
•
•
HashSetはHashMapに委譲する形で実装されている
やはりEntryはスペースの無駄である
それぞれの(key, value)に対してのvalueも無駄である
平均して4倍のメモリ消費量
39
はるか昔の誤った判断
TECHNOLOGY
DIVISION
40
プリミティブのコレクションによるメモリ削減
TECHNOLOGY
DIVISION
25
20
Size (Mb)
15
10
JDK ArrayList
GSC
IntArrayList
Trove
TIntArrayList
5
0
Elements
41
List<Integer> vs. IntList
TECHNOLOGY
DIVISION
• JavaはObjectとプリミティブの配列を持つ
– 配列はメソッドを持たない
• JavaにはプリミティブのList、Set、Mapが存在しない
– プリミティブ型を使うにはBoxingが必要
– Boxingはメモリの浪費
• Reference + Header + alignment
42
Agenda
•
•
•
•
TECHNOLOGY
DIVISION
イントロダクション
古き良き時代の再到来
Java 8のStream APIは大海原への入り口
大海原(GS Collections)を探検してみよう
–
–
–
–
API
流暢さ
メモリ効率
メソッド参照
• フレームワークの比較
43
ラムダ式とメソッド参照
TECHNOLOGY
DIVISION
• Kata をJava 7からJava 8にアップグレード
• 無名内部クラスを用いていた箇所をメソッド参照に変換
MutableList<String> customerCities =
customers.collect(Customer::getCity);
• ラムダ式に変換したところもある
MutableList<Customer> customersFromLondon =
customers.select(customer ->
customer.livesIn("London"));
44
ラムダ式とメソッド参照
TECHNOLOGY
DIVISION
• メソッド参照のシンタックスは魅力的
• selectの例をメソッド参照で書けないか?
MutableList<Customer> customersFromLondon =
customers.select(Customer::livesInLondon);
• 誰もこんなメソッドは書かない。。
45
ラムダ式とメソッド参照
TECHNOLOGY
DIVISION
• 現在メソッド参照を使用している箇所
• かつてはクラス定数として定義していた (Java 8 以前)
MutableList<String> customerCities =
customers.collect(Customer.TO_CITY);
public static final Function<Customer, String> TO_CITY =
new Function<Customer, String>() {
public String valueOf(Customer customer) {
return customer.getCity();
}
};
46
ラムダ式とメソッド参照
• selectの例はガベージをつくる
TECHNOLOGY
DIVISION
(Java 8 以前)
MutableList<Customer> customersFromLondon =
customers.select(new Predicate<Customer>()
{
public boolean accept(Customer customer)
{
return customer.livesIn("London");
}
});
47
ラムダ式とメソッド参照
TECHNOLOGY
DIVISION
• ガベージを避けるためselectWith(Predicate2)を導入
(Java 8 以前)
MutableList<Customer> customersFromLondon =
customers.selectWith(Customer.LIVES_IN, "London");
public static final Predicate2<Customer, String> LIVES_IN =
new Predicate2<Customer, String>()
{
public boolean accept(Customer customer, String city)
{
return customer.livesIn(city);
}
};
48
ラムダ式とメソッド参照
TECHNOLOGY
DIVISION
• この*With()メソッドはメソッド参照と非常に相性が良い
MutableList<Customer> customersFromLondon =
customers.selectWith(Customer::livesIn, "London");
• おかげでメソッド参照が使える箇所が数多く生じた
49
フレームワークの比較
Features
GS Collections
Java 8
Guava
Rich API



Interfaces
Readable, Mutable,
Immutable, FixedSize,
Lazy
Mutable, Stream
Mutable, Fluent
Optimized Set & Map
 (+Bag)
Immutable Collections

Primitive Collections
(+Bag, +Immutable)
Multimaps
(+Bag, +SortedBag)
(+Linked)
Bags (Multisets)


BiMaps


Iteration Styles
Eager/Lazy,
Serial/Parallel
TECHNOLOGY
DIVISION
Trove
Scala

Mutable
Readable, Mutable,
Immutable, Lazy




Lazy,
Serial/Parallel
Lazy,
Serial
(Multimap trait)
Eager,
Serial
Eager/Lazy,
Serial/Parallel (Lazy
Only)
50
TECHNOLOGY
DIVISION
付録
51
GS Collectionsを始めてみよう
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>6.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>6.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>6.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>6.1.0</version>
</dependency>
TECHNOLOGY
DIVISION
お気に入りのビルド・依存性管理ツールで
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="6.1.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="6.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="6.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="6.1.0"/>
Gradle
dependencies {
compile group: 'com.goldmansachs', name: 'gs-collections-api', version: '6.1.0'
compile group: 'com.goldmansachs', name: 'gs-collections', version: '6.1.0'
testCompile group: 'com.goldmansachs', name: 'gs-collections-testutils', version: '6.1.0'
compile group: 'com.goldmansachs', name: 'gs-collections-forkjoin', version: '6.1.0'
}
52
GS Collectionsを始めてみよう
TECHNOLOGY
DIVISION
様々なコンテナの初期化の例
List, Set, Bag, Map, Multimap他、com.gs.collections.imple.factory下に多数存在
MutableSet<String> mutableSet = Sets.mutable.of("One", "One", "Two", "Three");
MutableBag<String> mutableBag = Bags.mutable.of("One", "One", "Two", "Three");
MutableMap<String, String> mutableMap = Maps.mutable.of("key1", "value1", "key2", "value2", "key3", "value3");
Multimap<String, String> multimapWithList = Multimaps.mutable.list.with("key1", "value1-1", "key1", "value1-2", "key2", "value2-1");
それぞれMutable, Immutableのファクトリが存在
MutableList<String> mutableList = Lists.mutable.of("One", "Two", "Three");
//Equivalent of FastList.newList("One", "Two", "Three")
MutableList<String> mutableListWithBlank = Lists.mutable.with(); //You have a choice to use of() or with(), whichever you like.
ImmutableList<String> immutableList= Lists.immutable.of("One", "Two", "Three");
List, Set, Map等のコンテナにはメモリ効率のよいFixedSize用のファクトリも存在
FixedSizeList<String> fixedSizeList= Lists.fixedSize.of("One", "Two"); //Memory efficient if we know the size beforehand
53
GS Collectionsを始めてみよう
即時実行のイテレーションパターン
Interval list = Interval.fromTo(0, 100);
list.detect(each -> each > 50);
list.select(each -> each > 50);
list.reject(each -> each > 50);
TECHNOLOGY
DIVISION
遅延実行のイテレーションパターン
list.asLazy()
.select(each -> each > 95)
.collect(Object::toString)
.makeString("[", ",", "]");
=> [96,97,98,99,100]
list.anySatisfy(each -> each > 50);
list.allSatisfy(each -> each > 50);
list.collect(Object::toString);
list.injectInto(3, Integer::sum);
54
GS Collectionsを始めてみよう
TECHNOLOGY
DIVISION
GS Collectionsにはこ
こでは紹介しきれない
様々な機能が数多くあ
ります!
まずはRichIterable上
に存在する様々なAPI
を堪能し、JavaDoc、
パッケージやインター
フェースを探索してみ
てください。
55
セッション - Parallel-lazy Performance:
Java 8 vs Scala vs GS Collections
TECHNOLOGY
DIVISION
http://www.infoq.com/presentations/java-streams-scala-parallel-collections
QCon NY発表後に注目を浴びページビュートップに
出典:http://www.infoq.com/news/2014/12/qcon-ny-2015 より引用 (オレンジの囲みは発表者による)
56
研修資料 - GS Collections Kata
TECHNOLOGY
DIVISION
https://github.com/goldmansachs/gs-collections-kata
- ユニットテストをひとつずつパスしていくTDD型トレーニングマテリアル
- ゴールドマン・サックスの研修にも使用
- GS Collectionsの使用法を学習するのに最適
57
セッション - Scala Collections Performance
TECHNOLOGY
DIVISION
http://www.goldmansachs.com/gs-collections/presentations/2015-0317%20Scala%20Days%202015%20-%20Scala%20Collections%20Performance.pptx
- Scala Days San Francisco 2015
- Scalaのコレクション実装のパフォーマンス分析
- GS Collectionsで得られた知見から、Scalaのコレクション
実装のパフォーマンス改善案を提言
58
Resources
TECHNOLOGY
DIVISION
• GS Collections on GitHub
https://github.com/goldmansachs/gs-collections
https://github.com/goldmansachs/gs-collections/wiki
https://github.com/goldmansachs/gs-collections-kata
• GS Collections Memory Benchmark
http://www.goldmansachs.com/gscollections/presentations/GSC_Memory_Tests.pdf
• 実例で学ぶGS Collections (InfoQ 日本語翻訳記事)
http://www.infoq.com/jp/articles/GS-Collections-by-Example-1
http://www.infoq.com/jp/articles/GS-Collections-by-Example-2
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
59
TECHNOLOGY
DIVISION
Learn more at GS.com/Engineering
© 2015 Goldman Sachs. This presentation should not be relied upon or considered investment advice. Goldman Sachs does not warrant or guarantee to anyone the accuracy, completeness or efficacy of this
presentation, and recipients should not rely on it except at their own risk. This presentation may not be forwarded or disclosed except with this disclaimer intact.
60