S-JIS[2016-12-10/2017-04-30] 変更履歴

Asakusa Framework StringOptionクラス

Asakusa FrameworkOperator DSLで使うStringOptionクラスについて。


StringOption

StringOptionは、内部で(java.lang.Stringでなく)org.hadoop.io.Textを保持している。[2013-12-15]
したがって、getメソッドでは(Stringでなく)Textが返る。
Stringが欲しい場合はgetAsStringメソッドを使う。

モデルクラスでも、DMDL上でTEXTが指定されたプロパティーには、AsStringの付いたgetter/setterメソッドが生成される。


ただし、単純に値を移送するだけなら、AsStringの付いたメソッドを使うのは実行効率が悪い。
内部ではTextからString(new String(bytes, "UTF-8")相当)、あるいはStringからTextへの変換(string.getBytes("UTF-8")相当)が発生しているから。

//実行効率が悪い
	private void example(SalesDetail model1, SalesDetail model2) {
		String code = model2.getStoreCodeAsString();
		model1.setStoreCodeAsString(code);
	}

↓↑実行効率以外は同じ

import import org.apache.hadoop.io.Text;

	private void example(SalesDetail model1, SalesDetail model2) {
		Text code = model2.getStoreCode();
		model1.setStoreCode(code);
	}

↓↑ほぼ同じ

import com.asakusafw.runtime.value.StringOption;

	private void example(SalesDetail model1, SalesDetail model2) {
		StringOption code = model2.getStoreCodeOption();
		model1.setStoreCodeOption(code);
	}

また、getメソッドおよびAsStringの付いたgetメソッドは、内部で保持している値がnullだったらNullPointerExceptionが発生する。(メソッドの戻り値としてnullが返ってくるわけではない)
Optionの付いたsetメソッドではnullの状態ごとコピーされる。


同じStringOptionに対してgetAsString()を何度も呼ぶのも実行効率が悪い。
(TextからStringへ変換した結果をStringOption内部でキャッシュしていたりはしない為)

//実行効率が悪いし、値がnullだったらNullPointerExceptionが発生する
	public void example(SalesDetail model) {
		if (model.getItemCodeAsString().equals("0001")) {
			〜
		} else if (model.getItemCodeAsString().equals("0002")) {
			〜
		} else if (model.getItemCodeAsString().equals("0003")) {
			〜
		}
	}

import com.asakusafw.runtime.value.StringOption;
	private static final StringOption ITEM0001 = new StringOption("0001");
	private static final StringOption ITEM0002 = new StringOption("0002");
	private static final StringOption ITEM0003 = new StringOption("0003");

	public void example(SalesDetail model) {
		if (model.getItemCodeOption().equals(ITEM0001)) {
			〜
		} else if (model.getItemCodeOption().equals(ITEM0002)) {
			〜
		} else if (model.getItemCodeOption().equals(ITEM0003)) {
			〜
		}
	}

StringOptionの定数を用意しておけば、変換(String→Text)の回数は定数の個数分だけで済む。
model.getXxxAsString()を使う方式だと、呼び出す度に変換(Text→String)が発生してしまう。


StringOptionのメソッド

メソッド ver 説明
new StringOption(String)   文字列を保持する。
nullを渡しても良い。
StringOption option = new StringOption("abc");
new StringOption()   nullを保持する。 StringOption option = new StringOption();
Text get()   Textを返す。
nullの場合はNPEが発生する。
 
String getAsString()   Stringを返す。
nullの場合はNPEが発生する。
String s = option.getAsString();
Text or(Text)   Textを返す。
nullの場合は引数のTextを返す。
 
