目次
1. はじめに
2. Java の for 文
3. guava
4. 実装
5. まとめ
参考文献
1. はじめに
Java 100 本ノック、55 本目の応用。
業務で Java を使うので、Java 100 本ノックを使い学習をしています。55 本目の問題は、ファイルを読み 1 行の文字数を合計して出力するプログラムを実装するというものですが、応用として読んだ行に行番号をつけて別ファイルに書くプログラムを実装することにしました。
Python の for 文では簡単にインデックスを扱える。
Java では、Files
や BufferedReader
を使えばファイルの中身を String
の List
や Stream
で取得できます。なので、for 文や Stream
でインデックスと要素を取得すれば簡単に実装できるなと思いました。Python では簡単にできるので。
list = ['a', 'b', 'c']
for idx, element in enumerate(list):
print(f'{idx} {element}')
0 a
1 b
2 c
でも、Java ではこんな便利機能はすぐに見つからなかった......
2. Java でインデックスと要素を扱う
拡張 for 文
import java.util.List;
public class Sample {
public static void main(String[] args) throws Exception {
List<String> list = List.of("a", "b", "c");
int idx = 0;
for (String element : list) {
System.out.println(String.format("%s %s", idx, element));
idx++;
}
}
}
まあできるけど、idx のスコープがいけてないよね。
普通の for 文
import java.util.List;
public class Sample {
public static void main(String[] args) throws Exception {
List<String> list = List.of("a", "b", "c");
for (int idx = 0; idx < list.size(); idx++) {
String element = list.get(idx);
System.out.println(String.format("%s %s", idx, element));
}
}
}
古臭い。
IntStream
import java.util.List;
import java.util.stream.IntStream;
public class Sample {
public static void main(String[] args) throws Exception {
List<String> list = List.of("a", "b", "c");
IntStream
.range(0, list.size())
.mapToObj(i -> String.format("%s %s", i, list.get(i)))
.forEach(System.out::println);
}
}
まだ許せるが何をやっているかわかりにくい。List
を操作してる感がない。そもそも BufferReader
を使いたいから List
は NG だった。
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Sample {
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("a", "b", "c");
List<String> list = stream.toList();
IntStream
.range(0, list.size())
.mapToObj(i -> String.format("%s %s", i, list.get(i)))
.forEach(System.out::println);
}
}
まったくいけてない......
3. guava
コア API だけでは厳しそうだということで調べてみると、guava という Google が開発しているライブラリを見つけました。Streams.mapWithIndex
使えば良さそう。
import com.google.common.collect.Streams;
import java.util.stream.Stream;
public class Sample {
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("a", "b", "c");
Streams.mapWithIndex(
stream,
(element, idx) -> String.format("%s %s", idx, element)
)
.forEach(System.out::println);
}
}
python の enumerate
と全く同じ要領で使えて感動。
4. 実装
本題の実装。テキストファイルを 1 行ずつ読み、行番号をつけて新規ファイルに出力するプログラムです。
import com.google.common.collect.Streams;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* 応用。
*/
public class ExAnswer055 {
/**
* メインメソッド。
*
* @param args コマンドライン引数
*/
public static void main(String[] args) {
Path input = Path.of("./src/main/resources/MyAnswer055.txt");
Path output = Path.of("./src/main/resources/exoutput055.txt");
try (
BufferedReader reader = Files.newBufferedReader(
input,
StandardCharsets.UTF_8
);
BufferedWriter writer = Files.newBufferedWriter(
output,
StandardCharsets.UTF_8
)
) {
Streams.mapWithIndex(
reader.lines(),
(str, idx) -> String.format("%s %s%n", idx + 1, str)
)
.forEach(i -> write(writer, i));
} catch (IOException | UncheckedIOException e) {
e.printStackTrace();
}
}
private static void write(BufferedWriter writer, String line) {
try {
writer.write(line);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
シンプルでいい感じに実装できました。プライベートメソッドの write
は、writer.write(line)
で IOException
が出るので、非チェック例外にして throw するために作りました。Stream
内で try-catch はしたくないので。
5. まとめ
Python でデータ処理する時は enumerate
を頻繁に使っていたので、Java でも標準であってもいいと思うんですけどね。まあでもこんな感じでコア API 以外も自分で調べて使いこなせてきたのでヨシ!
参考文献
- Stream の中間操作で index を扱う, Junpei Katayama (Zenn), https://zenn.dev/junpei_katayama/articles/b8a549f104a0a0, 2023-09-25 確認
- 【Java入門】要素数をカウントする方法(ストリームAPI), kitanote, https://kita-note.com/java-stream-count, 2023-09-25 確認
- guava, maven central repository, https://central.sonatype.com/artifact/com.google.guava/guava, 2023-09-25 確認
- Streams.mapWithIndex, com.google.guava, https://www.javadoc.io/doc/com.google.guava/guava/21.0/com/google/common/collect/Streams.html#mapWithIndex-java.util.stream.Stream-com.google.common.collect.Streams.FunctionWithIndex-, 2023-09-25 確認