1. 3 行のテキスト "a\nb\nc" は 3 行と数える
  2. 空文字列 "" は 0 行
  3. 改行を含まない "hello" は 1 行
  4. 末尾改行 "a\nb\n" は 2 行 (末尾改行のみは行とみなさない)
  5. 改行のみ "\n" は 1 行 (空行 1 つとして数えられる)
コース一覧
Java 中級:コレクション・Stream・例外処理
ファイルを行単位で読む

Java 中級:コレクション・Stream・例外処理

コレクション、ジェネリクス、例外処理、Stream API、関数型インターフェース、日付処理、ファイル I/O、継承など Java の中級トピックを実践的に学べるコースです。Java の基礎文法とオブジェクト指向を理解している学習者を対象に、現場の Java コードを読み書きするための知識を補強します。約 16 時間 (1 日 30 分 × 32 日) で 64 レッスンを修了でき、修了後は Spring Boot や業務システム開発に必要な Java 力が身につきます。

1
コレクション基礎
01. ArrayList を使う5分
02. List を走査する5分
03. 要素の削除と検索5分
04. HashMap の基本5分
05. Map を走査する5分
06. Set で重複を排除5分
07. Collections クラスの便利メソッド5分
08. コレクション基礎 まとめクイズ5分
2
ジェネリクス
01. ジェネリッククラスを作る5分
02. ジェネリックメソッド5分
03. 境界型パラメータ5分
04. ワイルドカード ?5分
05. Pair<K,V> を作る5分
06. ジェネリクス まとめクイズ5分
3
例外処理
01. try-catch で例外をつかむ5分
02. 複数の catch ブロック5分
03. throws と例外の伝播5分
04. 独自の例外を作る5分
05. try-with-resources5分
06. finally ブロック5分
07. 例外処理 まとめクイズ5分
4
Stream API
01. Stream を作る5分
02. filter で絞り込む5分
03. map で変換する5分
04. reduce で集約する5分
05. collect で集める5分
06. sorted で並び替え5分
07. distinct で重複排除5分
08. limit と skip5分
09. 並列ストリーム5分
10. Stream API まとめクイズ5分
5
関数型インターフェース
01. ラムダ式の基本5分
02. メソッド参照 ::5分
03. Function インターフェース5分
04. Predicate インターフェース5分
05. Consumer と Supplier5分
06. BiFunction と 2 引数の関数5分
07. 関数型インターフェース まとめクイズ5分
6
文字列操作
01. String.format で書式化5分
02. StringBuilder で連結5分
03. 正規表現の基本5分
04. split と join5分
05. 文字列操作 まとめクイズ5分
7
日付と時刻
01. LocalDate で日付を扱う5分
02. LocalDateTime で時刻も扱う5分
03. Duration で時間差を計算5分
04. 日付の書式化とパース5分
05. 日付の加減算5分
06. 日付と時刻 まとめクイズ5分
8
ファイル I/O
01. Files でファイルに書き込む5分
02. ファイルを行単位で読む5分
03. Path でファイルパスを扱う5分
04. BufferedReader と Stream API5分
05. ファイルの存在確認と削除5分
06. ファイル I/O まとめクイズ5分
9
継承とポリモーフィズム
01. extends で継承する5分
02. super で親を呼ぶ5分
03. メソッドのオーバーライド5分
04. abstract で抽象クラス5分
05. interface で契約を定義5分
06. default メソッド5分
07. instanceof と型パターン5分
08. ポリモーフィズムを活かす5分
09. 継承とポリモーフィズム まとめクイズ5分

ファイルを行単位で読む

1 行ずつ読むだけなのに、while と null 判定が要る

ログを 1 行ずつ確かめたい、設定ファイルを上から順に処理したい。やりたいことは「行の並びが欲しい」だけなのに、昔ながらの書き方だと BufferedReader を用意して、readLine() の戻り値を変数に代入しながら null と比べる while を回し、読み終えたら閉じる、という手続きが要りました。本題に入る前の準備がやたらと長いのです。

Files.readAllLines は、その全部を 1 行にまとめてくれます。渡した Path のファイルを開いて最後まで読み、閉じたうえで List<String> を返します。

Java

import java.nio.file.Files; import java.nio.file.Path; import java.util.List; public class Demo { public static void main(String[] args) throws Exception { List<String> lines = Files.readAllLines(Path.of("access.log")); System.out.println(lines.size()); for (String line : lines) { System.out.println(line); } } }

