アプリを作ってみた後の今の所感

初めて知ったJavaのメリット

  • 苦労してコーディングした後は一発で動きやすい
    型宣言の強みを身を持って理解できた。
    Eclipseのエラーを潰していって、全てのエラーや警告に対処が終わっていよいよ実行。一発で期待値が戻ってきて正常終了。唖然、、
    ネットワークプログラム作るときにrubyやpythonでは一発で通るなんて経験がなかったから驚いた。これはコーディング時に推測できるデータ値のレベルが、Javaの厳格な型宣言のお陰で、コーディング段階でエラー検出できる。
  • 実行性能がすごく良いっぽい。
    これがコンパイルという名の神か。いつかベンチマークしてみようと思う。
    直感的にループがめっちゃ速い気がする。
    無駄の無い処理ロジックをちゃんと組めれば、相当なパフォーマンスを得られそうだ。
  • pythonだとnetwork系のライブラリをパフォーマンス良く使いこなすためにコツがいるもんだが、ほぼサンプルソースそのままのJavaで意味わからず組んでみたところ、ブラウザより極端に遅いとかそういう不可思議な事態がなかった。
  • 他にいくつかあった気がするんだが、
    なんせいろんな調査に時間がかかり、何をしようとしていたか忘れてしまう程だった。

今も感じるJavaのデメリット

  • コードの視認性が悪い。無駄に行数が増える。
    ほぼ型変換のコーディングが無駄に感じるのだが、
    型宣言して、処理結果の値を取得し、次の処理に引数で渡す際に型が違うから
    合わせるための変換を行うというボイラーコードを必ず生む。
  • ファイル数が多くなりすぎ、嫌になる。
  • 生産性が悪い、と一概には言わないがお世辞にも良くは無いだろう。
  • 良くするには相当に便利ライブラリを用意する必要がある。
    今回のアプリのコア処理がIMAP接続、通信だったのだが、
    JavaMailというライブラリをどうやってインストールにハマッてしまった。

とりあえずJava開発の今後に備え、

  • 標準関数が低レベルすぎて直感的にコーディングできない。
    今回のアプリの初歩的な処理でファイルの読み込みがあったのだが、
    単なるローカルファイルからデータを読むことが、
    Javaではなぜこんなに難しく考えるのかが理解できない。
  • このままでは生産性が上がらないので、今後も使うであろう自作ライブラリをいくつか用意した。文末に掲載しておきました。
    不適切なロジックがあればコメント歓迎です。
  1. バイトデータからファイルへの変換
  2. ファイルからバイトデータへの変換
  3. 入力ストリームからファイルへの変換
  4. ファイルから入力ストリームへの変換
  5. ファイルやらディレクトリやらの再帰探索と並び替え
  6. ファイルの存在チェック
  7. ディレクトリの作成
  8. ディレクトリの削除
  9. ファイルの削除

<pythonの場合(close処理は説明上省略)>
data = open("hoge.vmg").read()
<rubyの場合>
data = File.open("hoge.vmg").read

<javaの場合(close処理は説明上省略)>
いろいろな方法があるようなのですが、ググった時によく見る例が以下
try{
  File file = new File("c:¥¥tmp¥¥test.txt");
  BufferedReader br = new BufferedReader(new FileReader(file));

  String str = br.readLine();
  while(str != null){
    System.out.println(str);

    str = br.readLine();
  }
}catch(IOException e){
  System.out.println(e);
}

おいおいprintするんじゃなくって「String data」っていう変数にファイル内容が欲しいだけなんすけどー、例が見つからない、どれ見てもみんなサンプルはprintだ。

data配列作ってappendしろっつうことか?なげーよ

try{
  List<String> data = new ArrayList<String>();
  File file = new File("hoge.vmg");
  BufferedReader br = new BufferedReader(new FileReader(file));

  String str = br.readLine();
  while(str != null){
    ret.add(str);

    str = br.readLine();
  }
}catch(IOException e){
  System.out.println(e);
}


readLineはあるのにread()は全部じゃないのか?かなり納得行かず気持ち悪いが
小一時間調べてみて、他にもいろんな方法が見つかるが何がどういう時の正解なのか、
こんなところで道草する訳にはいかない、、やること他に多数あるのでとりあえずコレでいいや。

まとめ

初めてJavaでプログラミングした。Javaプログラミングって吐き気すら感じてた。

今回どうしてもAndroidアプリを作るにあたり、Javaが必要になった。
人間必要に迫られれば頭に入るものだ。
Eclipseのコード補完の多大な恩恵があることはよく分かったが、型宣言や引数のデフォルト値が許されない等、よくも悪くも厳格なルールに基づいた言語だ。
それ故に相当な設計力が無いと、ボイラーコードがすぐ発生する。

