ラベル Java の投稿を表示しています。 すべての投稿を表示
ラベル Java の投稿を表示しています。 すべての投稿を表示

2013年1月1日火曜日

Scalaでダックタイピング?implicitを使ってみたよ

あけましておめでとうございます。

年明け最初の記事は、Scalaの勉強ということでimplicitを使ってみた話。

Javaの実装でtoHoge()な書式が好きなので、interfaceを使って実現をするのですが、
既存のクラスに関してはそれができません。

その具体例と、対応方法は次のコード。
Outputableを実装したクラスを受け取って出力を行うクラスです。



自前のクラスに関しては、implementsすれば好き勝手に実装ができますね。



そして出力用のコード。



しかし、既存のクラスに関してはそうはいかないので、ラッパークラスを
用意することになります。





呼び出し元も、新しいクラスを呼び出したりで面倒くさい。

Javaという言語は面倒臭いですん。

さて、Rubyではもっと柔軟な感じにいけて、クラスの定義を
コードの途中で再開させることができるのです。

まずは、自前のクラスに対しての実装。




そして、既存のクラスの拡張。




Rubyって便利。

そして、最後にScala。暗黙的変換のimplicitキーワードを使ったメソッドを
用意することで、コンパイラが自動的に適した型に変換するメソッドを呼び出して
くれるのです。







implicitを使って変換を行う例。





実に気持ちがいい。呼び出し元は、クラスの変換とか意識しなくていいんですよ。

ただ、Javaでも型変換にtoHoge()な実装をしない
コードをたくさん見てきたので、ちょっとアレ。

今年も、綺麗なコードを求めてがんばりますね。

さて、今回参考にした書籍は次。


あと、最近はPlay frameworkを使ってScalaを
勉強してます。

2012年4月14日土曜日

【Java】WikipediaシソーラスAPIを使う【wikipedia】

Wikipediaシソーラスを使う。

企画しているAndroid道で作る練習アプリのネタで、Wikipediaシソーラスを使おうかなって考えました。

と言うのも、なんか
  • AndroidやJavaの基本機能の練習はやりたい
  • でも、作って面白いものにしたい
  • 誰かに自慢できる感じのもの
  • ちょっと、斜め上を目指した感じ

のアプリを作ろうとおもったから。ランダムにWikipediaの項目を表示するアプリはあるけれど、シソーラス検索するアプリは無ってことで、オリジナリティもあるし。

早速、SIGWPからWikipediaAPIのソースをDLしてきました。

実は、WikipediaAPIへのチャレンジは2回目。卒研の時も、このライブラリを使おうと思ったけど、なぜか上手く行かず。

仕方なく、WEBにで提供されている検索結果のHTMLを解析する荒業に出ました。

まあ、理由は色々とあるのですが、そもそも公式でリファレンスを配布していないことも原因の一つかと。

Apache/Axisくらい使えるよね? って感じでしょうか。いや、いいんですけど。

公式サイトに設定されているコードの例もどうやら古いバージョンのものらしく、掲載されているクラスもメソッドも無い。

どうにか、ソースを読んで使えるようになりました。シソーラス単語と関連度を取得するコードが以下。

public class Main {
 // private static final String TAG = Main.class.getSimpleName();

