Java8の良いのか悪いのかわからない活用法を紹介します。
若干難解なので職場で活用して先輩に怒られても知りません。
#AutoCloseableってもしかして関数型インターフェース!??
AutoCloseableは@FunctionalInterfaceはもちろんついていませんが、
関数型インターフェースの定義からすれば関数型インターフェースですね。
つまり
##AutoCloseableでないクラスをtry-with-resourcesでクローズする
Graphicsなんかまさにdisposeめんどくさいですね。
/**
* 自力でGraphicsをclose
*/
public static void disposeSample(BufferedImage image) {
Graphics graphics = image.createGraphics();
try {
//処理
} finally {
graphics.dispose();
}
}
簡単にはこうですが、場合によってはgraphicsのnull判定入れたりめんどくさいことこの上ないです。
ですがメソッド参照で
/**
* ラムダ式でAutoCloseable化。try-with-resourcesに。
*/
public static void disposeSample(BufferedImage image) {
Graphics graphics = image.createGraphics();
try (AutoCloseable closeable = graphics::dispose) {
//処理
} catch (Exception e) {
e.printStackTrace();
}
}
とするとtry-with-resourcesが使えるわけです
参考:AutoCloseableでなくてもtry-with-resourcesがしたい
が、これだとExceptionをcatchしないといけないので
/**
* throwsなしのAutoCloseable
*/
public interface MyCloseable extends AutoCloseable {
@Override
void close();
}
/**
* catchが不要になった
*/
public static void disposeSample(BufferedImage image) {
Graphics graphics = image.createGraphics();
try (MyCloseable closeable = graphics::dispose) {
//処理
}
}
とすれば完璧です!!MyCloseableを一つ作っておきましょう!
もう一段階難解にしたいなら下記のようにするのもおすすめです。
public static void disposeSample(BufferedImage image) {
Graphics graphics;
try (MyCloseable closeable = (graphics = image.createGraphics())::dispose) {
//処理
}
}
#Iterableってもしかして関数型インターフェース!??
Iterableは@FunctionalInterfaceはもちろんついていませんが、
関数型インターフェースの定義からすれば関数型インターフェースですね。
つまり、
##Iteratorを拡張for文で回す
/**
* Iteratorを拡張for文で回す。
*/
public static void iteratorFor() {
Iterator<String> iterator = Arrays.asList("A", "B", "C").iterator();//Iteratorを作りたいだけ。
for (String s : (Iterable<String>) () -> iterator) {
System.out.println(s);
}
}
とすると、Iteratorで拡張for文が使えるわけです!
もちろん今回の場合、普通はIterator#forEachRemainingを使って
/**
* 普通にIterator#forEachRemaining
*/
public static void iteratorFor() {
Iterator<String> iterator = Arrays.asList("A", "B", "C").iterator();//Iteratorを作りたいだけ。
iterator.forEachRemaining(System.out::println);
}
とJavaさんからは推奨されそうですが、
この場合、breakできないのが玉に傷ですね。
/**
* Iteratorを拡張for文で回す。
*/
public static void iteratorFor() {
Iterator<String> iterator = Arrays.asList("A", "B", "C").iterator();//Iteratorを作りたいだけ。
for (String s : (Iterable<String>) () -> iterator) {
if(s.equals("B"))
break;
System.out.println(s);
}
}
とかね。
##Listライクな情報からStream生成
これは難解コーディングではありませんが、次のテーマの下準備です。
sizeっぽい情報と、get(index)っぽいメソッドがあればStreamにすることができます。
/**
* StringBuilderをCharacterのListにする<br>
* 途中CharacterのStreamにしてる
*/
public static List<Character> stringBuilderToCharList() {
StringBuilder sb = new StringBuilder("ABC");
return IntStream.range(0, sb.length())
.mapToObj(sb::charAt)
.collect(Collectors.toList());
}
参考:http://www.ne.jp/asahi/hishidama/home/tech/java/stream.html#h_outline
の例「Excelのシート一覧取得」
さあここから、
##Streamを拡張for文で回す(Listライクな情報を拡張for文で回す)
Streamからiterator()を呼び出してラムダ式でIterable化すれば拡張for文が使えます。
/**
* StringBuilderを拡張for文で回す。
*/
public static void stringBuilderFor() {
StringBuilder sb = new StringBuilder("ABC");
for (Character c : (Iterable<Character>) () -> IntStream.range(0, sb.length()).mapToObj(sb::charAt)
.iterator()) {
System.out.println(c);
}
}
もちろんStreamもforEachメソッド持ってるので通常はそちらを使うべきですが、bre(略)
でもでも、collect(Collectors.toList())したら普通に拡張for文使えますよね?
その通り。使えますが比較してみると大きな違いがあります。
private static class ListLike {
public int size() {
return 10;
}
public String get(int index) {
System.out.println("get(" + index + ")");
return Integer.toString(index);
}
}
public static void iteratorFor() {
System.out.println("iteratorFor");
ListLike list = new ListLike();
for (String s : (Iterable<String>) () -> IntStream.range(0, list.size())
.mapToObj(list::get)
.iterator()) {
if(s.equals("4")){
break;
}
System.out.println("each " + s);
}
}
public static void collectFor() {
System.out.println("collectFor");
ListLike list = new ListLike();
for (String s : IntStream.range(0, list.size())
.mapToObj(list::get)
.collect(Collectors.toList())) {
if(s.equals("4")){
break;
}
System.out.println("each " + s);
}
}
実行結果はそれぞれ
- iteratorFor
iteratorFor
get(0)
each 0
get(1)
each 1
get(2)
each 2
get(3)
each 3
get(4)
- collectFor
collectFor
get(0)
get(1)
get(2)
get(3)
get(4)
get(5)
get(6)
get(7)
get(8)
get(9)
each 0
each 1
each 2
each 3
となりcollectは一回リストにするのでその分無駄があります。
やはりIterableをラムダ式で生成するのがスマート(!?)ですね!
こちらもどうぞ
Java8が好きになる話(StreamAPIの話はしない) その1 Map#computeIfAbsentとList#sort
Java8が好きになる話(StreamAPIの話はしない) その2 Optional#map
Java8が好きになる話(StreamAPIの話はしない) その3 インターフェースのデフォルト実装
Java8が好きになる話(StreamAPIの話はしない) その4 ラムダ式のインスタンス