前のエントリでいい感じで書けそうみたいなことを書いたが、例外処理について言及していなかった。

CompletableFuture は Promise 同様エラー処理用にcompleteExceptionally(Throwable ex) というメソッドを持っている。これを呼ぶと後続の exceptionally() にエラー処理が移る (そしてリカバリできる) 。

では普通の、時間のかかり、なおかつ検査例外を出す同期メソッドを CompletableFuture として実行する場合例外はどうすればいいだろうか?

runAsync などの中では CompletableFuture インスタンスは見えないので、catch して明示的に completeExceptionally() することができない。

いくつか方法がありそうだけど、よくわかってない

CompletableFuture を明示的に扱うラッパメソッドを作る

package com.company;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
new Main().doMain(args);
}
private static <T> CompletableFuture<T> async(Consumer<CompletableFuture<T>> function) {
final CompletableFuture<T> future = new CompletableFuture<>();
function.accept(future);
return future;
}
public void doMain(String[] args) {
final CompletableFuture<Void> future1 = async(f -> {
try {
f.complete("Foobar");
} catch (Exception e) {
f.completeExceptionally(e);
}
}).thenAccept(x -> {
System.out.println(x);
});
final CompletableFuture<Void> future2 = async(f -> {
try {
throw new RuntimeException("exception");
} catch (Exception e) {
f.completeExceptionally(e);
}
}).exceptionally(ex -> {
System.out.println("exception!!");
return ex;
}).thenAccept(x -> {
System.out.println(x);
});
CompletableFuture.allOf(future1, future2).thenRun(() -> {
System.out.println("All done");
});
}
}
view raw Main.java hosted with ❤ by GitHub

こういう感じで、JS でいうところの new Promise( (resolve, reject) => {}) に相当するメソッドを作って、明示的に同期コードでの終了時/例外時の処理を行う。

JS の流れだとわかりやすいけど、ラッパメソッドとかいちいち書きたくはないし、せっかくマルチスレッドによって同期的に書ける処理を非同期っぽくなおすのはダサい。

全部 RuntimeException にしてしまう

runAsync 内で全例外をキャッチして非検査例外にしてしまう。

この場合投げられた例外は java.util.concurrent.CompletionException (これも非検査例外) にさらにラップされて exceptionally に渡される。

全例外 catch して completeExceptionally するのも実質非検査への変換なのでこれでもよさそう。実質はラッパメソッドでキャッチして completeExceptionally するのと変わりない。

その他

検査例外をうまく生かしつつ処理するというのが難しそう。各ステージで検査例外は全て処理するというのが想定されているのだろうか? とりあえず全部 catch して uncheck にするというのをやっていると、当然検査例外をまともに処理しようという気にはならなくなる。

検索例外を投げるメソッドは、直接メソッド参照のスタイルで runAsync(this::FooBar) 等と渡せない。

  1. トップ
  2. tech
  3. CompletableFuture と例外
  1. トップ
  2. java
  3. CompletableFuture と例外

(実質的な) 非接続状態のことをハイインピーダンス (Hi-Z) 状態 (Tri-state) と言う。久しぶりに触ると、どうすれば Hi-Z になるんだっけ??となるのでメモしておく

Arduino 風にいうと、

  • DDxn は pinMode(XX, INPUT | OUTPUT);
  • PORTxn は digitalWrite(XX, LOW | HIGH);
  • PUD (in MCUCR) はプルアップの有効化を決めるフラグだけど普通は有効にしとくので気にしない (Pull-up Disable フラグ、1でdisableされる)

プルアップ有効のケースだと、pinMode が INPUT かつ digitalWrite で LOW したピンはハイインピーダンス

  1. トップ
  2. tech
  3. Arduino / AVR でコード上からピンを非接続状態とする

続きをかきました 500 Can't connect to lowreal.net:443 (certificate verify failed)

仕様はちょっと前に調べて、先日対応バッテリーがきたので試してみました。

 -

3.0 / 5.0

回路図

12V を出す場合必要なのは D+ 0.6V / D- 0.6V なので、非常に簡単な構成。

VBUS には QC時に 5V〜12V の電圧がかかる。直接 Arduino の VIN に繋いでいるが、Arduino 側で 5V レギュレータが入っているので問題ない (ref. https://www.arduino.cc/en/uploads/Main/ArduinoNano30Schematic.pdf )。当然 5V ピンに直接繋いではならない (燃える)

コード

#include <Arduino.h>
#include <avr/sleep.h>

const int D_PLUS  = 11;
const int D_MINUS = 12;

/**
 * Arduino nano has 5V regulated power, so required voltages are generated with:
 * 3.3V: 4.7kΩ / 9.1kΩ
 * 0.6V: 1.1kΩ / 150Ω
 *
 */

void setup() {
	// wait until stable connection
	delay(1000);

	// reset line
	pinMode(D_PLUS, OUTPUT);
	pinMode(D_MINUS, OUTPUT);
	digitalWrite(D_PLUS, LOW);
	digitalWrite(D_MINUS, LOW);
	delay(100);

	// D+ and D- to 0.6V for 1.25s
	digitalWrite(D_PLUS, HIGH);
	digitalWrite(D_MINUS, HIGH);
	delay(1500);

	// D- to 0V for 1ms
	digitalWrite(D_MINUS, LOW);
	delay(2);

	// Set voltage
	digitalWrite(D_MINUS, HIGH);

	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_mode();
}

void loop() {
}

結果

12V とれたよ〜 (赤が VBUS、黄は D-)

備考

9V に対応する場合 D+ を途中から 0.6V -> 3.3V とする必要があるので、もう少し回路とコードが必要。

  1. トップ
  2. tech
  3. Quick Charge 2.0 電源から 12V とる