CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第9章 Java 7 の機能を復習する : 問題 11 : ProcessBuilder

問題

ProcessBuilderクラスを使って、ユーザーのホームディレクトリの全てのサブディレクトリ内の全てのファイルからクレジット番号を探すために "grep -r" を呼び出すプログラムを作成せよ。
そして、ファイル内で見つけた番号を収集せよ。

解答

クレジット番号は結構複雑な規則があるみたいだけど、単純に14~16桁の数字列とします。
正規表現で表すと

[0-9]{14,16}

となる。

// grep コマンド実行
ProcessBuilder builder = new ProcessBuilder("grep", "-r", "[0-9]{14,16}", "./");
File home = new File(System.getProperty("user.home"));
builder.directory(home);
File outputFile = File.createTempFile("card", ".txt");
builder.redirectOutput(Redirect.to(outputFile));
Process process = builder.start();
try {
    process.waitFor();
} catch (InterruptedException ex) {
    // 無視
}
// ファイルからクレジット番号を収集
Pattern pattern = Pattern.compile("[0-9]{14,16}");
Set<String> cards = new HashSet<String>();
for (String line : Files.readAllLines(outputFile.toPath())) {
    Matcher matcher = pattern.matcher(line);
    while (matcher.find()) {
        cards.add(matcher.group());
    }
}

私のマシンは Windows なので、「ファイルからクレジット番号を収集する」方のコードは動作確認しましたが、「grep コマンド実行」がちゃんと動くかどうかは未確認です。
悪しからず。

第9章 Java 7 の機能を復習する : 問題 10 : java.util.Objects クラス その 2

問題

次のLabeledPointクラスのcompareToメソッドを実装せよ。

public class LabeledPoint {
    private String label;
    private int x;
    private int y;
    ...
}

解答

Java 8 で導入されたComparatorの default メソッドthenComparingを使えば一発なんだけど、ここは Java 7 なので我慢して…

public int compareTo(LabeledPoint other) {
    Objects.requireNonNull(other);
    if (Objects.compare(label, other.label, String.CASE_INSENSITIVE_ORDER) != 0)
        return Objects.compare(label, other.label, String.CASE_INSENSITIVE_ORDER);
    else if (Integer.compare(x, other.x) != 0)
        return Integer.compare(x, other.x);
    else
        return Integer.compare(y, other.y);
}

第9章 Java 7 の機能を復習する : 問題 9 : java.util.Objects クラス

問題

次のLabeledPointクラスのequalsメソッドとhashCodeメソッドを実装せよ。

public class LabeledPoint {
    private String label;
    private int x;
    private int y;
    ...
}

解答

java.util.Objects クラスを使用する。

equalsメソッド

public boolean equals(Object other) {
    if (!(other instanceof LabeledPoint))
        return false;
    LabeledPoint point = (LabeledPoint)other;
    return Objects.deepEquals(
        new Object[]{      label,       x,       y},
        new Object[]{point.label, point.x, point.y}
    );
}

hashCodeメソッド

public int hashCode() {
    return Objects.hash(label, x, y);
}

第9章 Java 7 の機能を復習する : 問題 8 : Integer.compare と Integer#compareTo

問題

整数の X 座標と Y 座標をフィールドに持つPointクラスのcompareToメソッドを、Integer#compareToを使わないで実装せよ。

public int compareTo(Point other) {
    int diff = Integer.valueOf(x).compareTo(other.x);
    if (diff != 0)
        return diff;
    return Integer.valueOf(y).compareTo(other.y);
}

解答

Integer#compareToメソッドは、JDK 1.2 で導入されたIntegerオブジェクト同士の比較メソッドである。
従って、毎回Integerオブジェクトを生成することになる。

ところが Java 7 で導入されたInteger.compareメソッドは、intを対象としているためIntegerオブジェクトを生成する必要がない。

Integer.compareメソッドを使用

public int compareTo(Point other) {
    int diff = Integer.compare(x, other.x);
    if (diff != 0)
        return diff;
    return Integer.compare(y, other.y);
}

第9章 Java 7 の機能を復習する : 問題 7 : Files.copy の威力

問題

URL.openStreamFiles.copyを使って、Web ページの内容を読み込んで、ファイルに保存するプログラムを作成せよ。

解答

私のはてなブログをファイルに書き出してみよう。

URL url = new URL("http://closedunbounded.hatenablog.com/");
try (InputStream stream = url.openStream()) {
    Files.copy(stream, Paths.get("blog.html"), StandardCopyOption.REPLACE_EXISTING);
}

Files.copy(InputStream, Path, CopyOption...)メソッドは凄い便利ですね。

第9章 Java 7 の機能を復習する : 問題 6 : Files.readAllLines の威力

問題

Files.readAllLinesFiles.writeを使って、ファイルから全ての行を読み込み、逆順に書き出すプログラムを作成せよ。

解答

ファイルの文字コードUTF-8 と仮定する。

List<String> lines = Files.readAllLines(Paths.get("/usr/share/dict/words"));
Collections.reverse(lines);
Files.write(Paths.get("/tmp/out.txt"), lines);

第9章 Java 7 の機能を復習する : 問題 5 : Files.readAllBytes の威力

問題

Files.readAllBytesFiles.writeを使って、ファイルから全ての文字を読み込み、逆順に書き出すプログラムを作成せよ。

解答

ファイルの文字コードUTF-8 と仮定する。

byte[] bytes = Files.readAllBytes(Paths.get("/usr/share/dict/words"));
StringBuilder content = new StringBuilder(
    new String(bytes, StandardCharsets.UTF_8)
);
content.reverse();
Files.write(
    Paths.get("/tmp/out.txt"),
    content.toString().getBytes(StandardCharsets.UTF_8)
);

words ファイルの改行コードが CR+LF だと、LF, CR という順番で出てきますけどね。