日々常々

ふつうのプログラマがあたりまえにしたいこと。

GoogleSlidesで出力したPDFがプレビューでうまく表示できない

たとえば「左端がページの端にくっついた、水平グラデーションで塗りつぶした図形」

こういうの

GoogleSlidesのスクショ

これをPDFダウンロードしてMacのプレビューで開くと、こんなふうに水平グラデーション(下)だけ色だけ落ちる。上の円形グラデーションは問題ない。

PDFをプレビューで開いたのスクショ

謎。

なおPDFをChromeやEdgeで開くと期待通り塗りつぶされる。Safariはプレビューと同じで塗りつぶされない。

PDFをChromeで開いたスクショ

なのでPDFファイルに情報は入っているんだろう。 SpeakerDeckにアップロードしても見えたし。

ダメなパターンを見つけよう

と思ってGoogleSlidesで作ったの

でPDFを出してプレビューで開く。

結果

サイズとかの問題ではなく、X=0の時が条件ぽい。これやるまで「横幅がページと同じやつ?」と思ってた。

見ての通り、背景色も同様に表示されない。X=0扱いなのかな。

まとめ

deckを使ってみようと思ってGoogleSlidesをつかった時に踏んだから、GoogleSlidesの問題かと思ったけど、どうも濡れ衣のよう。

雑に調べたらプレビューとかのQuartz PDFKit?の既知の不具合っぽい?

よくわからんし水平グラデーションやめとくか・・・

Objects.requireNonNullを使わない方がましな場合がある話

こう言うのがあって。

class Hoge {
  public static void main(String[] args) {

    Object hoge = null;

    hoge.toString();
  }
}

実行すると当然NPEになるんだけど、こんな感じで出る。

% java Hoge.java
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Object.toString()" because "<local1>" is null
    at Hoge.main(Hoge.java:8)

一昔前は Cannot invoke "Object.toString()" because "<local1>" is null なんて出なかったんだけど、 JEP 358: Helpful NullPointerExceptions で出るようになりました。LTS基準で考えると導入されたJava17は2021年9月なので、使ってたりするところも多くなっているんじゃないかなと。

null になりえるところでは null チェックしましょう」には異論はない。そして null チェックしてくれる Objects#requireNonNull(T) とかもJSLにはある。

docs.oracle.com

IDEも「これ null になるからチェックしたまへ」と警告出してくれるし、quick fixで requireNonNull で包むのも候補に出てくる。とはいえ……

import java.util.Objects;

class Hoge {
  public static void main(String[] args) {

    Object hoge = null;

-    hoge.toString();
+    Objects.requireNonNull(hoge).toString();
  }
}

こうするのはイマイチなんだ。IDEの警告は消えるけど、警告をなくすだけの臭いものに蓋をして熟成させる対応であり、あまりよくない。

なんでかって言うと、この実行結果はこうなってしまう。

% java Hoge.java
Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:233)
    at Hoge.main(Hoge.java:10)

スタックトレース増える。けど、必要な情報ではない。何もしなければ出てくるJEP 358よりも情報が減っている。文字数が増えて情報量が減る、酷い話だ。

コード量も requireNonNull を書くことで増えている。でも「hogenull であってはいけない」なんてのは続くメソッド呼び出しでわかってる話でしかないので、情報量はあまり増えていない。「null じゃないはずなんだ!」と言う主張は感じなくはないので役に立つ可能性もわずかにはあるけれど、機械的な警告消し対応(表出した事象の叩き潰し での「警告を消せ」に対する「誤った対応」 )であれば主張なんてないので、読み取っても誤読にしかならない。

以上により、私は 引数が1つの requireNonNull は役に立たない と思っている。役に立たないどころか、使わない方がマシまである。JEP 358のメッセージが出ているほうが役に立つ。

まぁ requireNonNull はJava1.7で導入されたものだし、 if や条件演算子null チェックするよりはまぁってこともあったわけだけども。

と言うことで、どうせ使うなら引数2つの方を使いましょう。第二引数にエラー時のメッセージを込められる。

import java.util.Objects;

class Hoge {
  public static void main(String[] args) {

    Object hoge = null;

    Objects.requireNonNull(hoge, "hogeがnullのままここにきてしまった。宇宙線の仕業?").toString();
  }
}
% java Hoge.java
Exception in thread "main" java.lang.NullPointerException: hogeがnullのままここにきてしまった。宇宙線の仕業?
    at java.base/java.util.Objects.requireNonNull(Objects.java:259)
    at Hoge.main(Hoge.java:8)

こうなっていれば、このエラーに遭遇したときに「これ実装した人は疲れてたんだなぁ」と言うのがわかる。

以上のように nullになった場合のことを考慮したメッセージを第二引数に書いたrequireNonNull > JEP 358によるデフォルトメッセージ > 引数1つのrequireNonNull である以上、引数1つのを使ってたら検出するように静的解析設定した方がいいかもなぁと思ったりする今日この頃。requireNonNullJavadocに書いてるような、コンストラクタで引数をフィールドに代入するときとかのようにメソッド呼び出しが続かない時には適切だと思うんだけども。

とかなんとか書いたけど、これ以前に null になり得るコードを避けるべきという前提があり、自分で書かずとも null になりえるパラメタやレスポンスを受けるなら早期エラーにするかさっさと Optional とかで包んで適切に扱いましょう、と言う話はある。

null 滅びないかなぁ。

追記

似たようなこと書いてた。

irof.hateblo.jp

Java14以降ではObjects#requireNonNull(Object) メソッドや自身で null チェックしての例外送出より、そのままNPEを起こした方が解析しやすいまであります。予期しないNPEには備えるんじゃなく、予期しないnullを教えてくれるNPEを素直に受け止めるのがいいと思います。

2021年よりは使われてる環境も多くなってるだろうし、改めてって感じでヨシとしとく。

型で語るカタ

2025-07-11 に 型の表現力 / 関ジャバ'25 7月度 を開催しました。 今年は毎月やるとか言ってますが、なんとか折り返しました。これも一緒に運営/参加してくださっている皆様のおかげです。

今回は公募セッション枠。あいてたので2日前に申し込んだわけですが、タイトル先行した結果ものすごい難産でした。困ったもんだ。

speakerdeck.com

Javaでのアプリケーション開発で、型の専門的な知識がなくても利点が得られそうなところを挙げた感じです。

当日の話

家出る直前にMacBookProの確認したら電池0%で、「iPhoneKeynoteでプロジェクター出力できるし、いけるいける」とiPhoneだけ持って現地向かいました。 開始前に接続確認したら、プロジェクターとの相性?でプロジェクターには「この信号を処理できません」的なメッセージが出てアウト。 画面だけなら映ったんですが、Keynoteでプレゼン開始するとダメになるパターンでした。こういうのもあるのか。

一応バックアップとしてSpeakerdeckに先にアップロードしていたので、端末を借りてそちらを映してもらって難を逃れました。 ダメだったらPDFでの投影とか、内容は現場じゃ資料なしで話してるものなので「最悪口頭だけでもいけるかー」くらいに思っていたので、トラブルの割には焦りとかはなかったです。

ただKeynoteの発表者ディスプレイがないと色々やりづらいなぁと再認識しました。 次のスライドが見えてなくて「どこまでここで話すんだっけ?」となっちゃったし、時間とページ数がわからないのでタイムコントロールが難しかったです。

セクション画像

Grokさんにセクションタイトルで画像を作ってもらったら、なんか人の画像が多かったんだけど、なんでだろな。

ChatGPTさんに「プリミティブとラッパー」を描いてもらったらこんな感じでした。

なるほど。