各要素に入るのは行の中身だけで、末尾の \n や \r\n は取り除かれています。返ってくるのは見慣れた List なので、size() で行数を数えるのも、for で回すのも、stream() につなぐのも思いのままです。ファイルは戻ってきた時点ですでに閉じられているので、自分で閉じる必要はありません。

末尾の改行は 1 行として数えない

行数を数えると、多くの人が「1 行多いはず」「1 行足りない」で止まります。数え方には決まりがあり、最後の改行のうしろは行として数えません。

  • "a\nb\nc" は ["a", "b", "c"] で 3 行
  • "a\nb\n" は ["a", "b"] で 2 行
  • "hello" は ["hello"] で 1 行
  • "\n" は [""] で 1 行

"a\nb\n" が 2 行なのは、改行を「行の終わりを示す印」として読んでいるからです。最後の \n は 2 行目を閉じただけで、そのうしろに 3 行目が始まっているわけではありません。テキストファイルの末尾に改行を置く習慣は Unix から続くもので、多くのツールがこの数え方で一致しています。

空のファイルの場合、返るのは null ではなく要素 0 個の List です。if (lines == null) のような身構えは要らず、lines.isEmpty() で判定します。

Java

List<String> empty = Files.readAllLines(Path.of("empty.txt")); System.out.println(empty.size()); // 0 System.out.println(empty.isEmpty()); // true
解説

文字化けしたときは、まずファイル側の文字コードを疑ってください。引数 1 つの readAllLines は UTF-8 として読むので、Shift_JIS で保存されたファイルを渡すと化けるか、MalformedInputException で落ちます。第 2 引数に Charset を渡せば読み分けられます。

やってみよう

Solution.countLines(String content) を完成させます。

  1. 一時ファイルを作り、受け取った content を書き込む
  2. そのファイルを Files.readAllLines で読み返す
  3. 返ってきた List<String> の行数を int として return する
  4. 後始末として一時ファイルを削除する

一時ファイルの作り方と書き込みは前回のとおりです。countLines("a\nb\n") は 3 ではなく 2、countLines("") は 0 を返します。上の数え方の表と突き合わせながら確かめてください。

要件

  1. java.nio.file.Files.createTempFile で一時ファイルを作成し、その Path を使うこと
  2. Files.writeString(path, content) で引数の文字列を書き込み、Files.readAllLines(path) で読み返すこと
  3. 読み返した List<String> の size() を int として return すること (Files.lines(p).count() を使う場合は (int) でキャストする)

入出力例

countLines("a b c") → 3 countLines("") → 0 countLines("hello") → 1 countLines("a b ") → 2 countLines(" ") → 1

ヒント

`Files.createTempFile("demo", ".txt")` は接頭辞と拡張子だけ指定すれば、衝突しないユニークなパスを自動で作ってくれます

`Files.readAllLines` は末尾改行を行として数えないため、`"a\nb\n"` の `size()` は `2` です。テストの期待値もこの仕様に合わせています

メソッドシグネチャに `throws Exception` を付けておけば `IOException` を個別に `try-catch` しなくても呼び出せます

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

関連レッスン

  • Path でファイルパスを扱う

    java.nio.file.Path と Paths.get を使って、OS 非依存にファイルパスを組み立てたり分解したりする基本を学ぶ。

  • BufferedReader と Stream API

    BufferedReader の発想を引き継ぎつつ、Files.lines で 1 行ずつ Stream<String> としてファイルを読み込み、Stream API で集計するモダンな書き方を学ぼう。

  • ファイルの存在確認と削除

    Files.exists / Files.delete などの基本 API を使い、一時ファイルを作って存在を確認し、削除してからもう一度確認するコードを書いてみよう。

  • ファイル I/O まとめクイズ

    ファイル I/O 章 (Files / Path / BufferedReader / try-with-resources) の総まとめ。書き込み API の使い分け、リソースの自動 close、文字コード、例外処理の組み合わせを 4 択クイズで再確認する。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 処理計算や代入を表す長方形
  • 戻り値呼び出し元への返答を表す点線矢印
  • 変数データに名前をつけて参照する仕組み
  • 文字化け送受信側のエンコード不一致による表示崩れ
  • 文字コード文字に番号を割り当てるルール体系
  • 引数位置引数=順番で渡す。
  • instanceof「このオブジェクトの実際の型は何か」を確認 → 安全に変換
main.java
学習モード
エディタを読み込んでいます

メモ

ファイルを行単位で読む

⌘S で保存