String or(String)   Stringを返す。
nullの場合は引数のStringを返す。
orの説明
String s = option.or("");
String s = option.or((String)null);
StringOption orOption(StringOption) 0.9.1 null以外の場合は自分自身を返す。[2017-04-30]
nullの場合は引数のStringOptionを返す。
StringOption EMPTY = new StringOption("");
StringOption r = option.orOption(EMPTY);
void reset()   空文字列にする。
resetの説明
option.reset();
boolean isNull()   中身がnullの場合trueを返す。 if (option.isNull()) { 〜 }
boolean isPresent() 0.9.1 中身がnull以外の場合trueを返す。[2017-04-30] if (option.isPresent()) { 〜 }
boolean isEmpty() 0.9.1 中身が空文字列の場合trueを返す。[2017-04-30]
nullの場合はNPEが発生する。
if (option.isEmpty()) { 〜 }
boolean has(String)   文字列が等しいかどうかを判定する。
(equalsはStringOptionを引数に取るが、hasはStringが引数)
if (option.has("abc")) { 〜 }
if (option.has(null)) { 〜 }
boolean contains(String)
boolean contains(StringOption)
0.9.1 文字列を含んでいるかどうかを判定する。[2017-04-30]
中身または引数がnullの場合はNPEが発生する。
if (option.contains("b")) { 〜 }
boolean startsWith(String)
boolean startsWith(StringOption)
0.9.1 文字列の先頭が一致しているかどうかを判定する。[2017-04-30]
中身または引数がnullの場合はNPEが発生する。
if (option.startsWith("a")) { 〜 }
boolean endsWith(String)
boolean endsWith(StringOption)
0.9.1 文字列の末尾が一致しているかどうかを判定する。[2017-04-30]
中身または引数がnullの場合はNPEが発生する。
if (option.endsWith("c")) { 〜 }
void appendTo(StringBuilder) 0.9.1 StringBuilderに文字列を追加する。[2017-04-30]
nullの場合はNPEが発生する。
(内部ではStringOptionUtil.appendを呼び出している)
StringBuilder sb = new StringBuilder();
option.appendTo(sb);

ちなみに、StringOptionに値をセットするメソッドとしてmodifyとcopyFromがあるが、非推奨。

java.lang.Stringにあるメソッドと同じ名前のメソッドは、同じような処理を行う。[2017-04-30]
ただし、Textクラスのまま処理を行うので、一旦Stringに変換して自分で処理するより高速なはず。


StringOptionUtil

AsakusaFW 0.8.0で、StringOptionUtilというユーティリティークラスが用意された。[2016-12-10]
StringOption本体とStringOptionUtilの区分けは、概ね、StringOption内部の状態を変えないものはStringOption本体、中身を加工するメソッドはStringOptionUtilにある。
getAsStringメソッドでStringを取得すれば何でも出来るわけだが、StringOption内部はTextで保持しているので、変換はなるべく避けたい。StringOptionUtilはTextのまま扱うようになっている)

import com.asakusafw.runtime.value.StringOptionUtil;
メソッド ver 説明
Reader asReader(StringOption) 0.8.0 StringOptionを読むReaderを返す。  
void trim(StringOption option) 0.8.0 StringOptionの両端の空白を除去する。
(StringOptionがnullの場合はNPEが発生する)
StringOptionUtil.trim(option);
void append(target, contents) 0.8.0 targetの末尾にcontentsを付加する。
(targetの中身がnullの場合はNPEが発生する)
(contentsがnullの場合はNPEが発生する)
StringOption target = new StringOption("abc");
StringOption contents = new StringOption("123");
StringOptionUtil.append(target, contents);
StringOption target = new StringOption("abc");
String contents = "123";
StringOptionUtil.append(target, contents);
0.9.1 StringBuilder target = new StringBuilder("abc");
StringOption contents = new StringOption("123");
StringOptionUtil.append(target, contents);
int countCodePoints(StringOption) 0.9.1 コードポイント数を返す。[2017-04-30] int n = StringOptionUtil.countCodePoints(option);
int parseInt(StringOption) 0.9.1 intに変換する。[2017-04-30]
(StringOptionがnullの場合はNPEが発生する)
int n = StringOptionUtil.parseInt(option);
long parseLong(StringOption) 0.9.1 longに変換する。[2017-04-30]
(StringOptionがnullの場合はNPEが発生する)
long n = StringOptionUtil.parseLong(option);
BigDecimal parseDecimal(StringOption) 0.9.1 BigDecimalに変換する。[2017-04-30]
(StringOptionがnullの場合はNPEが発生する)
BigDecimal n = StringOptionUtil.parseDecimal(option);

or

数値系Optionと同じく、StringOptionにもorメソッドがある。[2013-12-17]

		String code = model2.getStoreCodeOption().or("");
		model1.setStoreCodeAsString(code);

↓↑実行効率以外は同じ

	private static final Text EMPTY_TEXT = new Text();

		Text code = model2.getStoreCodeOption().or(EMPTY_TEXT);
		model1.setStoreCode(code);

orメソッドでは、StringOptionの中身がnullだったらorメソッドの引数が返る。


reset

空文字列を入れるなら、resetメソッドの方が速いかも?[2013-12-17]

		model1.setStoreCodeAsString("");

↓↑同じ

		model1.getStoreCodeOption().reset();

Option系クラスへ戻る / Operator DSLへ戻る / AsakusaFW目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま