CSV書込み、(1)

5年も前に CSVを生成する Javaプログラムコードを、csv4j を使って書いていた。


2011年 3月
http://oboe2uran.hatenablog.com/entry/2011/03/19/101643CSV書き込み(1) - Oboe吹きプログラマの黙示録

http://oboe2uran.hatenablog.com/entry/2011/03/22/210219CSV書き込み(2) - Oboe吹きプログラマの黙示録

http://oboe2uran.hatenablog.com/entry/2011/03/25/121714CSV書き込み(3) - Oboe吹きプログラマの黙示録

でも、1年前、これだと使い勝手が悪くて、 net.sf.csv4j.CSVWriter を使いたくなり、当時、環境としても Java7のままだったので、

次のインターフェースを用意して

public interface Csvoutable{
   /**
    * net.sf.csv4j.CSVWriter#writeLine(String[]) に渡す String[] を生成する。.
    * @return String[]
    */
   public String[] arrays();
}

このインターフェースで受け取った文字列配列をCSV出力する抽象クラスを用意して使った。

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.function.Supplier;
import net.sf.csv4j.CSVWriter;
/**
 * CSV作成抽象クラス.
 */
public abstract class CsvBinary{
   /**
    * ヘッダ行の提供.
    * @return CSVヘッダとなるString配列
    */
   protected abstract String[] getHeaders();

   /**
    * CSVコンテンツ行の提供.
    * @return CSVコンテンツとなる Csvoutable のコレクション
    */
   protected abstract Collection<? extends Csvoutable> getElements();

   /**
    * CSV生成.
    * @param bout 書込み先 OutputStream
    */
   public void write(OutputStream out){
      try{
         OutputStreamWriter writer = new OutputStreamWriter(out, "MS932");
         CSVWriter csvWriter = new CSVWriter(writer);
         csvWriter.writeLine(getHeaders());
         for(Csvoutable c:getElements()){
            String[] a = c.arrays();
            String[] s = new String[a.length];
            for(int i=0;i < s.length;i++){
               s[i] = a[i]==null ? "" : a[i];
            }
            csvWriter.writeLine(s);
         }
         writer.close();
      }catch(Exception e){
         throw new RuntimeException(e.getMessage(), e);
      }
   }
}

使用例は、、

CsvBinary csvbinary = new CsvBinary(){
   @Override
   protected String[] getHeaders(){
      return new String[]{ "A", "B", "C" };
   }
   @Override
      protected Collection<? extends Csvoutable> getElements(){
      return getLineData();
   }
};

のように生成して、getElements で呼ぶgetLineDataは、、

rotected List<Csvoutable> getLineData(){
   List<Csvoutable> csvlist = new ArrayList<Csvoutable>();

   // DB読込み等ハンドラの中で以下を実行

   csvlist.add(new Csvoutable(){
      @Override
      public String[] arrays(){
         return new String[]{
            "11","12","テスト"
         };
      }
   });
   return csvlist;
}

CSVのヘッダ行とデータ行の書込みを明示的で見通しが良いと、1年前は思っていた。
でも、長くて複雑な出力要求がきたら、どうなんだ!?
→ そういう要件自体が問題なんですけど。

Csvoutable に、@FunctionalInterface() を付けたところで
1行書き出し文が、ラムダに代わるくらい、、、

Collection> を返すようメソッドを CsvBinary の中で、、
としても、、

たいして魅力的なコードにはならない。

→ つづきを、CSV書込み(2)で。。。