メイン

tips: JAVA アーカイブ

2004年12月15日

StringBuffer の文字列比較

非常に単純なことなのですが、JAVA を始めた際にしばらく気づかず苦労しました。
StringBuffer クラスのインスタンスの文字列を比較しようとした場合、 たとえば "aaa" という文字と等しいという条件を判断しようとした際

StringBuffer sb = new StringBuffer("aaa");
if(sb.equals("aaa")){ ... }

とすると条件式は false になってしまいます。 なぜかというと、sb は StringBuffer クラスなのですが "aaa" は String クラスのため、等しくないと判断されてしまうのです。
この場合

if(sb.toString().equals("aaa")){ ... }

とするとよいようです。

JAR ファイル内に画像ファイルなどを含める

画像ファイルを JAVA プログラム内で使用する場合 とりあえず使うにはイメージ関連のクラス(Swing なら ImageIcon)のコンストラクタに ファイル名を渡せばよいですが、 この方法だと JAR ファイル化した時に画像ファイルを JAR ファイルに含められません。 (ファイル名指定だとファイルそのものを取得しようとするため)。

この場合、クラスローダーというクラスの getResource というメソッドを使用すれば 画像などのファイルを URL もしくは InputStream の形で取得できます。 クラスローダーは java の実行時に必要なクラスをクラスパスの JAR ファイルからロードするクラスです。 そして getResource メソッドを使用すれば、クラスファイルを取得するのと同じように JAR ファイルの中の画像を取得できます。

Swing の場合

ClassLoader classLoader = this.getClass().getClassLoader();
URL resUrl = loader.getResource("xxx.gif");
ImageIcon image = new ImageIcon(resUrl);

SWT の場合

Image image;
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream iStream = classLoader.getResourceAsStream("xxx.gif");
if(iStream != null){
image = new Image(Display.getDefault(), iStream);
}

JAR ファイルを実行時に main メソッドが見つからない

原因その1:
JAR ファイルを実行した場合、どのクラスファイルに main メソッドがあるかを マニフェストファイルに指定する必要があります。
Main-Class: パッケージ名.クラス名
という行を追加してください。

原因その2:
非常に情けないのですが、この原因で小一時間悩みました。
マニフェストファイルに Main-Class を追加したにも関わらず実行できず、 よくよく考えてみたところ、パッケージ名の命名規則によると 大文字は使用してはいけませんでした。 名称をすべて小文字にしたところまったく問題なく動作しました。

2004年12月19日

JAVA での環境変数取得 & アプリケーション設定

JAVA においては環境変数の取得を System クラスの getProperty(ies) メソッドで取得できます。 また、アプリケーション独自の設定も、任意の *.properties ファイルを開き Properties クラスを利用することで、ファイル内の書式を意識せず ファイルに保存することが可能です。

詳細は

2004年12月23日

MacOS X で起動する JAVA アプリケーション

もちろん JAVA で作成したプログラムは基本的にマルチプラットフォームですが 普通はコマンドラインで手動で起動しないといけません。 MacOS X の場合、必要なファイルを特定のディレクトリ構成に配置すれば ダブルクリックで実行できるようになるようです。
いまのところ自分の方ではうまくいっていませんが。

情報ソース:

2005年01月09日

一意なパッケージ名の取得

JAVA のプログラムを作成する際、 クラスが増えて来るとパッケージ化を行うかと思います。 個人的な開発をする限りにおいては任意のパッケージ名を使ってもとくに支障ありませんが 外部に公開したり、再利用したりするためにはパッケージ名が他のパッケージと競合しない =一意である必要があります。 多くの場合、パッケージ名は開発した団体のインターネットドメインを使用するのが通例となっており 言語仕様上も推奨されているようですが、 まだ個人レベルの開発者では独自のドメインを持たない場合も多いと思います。

このような開発者のために、日本では IAjapan(財団法人インターネット協会)の JAVA研究部会がパッケージ名の登録サービスを行っています。 このサービスに登録すれば、 JAVA研究部会のドメイン java-conf.gr.jp を用いて jp.gr.java-conf.xxx という一意なパッケージ名を使用できるようになります。

詳しくは
IAjapan JAVA 研究部会

2005年02月12日

空文字列で TextNode を生成する

ドキュメントツリーにあらたなノードを追加する場合 Document インターフェイスの createXXX メソッドを使用しますが createTextNode で空文字のテキストノードを作成する場合、 createTextNode(""); とすると実際にはこのノードは作成されないようです。 (生成されたテキストノードを追加した要素が、子のノードを持たない要素となる)。

例:
Element element = docUnitList.createElement("TextTag");
element.appendChild(document.createTextNode(""));
結果:
<TextTag />

空文字のノードを追加する場合、引き渡す文字列として "" ではなく 明示的にあらたな String インスタンスを渡すと、開始タグと終了タグの両方が出力されます。

例:
Element element = docUnitList.createElement("TextTag");
element.appendChild(document.createTextNode(new String()));
結果:
<TextTag></TextTag>

もっとも、この表記のタグも再度 JAXP の XML パーサなどで読み込むと テキスト要素を持たない要素と解釈されるようなので テキスト要素がない可能性も考慮してコーディングを行う必要があります。

2006年06月01日

cygwin で java -jar コマンドを使用する際の注意点

cygwin では、cygwin のルートフォルダが C:\cygwin の場合、 たとえば C:\cygwin\usr\local は cygwin 上では /usr/local のようにあらわせます。 (ちょうど cygwin のルートフォルダが cygwin 上でのルートディレクトリになります)。

この事が頭にあると、java コマンドで jar ファイルを実行する際、 つい
% java -jar /usr/local/java/xxx.jar
のように実行してしまいますが、 そうすると
Unable to access jarfile
jar ファイルが見つからないとエラーが発生してしまいます。

実はここで実行されている java コマンドは、 cygwin の 内部コマンドではなく、あくまで Windows 用の java.exe に過ぎないので jarファイル名は Windows のパス形式「C:\cygwin\usr\local\java\xxx.jar」のように 指定しないといけません。

分れば何ということはないのですが、 気づくまで小一時間かかりました。。。

2006年08月24日

Throwable#printStackTrace() の結果を文字列として取り出す(1/2)

デバックを行う場合など、例外が何処で発生したかを追跡するため printStackTrace() メソッドを使用しますが、 通常このメソッドは標準エラー出力にしか出力されません。 ログファイルに残したり、(コンソールではなく)ウェブ画面やGUI上に表示したい場合など 文字列に出力できるとよいのですが、標準では用意されていません。

方法の一つとして、Throwable#printStackTrace(PrintStream) や Throwable#printStackTrace(PrintWriter) を使用する方法があります。 引数に指定したストリームに結果を出力させることができるため、 Pipe ストリームを利用して結果をストリームから取り出すことができます。

例)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.PrintWriter;
import java.io.Reader;

public class StackTracePrintTest {
    ...
    private String getStackTraceString(Throwable e) throws IOException {
        // Pipe ストリームで出力ストリームと入力ストリームを接続する。
        PipedWriter pipeOut = new PipedWriter();
        PipedReader pipeIn = new PipedReader(pipeOut);
        PrintWriter out = new PrintWriter(pipeOut);

        // Throwable の printStackTrace メソッドで出力ストリームに書き出す。
        e.printStackTrace(out);
        out.flush();
        out.close();

        // 入力ストリームから結果を取得する。
        BufferedReader is = new BufferedReader(pipeIn);
        StringBuffer buf = new StringBuffer();
        String line;
        while ((line = is.readLine()) != null) {
            buf.append(line);
        }

        return buf.toString();
    }
}

上記の例の getStackTraceString メソッドで、 Throwable からスタックトレース情報を取得することが出来ます。

ただし、実際にこの処理をアプリケーション内で使おうとしたとき (おそらくマルチスレッドの状態で使うと) e.printStackTrace() の箇所以降に進まなくなってしまいました。 マルチスレッドの際のストリームの動作を調べれば解決するのでしょうが。。。

Throwable#printStackTrace() の結果を文字列として取り出す(2/2)

printStackTrace(PrintWriter) ではうまくいかない場合があるため、 実際には Throwable#getStackTrace() を用いる方が簡便かもしれません。 (JRE 1.4 以降)

このメソッドはスタックトレースの内容を StackTraceElement 配列として取得できます。 配列の一つ一つの内容を文字列に直せば、 printStackTrace() と同様の結果を得ることができます。 (ただしタブや改行などの整形は行う必要があります)

例)

public class StackTracePrintTest {
    ...
    private String getStackTraceString(Throwable ex) throws IOException {
        StringBuffer buf = new StringBuffer();
        buf.append(ex.toString());
        buf.append("\n");

        // スタックトレースの内容を取得
        StackTraceElement[] sts = ex.getStackTrace();
        for (int i = 0; i < sts.length; i++) {
            buf.append("\tat ");
            buf.append(sts[i].toString());
            buf.append("\n");
        }

        // Cause Throwable が存在する場合
        Throwable cause = ex.getCause();
        if (cause != null) {
            buf.append("Caused by: ");
            buf.append(this.getStackTraceString(cause));
        }

        return buf.toString();
    }
}

上記のようにすれば、スタックトレースの内容を文字列に出力することができます。 ただし自前でこの処理を作るよりは、 やはり printStackTrace() の内容をそのまま String で返すようなメソッドが用意されていてもよいように思いますが。。。

2007年02月21日

Throwable#printStackTrace() の結果を文字列として取り出す(追記)

以前書いた

Throwable#printStackTrace() の結果を文字列として取り出す
について、PipedReader/Writer を用いて実現しようとしていましたが もっと簡便な方法がありました。。。

Throwable#printStackTrace(PrintWriter) の引数に渡す PrintWriter に StringWriter を使えばよいようです。 StringWriter なんて便利なクラスがあったんですね。。。
ちなみにマルチスレッドでの挙動は確認していません。

About tips: JAVA

ブログ「240K DEV」のカテゴリ「tips: JAVA」に投稿されたすべてのエントリーのアーカイブのページです。過去のものから新しいものへ順番に並んでいます。

次のカテゴリはtips: eclipseです。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。