くわっちょさんのレガシーコードを見て思うこと #jjug

くわっちょさんのレガシーコードを見て思うこ
と #jjug
Title
くわっちょさんのレガシーコードを見て思うこと #jjug
Category
Programming::Java::StreamAPI
Created at
2014-08-23T11:24:32.000+09:00
Created by
making
Updated at
2014-08-23T11:24:32.000+09:00
Updated by
making
Orininal URL
http://blog.ik.am/#/entries/279
昨日のJJUGナイトセミナーのLT大会でくわっちょさんのLTをみて、う∼んと思った。
Before
Jjug ナイト・セミナー くわっちょ 20140822 from くわっ ちょ
After
Jjug ナイト・セミナー くわっちょ 20140822 from くわっ ちょ
なんというかfor文とかif文とか見た目的な部分がレガシーなのではなく、 複数のことをごっちゃまぜにして処理をしているのがレガシーなんじゃ
ないかなーと。
そこが治っていないとStream APIを使っても改善された感じが全くしない。(むしろ見にくくなってStream APIがdisられるだけなような) if分が多
いとかfor文が古いとかそういう問題じゃない。
処理を分解すると、何らかのルールに基づいて数値を変換する部分と、その数値を用いて文字列を作成する部分に分けられる。 Stream APIを使
うと分けた部分を以下のようにつなげることができる。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(31, 12, 23, 74, 65);
list.stream()
.mapToInt(Integer::intValue)
.map(i -> {
if (i < 5) {
return 5;
} else if (i < 11) {
return 11;
} else if (i < 16) {
return 16;
} else if (i < 21) {
return 21;
} else if (i < 26) {
return 26;
} else if (i < 31) {
return 31;
} else if (i < 41) {
return 41;
} else if (i < 51) {
return 51;
} else {
return i;
}
})
.mapToObj(i -> {
if (i > 51) {
return "greater than 51";
} else {
return "less than " + i;
}
})
.forEach(System.out::println);
}
前半でintを変換して、後半でそのintを出力用のStringに変換した。三項演算子は複数回使うと見にくくなるので、if文に変えた。 前半部分は長い
ので、以下のように別関数にわけても良いと思う。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(31, 12, 23, 74, 65);
list.stream()
.mapToInt(Integer::intValue)
.map(Hoge::convert)
.mapToObj(i -> {
if (i > 51) {
return "greater than 51";
} else {
return "less than " + i;
}
})
.forEach(System.out::println);
}
static int convert(int i) {
if (i < 5) {
return 5;
} else if (i < 11) {
return 11;
} else if (i < 16) {
return 16;
} else if (i < 21) {
return 21;
} else if (i < 26) {
return 26;
} else if (i < 31) {
return 31;
} else if (i < 41) {
return 41;
} else if (i < 51) {
return 51;
} else {
return i;
}
}
分けておくと、convertの結果をmemo化することもできる。
まあ、これでも見やすいような気はするけど、if文が気になるなら、convertを少し工夫することになる。
やりたいことをよく見ると、"「5, 11, 16, 21, 26, 31, 41, 51」のうち、xより大きい最小の整数を求める"ことに置き換えられるので、これを実装
すると、
public static void main(String[] args) {
List<Integer> list = Arrays.asList(31, 12, 23, 74, 65);
list.stream()
.mapToInt(Integer::intValue)
.map(Hoge::convert)
.mapToObj(i -> {
if (i > 51) {
return "greater than 51";
} else {
return "less than " + i;
}
})
.forEach(System.out::println);
}
static int convert(int i) {
return IntStream.of(5, 11, 16, 21, 26, 31, 41, 51)
.filter(x -> i < x)
.findFirst()
.orElse(i);
}
と書ける。
ワンライナーが好きなら、
public static void main(String[] args) {
List<Integer> list = Arrays.asList(31, 12, 23, 74, 65);
list.stream()
.mapToInt(Integer::intValue)
.map(i -> IntStream.of(5, 11, 16, 21, 26, 31, 41, 51)
.filter(x -> i < x)
.findFirst()
.orElse(i))
.mapToObj(i -> {
if (i > 51) {
return "greater than 51";
} else {
return "less than " + i;
}
})
.forEach(System.out::println);
}
こんな感じかな∼