23
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kotlin で可愛く CSV

Posted at

Kotlin 可愛い!

私は普段 Java や Python を使うエンジニアですが、Kotlin が好きです。

単純なデータの Import/Export にはよく CSV 形式を使用していますが、Kotlin ならどれだけ気持ちよく書けるのか試してみました。

ソースコードはこちらです。→ motch0214/kotlin-csv-sample

Apache commons-csv

今回、CSV のパーサライブラリとして commons-csv を使用します。
単純な機能感のものですが、Kotlin との相性を考えると、むしろ適していると感じます。シンプルに書けるのが Kotlin の魅力のため、Annotation 等でゴテゴテする必要はないです。(個人の見解です。)

サンプルデータ

使用するデータは以下とします。

"Name","Address","Sex","Age","Birthday"
"茂木 康文","mogi_yasufumi@example.com","男",32,"1983-04-25"
"立川 弘也","tachikawa_hironari@example.com","男",69,"1946-05-12"
"宮田 真一","miyata_shinichi@example.com","男",79,"1935-09-13"
"浅田 俊二","asada_shunji@example.com","男",53,"1961-10-29"

ヘッダあり、数値以外はクォートされています。

対応する data class も用意します。

data class User(
        val name: String,
        val address: String,
        val sex: String,
        val age: Int,
        val birthday: LocalDate
)

また、今回はヘッダを指定して CSV 内の列を指定するため、以下のような enum class を使います。

enum class UserColumn(override val header: String) : Column {
    NAME("Name"),
    ADDRESS("Address"),
    SEX("Sex"),
    AGE("Age"),
    BIRTHDAY("Birthday"),
}

Column は単なる header へのアクセス用インターフェースです。


interface Column {
    val header: String
}

CSV の読み込み

では、読み込みロジック部分です。

private val DATE_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")

class UserReader(reader: Reader) : CSVReader<User>(reader) {

    private fun String.toLocalDate(): LocalDate = LocalDate.parse(this, DATE_FORMAT)

    override fun CSVRecord.parse() = User(
            name = column(NAME),
            address = column(ADDRESS),
            sex = column(SEX),
            age = column(AGE).toInt(),
            birthday = column(BIRTHDAY).toLocalDate())
}

なかなか可愛くないですか?

CSV のどの列がどのように User クラスにマッピングされるのかが一目瞭然だと思います。

ちなみに、ベースクラスである CSVReader は私が書いたものですが、数行しかない極小のラッパーです。(→ CSVReader
拡張関数を駆使して、いい感じの見た目になるように調整しています。

CSV の書き込み

次は、書き込みロジック部分です。

class UserWriter(writer: Writer) : CSVWriter<User>(writer, HEADERS) {

    companion object {
        private val HEADERS = UserColumn.values().toList()
    }

    override fun User.encode() = mapOf(
            NAME to name,
            ADDRESS to address,
            SEX to sex,
            AGE to age,
            BIRTHDAY to birthday.format(DATE_FORMAT))
}

読み込み同様、マッピングが一目瞭然になっています。

encode() の返り値は Map にしています。ヘッダの定義とマッピング部分の順番がずれているなんてしょうもないバグに悩まされたくないのです。

CSVWriter も私が書いたものですが、同じく薄いラッパーです。(→ CSVWriter

まとめ

大した道具を使わなくても、Kotlin ならば CSV とオブジェクトのマッピングロジックが明示的でわかりやすく書けたと思います。

わかりやすいのがとっても重要です。
(Javaだとなかなかこうはいきません。。)

みなさんも Kotlin を使って可愛くプログラミングをしてみませんか?

ご意見・ご指摘お待ちしています。

23
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?