javaチョットデキルへの道〜javaコアsdkに見る真似したいコード10選〜
TRANSCRIPT
![Page 1: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/1.jpg)
Javaチョットデキルへの道~JavaコアSDKに見る真似したいコード10選~
JJUG CCC 2017 Spring2017/05/20#jjug_ccc
#ccc_l7Made with
エルナナ
![Page 2: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/2.jpg)
自己紹介
• 株式会社ジャストシステム 福嶋 航• Twitter @fukushiw• Java歴約20年、JavaでWebサービス作っています• #Java100 本ノックの人https://github.com/JustSystems/java-100practices
![Page 3: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/3.jpg)
今日お話しすること
無料でJava力アップ!
JavaコアAPIのソースはまさに宝の山。Java 100本ノック作者がその中から選りすぐりの
10コードブロックについて、どう優れているのかこれから書くコードに是非採用したくなるような、匠の技を
紹介します。
![Page 4: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/4.jpg)
はじめに
![Page 5: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/5.jpg)
JavaコアAPIとは
• JDKをインストールするとついてくる src.zip• Java SE Development Kit 8u131
コメント+空行が約53.6%
7,6501,087,6431,004,582
251,0132,343,238
FilesLines of Code EffectiveLines of Code CommentLines of Code BlankLines of Code Total
![Page 6: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/6.jpg)
本題
![Page 7: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/7.jpg)
初級編1~4
![Page 8: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/8.jpg)
1
NullPointerException
ダメ。ゼッタイ。
![Page 9: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/9.jpg)
NullPointerException ダメ。ゼッタイ。
外からやってくるものは必ず null チェック!
例:java.util.Arrays LL.3998-4007
public static int hashCode(char a[]) { if (a == null) return 0;
int result = 1; for (char element : a) result = 31 * result + element;
return result; }
![Page 10: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/10.jpg)
NullPointerException ダメ。ゼッタイ。
特にインスタンスを生成するときは上記のように明示的にnullチェックをしておく。インスタンスは生成できたが、使うときに(インスタンス生成時のnull渡しが原因で)
NullPointerException が発生、となると原因が追いにくくなる。
例:java.time.LocalDateTime LL.373-377
public static LocalDateTime of(LocalDate date, LocalTime time) { Objects.requireNonNull(date, "date"); Objects.requireNonNull(time, "time"); return new LocalDateTime(date, time); }
![Page 11: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/11.jpg)
2
ガード節
![Page 12: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/12.jpg)
ガード節例:java.lang.Thread LL.325-341
public static void sleep(long millis, int nanos) throws InterruptedException { if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); }
if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; }
sleep(millis); }
典型的なガード節と例外スロー。その後の処理ロジックで異常な状態を考慮しなくてよいようにす
ることで可読性を向上している。例外スロー時にちゃんとメッセージを設定しているところも注目。
![Page 13: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/13.jpg)
3
例外メッセージは丁寧に
![Page 14: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/14.jpg)
例外メッセージは丁寧に
何がいけないのかをちゃんと説明する
例:java.net.HttpURLConnection LL.237-251
* @throws IllegalStateException if URLConnection is already connected * or if a different streaming mode is already enabled. * * @see #setFixedLengthStreamingMode(int) * @since 1.5 */ public void setChunkedStreamingMode (int chunklen) { if (connected) { throw new IllegalStateException ("Can't set streaming mode: already connected"); } if (fixedContentLength != -1 || fixedContentLengthLong != -1) { throw new IllegalStateException ("Fixed length streaming mode set"); } chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen; }
![Page 15: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/15.jpg)
4
メソッドは短くシンプルに
![Page 16: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/16.jpg)
メソッドは短くシンプルに例:java.util.ArrayList LL.463-480
/** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
• コメント半分• 直接関係ないロジックは
サブルーチン化
1
23
45
![Page 17: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/17.jpg)
中級編5~8
![Page 18: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/18.jpg)
5
パフォーマンスコンシャス
![Page 19: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/19.jpg)
パフォーマンスコンシャス例:java.lang.String LL.2066-2091
public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */
while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; }
1. oldChar != newChar で変える必要性を確認
2. ループの中でインスタンス変数にアクセスしない
3. わざわざ oldChar の出現箇所を探している※もし出現しない場合は i == len となるので new char[len] も new String() もしない。
4. 3のために途中までしたループを無駄にしない
• 極力newしない• 極力インスタンス変数にアクセスしない
![Page 20: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/20.jpg)
パフォーマンスコンシャス(拡大1) public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */
1. oldChar != newChar で変える必要性を確認2. ループの中でインスタンス変数にアクセスしない
![Page 21: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/21.jpg)
パフォーマンスコンシャス(拡大2) while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; }
3. わざわざ oldChar の出現箇所を探している※もし出現しない場合は i == len となるので new char[len] も new String() もしない。
4. 3のために途中までしたループを無駄にしない
• 極力newしない• 極力インスタンス変数にアクセスしない
![Page 22: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/22.jpg)
6CloneNotSupportedException
の処理
![Page 23: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/23.jpg)
CloneNotSupportedExceptionの処理
CloneNotSupportedException は実装次第では絶対に起きない。(そもそもなぜ checked exception なのか不明)
ここではその例外をキャッチ、起きえないことをコメントで示し、InternalError をスローすることで対処。
→ assert ができる前の苦肉の策と思われる。他に同様のクラスあり。
例:java.util.Vector LL.672-681
try { @SuppressWarnings("unchecked") Vector<E> v = (Vector<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, elementCount); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); }
![Page 24: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/24.jpg)
ちなみにhttp://bugs.java.com/bugdatabase/view_bug.do?bug_id=4220218
JDK-4220218 : Please make CloneNotSupportedException uncheckedResolution : Won't Fix
![Page 25: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/25.jpg)
7
デザインパターンの適用
![Page 26: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/26.jpg)
デザインパターンの適用
↑Factory Methodパターン
その他GoF23パターンがどのコアAPIで使われているか、↓このまとめが秀逸http://stackoverflow.com/questions/1673841/examples-of-gof-
design-patterns-in-javas-core-libraries#answer-2707195
例:java.util.Calendar LL.313, 1611-1614 ※説明の便宜上折り返しを追加
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
public static Calendar getInstance() { return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); }
![Page 27: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/27.jpg)
8サブクラスで
スーパークラスに定義された型を
狭める
![Page 28: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/28.jpg)
サブクラスでスーパークラスに定義された型を狭める
UncheckedIOExceptionでは cause に IOException しか取らないように制限している。 Serializable なので、デシリアライズで変なものが注入されないよう
に、readObject()メソッドでちゃんとガードしている。同様のガード例として、
java.time.chrono.JapaneseChronology#readObject()メソッドは常に InvalidObjectException をスローするようになっている、など。
例:java.io.UncheckedIOException LL.82-89 private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); Throwable cause = super.getCause(); if (!(cause instanceof IOException)) throw new InvalidObjectException("Cause must be an IOException"); }
![Page 29: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/29.jpg)
上級編9~10
![Page 30: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/30.jpg)
9
立つ鳥跡を濁さず
![Page 31: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/31.jpg)
立つ鳥跡を濁さず例:java.util.Timer LL.103-117
/** * This object causes the timer's task execution thread to exit * gracefully when there are no live references to the Timer object and no * tasks in the timer queue. It is used in preference to a finalizer on * Timer as such a finalizer would be susceptible to a subclass's * finalizer forgetting to call it. */ private final Object threadReaper = new Object() { protected void finalize() throws Throwable { synchronized(queue) { thread.newTasksMayBeScheduled = false; queue.notify(); // In case queue is empty. } } }; コアAPIの中でも数少ない finalize() のオーバーライド。この
threadReaperはどこからも参照されていないので、このfinalize()が呼ばれるのはこのTimerインスタンスがお掃除されるとき。このときにちゃ
んと(中で起動している)スレッドを終了させるための仕掛け。
![Page 32: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/32.jpg)
10
final変数への代入
![Page 33: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/33.jpg)
final変数への代入 ※黒魔術例:java.math.BigInteger LL.4395-4465 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { : // Commit final fields via Unsafe UnsafeHolder.putSign(this, sign); : }
// Support for resetting final fields while deserializing private static class UnsafeHolder { private static final sun.misc.Unsafe unsafe; : static void putSign(BigInteger bi, int sign) { unsafe.putIntVolatile(bi, signumOffset, sign); } : } よい子は真似してはいけません!
![Page 34: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/34.jpg)
最後に
![Page 35: Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜](https://reader034.vdocuments.pub/reader034/viewer/2022050613/5a64797e7f8b9a31568b4779/html5/thumbnails/35.jpg)
お願い
いいものを見つけたら、 Twitter: @fukushiwまで何卒ご一報下さい!