 /**
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  // TODO Auto-generated method stub
  ServiceStub serviceStub = new ServiceStub();

  GetTopCandidateIDFromKeyword keyword = new GetTopCandidateIDFromKeyword();
  keyword.setKeyword("サクラ大戦");
  keyword.setLanguage("Japanese");

  GetTopCandidateIDFromKeywordResponse response = serviceStub
    .getTopCandidateIDFromKeyword(keyword);

  GetThesaurusDS getThesaurusDS = new GetThesaurusDS();
  getThesaurusDS.setLanguage("Japanese");
  getThesaurusDS.setIFrom(response
    .getGetTopCandidateIDFromKeywordResult());

  GetThesaurusDSResponse resp = serviceStub
    .getThesaurusDS(getThesaurusDS);
  GetThesaurusDSResult_type0 result = resp.getGetThesaurusDSResult();
  OMElement element = result.getExtraElement();
  XMLStreamReader reader = element.getXMLStreamReader();
  try {
   while (reader.hasNext()) {
    reader.next();
    if (reader.isStartElement()) {
     String tagName = reader.getName().toString();
     if (tagName.equals("l_weight") || tagName.equals("name")) {
      reader.next();
      System.out.println(reader.getText());
     }
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
   System.out.println("error");
  } finally {
   try {
    reader.close();
   } catch (Exception e) {

   }
  }
  System.out.println("end");
 }


XMLの解析でちょっと手こずったりしましたが、何とかうまくいきました。

得られるデータは、関連度順でソートされているようです。ですが、今回は関連度は利用するつもりは無いのでこの順番を維持したまま返してやる仕組みを作ればいいかなと。

しかし、与えられているメソッドの名前はどうにかなりませんかね・・・。getGethogehogeとか、もうね。

2012年3月12日月曜日

ループ内でのインスタンス作成

ちょっと、釈然としない問題があったのでメモ。

Befor

for (final String imageUrl : stringlList) {
    final URL url = new URL(imageUrl);//Warning
    ...
 }


このコードだと、PMDで ループ内でインスタンスを作るのは避けてください(Avoid instantiating new objects inside loops)が表示されてしまう。 色々と解決方法を検討した結果 After

for (final String imageUrl : stringList) {
    final URL url = createURL(stringList);
   }

private URL createURL(final String url) throws MalformedURLException {
 return new URL(url);
}


とすることで警告を消すことができた。 メソッドに分けただけで、同じじゃないか・・・? 可読性とかも変わっていないような気がするし、メモリ管理の面で見ても結局はループ内でのインスタンスを作成していることに変わりは無い。 まあ、そのうちベンチマークしてみるとするか・・・。

2012年3月2日金曜日

[JUnit]DatePickerをテストケースから操作する[Android]

Androidのテストでは、ウィジェットの操作はUIのスレッドで動作させる必用があるとのこと。

今回は、DatePickerを操作する。ソースは以下。

  activity = getActivity();

  fromDate = (DatePicker) activity.findViewById(R.id.from_data);
  toDate = (DatePicker) activity.findViewById(R.id.to_data);
  activity.runOnUiThread(new Runnable() {

   @Override
   public void run() {
    // TODO Auto-generated method stub
    fromDate.init(fromY, fromM, fromD, null);
    toDate.init(toY, toM, toD, null);
   }
  });
アクティビティのインスタンスから、runOnUiThreadを使ってUIのスレッドでの動作を行わせるとのこと。

今夜はリファクタリング的なことをやって、無駄に増えていった処理用のクラスを纏めていました。


リファクタリングとは、外部から見た時の挙動が変わってはいけない、とのこと。この本に書かれていた。

多分、クラスを分ける必用があるんだろうなぁとは思うけれど、どう分ければいいのかがよく分かっていなくて、後から見返すとかなりアレなことになっていることが多い。

2012年2月26日日曜日

【JUnit】データベースを操作するテスト【試してみた?】



先日作ったByte配列に変換したりその逆にしたりするメソッドを利用して、データベース周りを実装する。

割りと、参考サイトを見ていると実装の方法は同じなので今回つまった部分とか。

Blob型で保存をするので、PupSQLiteなどのビューアを利用してもデータの内容の確認ができない。そこで、正しくデータが保存できているのか等を確認するために、JUnitを利用することにする。

Byte配列とは出るけど、内容確認は無理




1:データベース操作クラスのテスト
  • データを挿入するinput
  • 削除するdelete
  • 全てのデータを得るfindAll
  • 任意のデータを得るfindById

それぞれのテストの実装は次の通り。
public class PartyDaoTest extends AndroidTestCase {
 DbHelper helper;
 PartyDao dao;

 Party party; //保存対象のデータ

 public PartyDaoTest() {
 }

 protected void setUp() throws Exception {
  super.setUp();

  helper = new DbHelper(getContext());
  dao = new PartyDao(helper.getReadableDatabase());

  setData();
 }


 protected void tearDown() throws Exception {
  super.tearDown();
 }

 public void testInsert() {
  assertNotNull("Should be not null if save data", dao.insert(party));
 }

 public void testFindAll() {
  dao.insert(party);
  
  assertTrue("Should be returned bigger than one.",
    dao.findAll().size() > 1);
 }

 public void testDelete() {
  assertNotNull("Shoudl be not null", dao.delete((int) dao.insert(party)));
 }

 public void testFindById() {
  int id = (int) dao.insert(party);
  Party p = dao.findById(id);
  
  assertEquals(party.getDate(), p.getDate());
 }
}

問題なくテストも成功するから多分、大丈夫。

2:利用するActivityのテスト

保存対象のデータ'Party'を新たに作ったIntentにputし,setActiviyIntentでActivityに渡す。

testSaveData()で、実際のテストを行なっている。ちなみに、テスト対象のsaveData()メソッドは、データを保存すると返り値としてデータのIDを返すと言う物。
public class SelectMemberActivityTest extends
  ActivityInstrumentationTestCase2<テスト対象のActivity> {

 Party party; //保存対象のデータ
 SelectMemberActivity mActivity;

 public SelectMemberActivityTest() {
  super("パッケージ名", テスト対象のActivity.class);

 }

 protected void setUp() throws Exception {
  super.setUp();
  Intent intent = new Intent(getInstrumentation().getContext(),
    テスト対象のActivity.class);
  party = setData();
  intent.putExtra("store_data", party);

  setActivityIntent(intent);
 }

 protected void tearDown() throws Exception {
  super.tearDown();
 }

 public void testSaveData() {
  assertNotNull("データを保存する.返り値がNull以外で成功とする", getActivity().saveData());
 }
}

さて、この簡単な実装だけど最初コンストラクタになぜか引数がついていてRuntimeExceptionが発生してた。気づいて修正するのにほぼ1日かかったって言うね・・・。ココみて直した。

さて、興味があるのでJUnitとか使ってますけど、決して今の開発スタイルはTDDとは言えないと思います。

そもそも、今回書いたテストも正しいテストと言えるのか分からない。その辺りは勉強なんだけど。

今風のソフトウェア開発の本を読めば多分書いてあるんだろうね。まあ、実践も一緒にやっていきたい所ではあるけれど。

多分今回書いたのはこのスライドで言うところの学習テストに当たるのかな。初めて使う機能だもんね、しっかりと抑えておきたい所ではある。

2012年1月15日日曜日

【アップデート】タイムキーパー ドラ娘



ドラ娘には会ったことがない。

会ったことがないなら、作ればいいじゃないかってことで、かつてリリースしたこのアプリ。

アイコン
もともと、機能なんかも少なくてリリースして放置していた。

だが、10月くらいにアンドロイダーさんで記事にしていただいていた。全く気づかなかったけど。

という訳で、モチベーションが上がったのでアップデート。

まずは、インターフェースの変更。

実は、画面のドラ娘をタップすることで任意のタイミングでドラを鳴らすことができた。

しかし、アンドロイダーさんでもその点に触れられていなかったことから、この機能に気づかなかった人が多かったのでは、と想像。

スクショ
そこで、Doraボタンを追加。これで大丈夫でしょう。

次に、音量関連の問題。端末の音量や、調整ができないことは割りと不便かなと。

そこで、画面上に現在の音量を表示。端末のボリュームボタンを使って調整を行えるように変更。

目立った更新はこの辺ですかね。あとは、タイトルバーを消して、アクションバーのようなものを追加したり。

という訳で、今後は
・バックグラウンドに回っても音がなるようにする

・設定を保存できるようにする。

とかを考えてはいます。

アプリのDLはこちらからどうぞ。