結局のところなんでもできるのだが、
ファイルの読み書き、変数の初期化、正規表現の使い方、コマンドライン実行時のjavaクラスパスの解釈、などなど色々と直感的ではないから頭に入らない。
もう一回同じもの作れと言われてもはっきり行ってスラスラとは作れない。

rubyやpythonの自然言語では、疑問に思うことすらなかったことに尽くハマりストレスを溜めながらも何とかアプリは完成した。

ちなみにJavaにはコマンドラインで取得できるパッケージ管理は何でしょうか?
例えばrubyならrubygems, pythonならpip, easy_installに相当するものは?
maven?よくわからん、

あとはAndroidライブラリの使い方に不明点が多数あるのだが、それは後日まとめていくことにする。


(備忘録)次回に向けたお土産ライブラリ

public class FileTools {

    //バイトデータからファイルへの変換
    public static void byte2file(byte[] w,String fileName) 
        throws Exception {
        FileOutputStream fos=null;
        try {
            fos=new FileOutputStream(fileName);
            fos.write(w);
            fos.close();
        } catch (Exception e) {
            if (fos!=null) fos.close();
            throw e;
        }
    }

    //ファイルからバイトデータへの変換
    public static byte[] file2byte(String fileName) 
        throws Exception {
        int size;
        byte[] w=new byte[1024];
        FileInputStream fin=null;
        ByteArrayOutputStream ret=null;
        try {
            fin=new FileInputStream(fileName);
            ret=new ByteArrayOutputStream();
            while (true) {
                size=fin.read(w);
                if (size<=0) break;
                ret.write(w,0,size);
            }
            fin.close();
            ret.close();
            return ret.toByteArray();
        } catch (Exception e) {
            try {
                if (fin!=null) fin.close();
                if (ret!=null) ret.close();
            } catch (Exception ee) {
            }
            throw e;
        }
    }

    //入力ストリームからファイルへの変換
    public static void stream2file(InputStream input,String fileName) 
        throws Exception { 
        int size;
        byte[] w=new byte[1024]; 
        FileOutputStream fos=null;
        try {
            fos=new FileOutputStream(fileName);
            while (true) { 
                size=input.read(w); 
                if (size<=0) break; 
                fos.write(w,0,size); 
            };
            fos.close();
            input.close();
        } catch (Exception e) {
            try {
                if (input !=null) input.close();
                if (fos!=null) fos.close();
            } catch (Exception e2) {
            }
            throw e;
        }
    }
    
    //ファイルから入力ストリームへの変換
    public static InputStream file2stream(String fileName) 
        throws Exception {
        return new FileInputStream(fileName);
    }

    //ファイルシステム関係

    //ファイルの存在チェック
    public static boolean existsFile(String path) {
        return (new File(path)).exists();
    }    
    
    //ファイルの削除
    public static boolean deleteFile(String path) {
        return deleteFile(new File(path));
    }

    //ディレクトリの削除
    public static boolean deleteFile(File dirOrFile) {
        if (dirOrFile.isDirectory()) {
            String[] children=dirOrFile.list();
            for (int i=0;i walkfiles(String path) {
  List ret = new ArrayList();
  File root = new File(path);
  File[] list = root.listFiles();

  for (File f : list) {
   if (f.isDirectory()) {
    ret.addAll(walkfiles(f.getAbsolutePath()));
   } else {
    ret.add(f.getAbsoluteFile());
   }
  }
  return ret_sort(ret);
 }

 public static List walkdirs(String path) {
  List ret = new ArrayList();
  File root = new File(path);
  File[] list = root.listFiles();

  for (File f : list) {
   if (f.isDirectory()) {
    ret.addAll(walkdirs(f.getAbsolutePath()));
    ret.add(f.getAbsoluteFile());
   }
  }
  return ret_sort(ret);
 }

 public static List walk(String path) {
  List ret = new ArrayList();
  File root = new File(path);
  File[] list = root.listFiles();

  for (File f : list) {
   if (f.isDirectory()) {
    ret.addAll(walk(f.getAbsolutePath()));
    ret.add(f.getAbsoluteFile());
   } else {
    ret.add(f.getAbsoluteFile());
   }
  }
  return ret_sort(ret);
 }

 private static List ret_sort(List files) {
  if (modifydate_ordered) {
   Collections.sort(files, new ModifyDateComparator());
  } else {
   Collections.sort(files);
  }
  return files;
 }

 private static class ModifyDateComparator implements Comparator {
  @Override
  public int compare(File s, File t) {
   return (int)(s.lastModified() - t.lastModified());
  }
 }
}

0 コメント:

コメントを投稿