メインコンテンツまでスキップ

「Java」タグの記事が35件件あります

全てのタグを見る

Java, Servlet: No suitable driver found for "~" の原因と解決法

· 約1分
Yu Sasaki
Enterprise Security Manager / Advisor

事象 - NullPointerException on java.sql.Connection

JDBCを用いてServletからMySQLのテーブルへアクセスする過程で、DriverManager.getConnectionメソッドの呼び出しの後、NullPointerExceptionが送出された(アプリケーション・サーバーはTomcat)。

<前略>
Connection conn = null;
try {
conn = DriverManager.getConnection(URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("<sql文>");
<後略>

tomcat_error_nullpointer

原因 - No suitable driver found for "~"

デバックトレースを行ったところ、No suitable driver found for "~"というメッセージが出力されていた。JDBC Driver のクラスパスを設定していなかった為、今回のエラーが発生した。

対策 - JDBC Driverのクラスパス設定

JDBC Driver ファイル(.jar)をクラスパスに追加する。Eclipse上での設定方法は「実行」→「実行の構成」から「クラスパス」タブ内の「ユーザー・エントリー」を選択、「外部JARの追加」ボタンから、Driverを設定する。

雑感

ありがちー、なミスをしてしまったー。

SJC-Pに受かった

· 約1分
Yu Sasaki
Enterprise Security Manager / Advisor

春先にSunがOracleに買収されて私的に気になるMySQLの形振りどうなるのかな、とか今後のOracleのロードマップ次第ではPostgreSQLのOSSとしての立場が再度見直されそう、とかSJC-P(Sun Certified Programmer for the Java Platform, Standard Edition 5.0)の名前や内容が変わるか否かが少し気になってましたが、そういった今後のことは今夏に発表らしいので(手続きや株主の訴訟が解決後)、気兼ねなくできた。 この試験はスコアが分野別にも集計してくれるので受験者の知識・技能を細かく評価するのに役立ちます。私はAPIコンテンツや並行性のセクションが100%に対してコレクション/ジェネリックスのセクションが相対的に低いという少し意外な結果が出たので、今日は自分のレベルが客観的に分かって収穫だった。

Java: OR論理演算子の評価条件

· 約2分
Yu Sasaki
Enterprise Security Manager / Advisor

以前、OR演算の2つのオペランドが両方評価されるか否かがあやふやだったので以下のコードを以て改めて確認してみます。

public class Sample1 {
public static void main(String[] args) {
int i = 5, j = 10, k =15;
if ((i++ < j) | (k-- > j))
System.out.println("values of i: " + i + " values of k: " + k);
if ((i < j) || (--k > j))
System.out.println("values of k: " + k);
}
}

実行結果は

values of i: 6 values of k: 14
values of k: 14

となります。 1つめのif文で使われている演算子はビット論理OR演算子で左右の両オペランドを評価します。よって式i++とk--が評価されているため結果はvalues of i: 6 values of k: 14となります。 2つめのif文で使われているのは短絡論理OR演算子で、評価順序は||の_左側のオペランドを先ず評価し_、それがtrueなら_右側は評価せず_(ORは片方が真ならもう片方の結果にかかわらず真ですから)、_falseなら評価_します。よって、if ((i < j) || (--k > j))ではi < jがtrueとなるため--k > jは評価されずkはデクリメントされません。よってkの値は変わらず、上記のような実行結果となります。

Java: イベント駆動によるModelとViewの分離 - Observer パターン

· 約4分
Yu Sasaki
Enterprise Security Manager / Advisor

よくGUIやWebアプリの簡単なサンプルソースなどは、UIとアプリケーションのロジックが同じクラスまたはメソッドに書かれている場合が多い。それはそのサンプルがある特定の機能や関数の紹介の為に簡潔に書いているのだが、仮にいざそのソースを元にアプリを作りこんで機能の追加を行っていくとUIとアプリのロジックは分離したほうが保守・拡張と共に行い易い。 下記のプログラムは1秒毎に数値をカウントし、それを2進数と10進数でGUI上のラベルに出力する機能をモデルとビューに分けている。すなわち、数値のカウントをするモデルと数値をUIに表示するビューに。(いくつかの言語ではGUIの部品としてタイマーがあるようだが。。)

Java, デザインパターン: Simple Factory - インスタンスの生成方法を任せる

· 約3分
Yu Sasaki
Enterprise Security Manager / Advisor

以前デザインパターンの理解の確認がてら簡単なコードを書いた。リファクタリングの前後を省いているので初見ではパターンのメリットと適応基準が見えにくく、またサンプルのテーマ設定が良くなかったので少々説明し難い。今回のようなToyコードみたいなのはたまに書く。

クラス図

simple_factory_classes 文字列の分割プログラム。 入力: クラス名+<区切り文字>+メソッド名の文字列 出力: その文字列の分割結果が格納されたインスタンス(Namerクラス)。 文字列の形式が"<クラス名>#<メソッド名>"か"<クラス名>.<メソッド名>"によって、すなわち区切り文字によって分割処理のメソッドの内容が変わるので、その違いを派生クラスでオーバーライドして定義したメソッドで吸収しようというもの。 これによる利点はMain側が分割対象の文字列の形式を意識しなくてよいこと。単にNameFactory#getNamer()に渡すだけ。文字列の形式が2つの内のどちらで、どのクラスに処理を任せるかの処理はgetNamer()が行う。これによって、仮に文字列の形式を増やす場合に修正するのはgetNamer()のifブロック、追加するのは新しい派生クラス。

Java, JSP: 現在時刻が指定期間内か判定する - GregorianCalendar#before、after

· 約3分
Yu Sasaki
Enterprise Security Manager / Advisor

日時を扱うクラスはDateとGregorianCalendarがありますが、Sunは後者を推奨しているようです。実際GregorianCalendarのほうが扱いやすいです。下のサンプルは、現在時刻が指定した期間内か否かを判定するものです。

ソースコード

<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page import="java.util.*" %> <%! final int MONTH_OFFSET = 1; String showTime(Calendar cal) { String str; str = cal.get(Calendar.YEAR) + "/" + (cal.get(Calendar.MONTH) + MONTH_OFFSET) + "/" + cal.get(Calendar.DATE) + " " + cal.get(Calendar.HOUR) + ":" + cal.get(Calendar.MINUTE); return str; } boolean isPeriod(Calendar start, Calendar end) { Calendar cur = Calendar.getInstance(); return cur.after(start) && cur.before(end); } %> JSP Date Comparison

# JSP Date Comparison

<% // (year, month, date, hour, minute) monthの範囲は0-11で1月は0 Calendar startTime = new GregorianCalendar(2009, 2 - MONTH_OFFSET, 23, 21, 0); Calendar endTime = new GregorianCalendar(2009, 2 - MONTH_OFFSET, 23, 21, 10); out.println("開始時刻: " + showTime(startTime) + "
"); out.println("終了時刻: " + showTime(endTime) + "
"); if (isPeriod(startTime, endTime)) { out.println("現時刻は指定期間「内」"); } else { out.println("現時刻は指定期間「外」"); } %>

日時の比較はGregorianCalendar#after、beforeメソッド以外にint compareTo(Calendar cal)等もあります。 実際に使う際、期間を指定するGregorianCalendarのコンストラクタの引数データは他の入力から受け取るようにします。

実行結果例

本日の21:05に計ると…

JSP Date Comparison
開始時刻: 2009/2/23 9:0
終了時刻: 2009/2/23 9:10
現時刻は指定期間「内」

追記: SimpleDateFormatによる出力の整形

d_kamiさんに改良していただきました。ありがとうございます(^-^)

String showTime(Calendar cal) { Date date = cal.getTime(); SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm"); return format.format(date); } と書けばすっきりするよ、import java.text.SimpleDateFormatを忘れずに - SimpleDateFormat - マイペースなプログラミング日記

showTimeを修正して計りなおした実行結果は、

開始時刻: 2009/02/23 21:00
終了時刻: 2009/02/24 21:10
現時刻は指定期間「内」

確かに出力はyyyy/MM/dd HH:mmの形式になっていて見栄えも良いです。

参考サイト

Java, Swing: JComponentのGraphicsオブジェクトを用いて直線を描画

· 約2分
Yu Sasaki
Enterprise Security Manager / Advisor

JComponentはほとんど全てのSwing コンポーネントの基底クラスで、Graphicsオブジェクトも持っています。下記のソースは、そのGraphicsを用いて画面に直線を描画するものです。

ソースコード

package linecomp;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class LineComp extends JComponent {
public static void main(String[] args) {
Runnable myGUI = new Runnable() {
@Override
public void run() {
JFrame win = new JFrame("Line Component");
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insets ins = win.getInsets();
win.setSize(300 + ins.left + ins.right, 300 + ins.top + ins.bottom);
win.add(new LineComp());
win.setVisible(true);
}
};
SwingUtilities.invokeLater(myGUI); // 保留中のすべての AWT イベントが処理されたあとに発生
}
@Override
public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawLine(0, 0, getWidth(), getHeight());
}
}

GUI部品の(再)描画レンダリングが発生した際、オーバーライドしたpaintComponent()内の手続きをEventQueueに登録しEDT(Event Dispatch Thread)が処理をします。標準のGUI部品をカスタマイズしたい場合などに使えます。その場合は予めsuper.paintComponent(g);でデフォルトのレンダリングを基底クラスに任せ、その後にカスタムの描画処理を書きます。

実行結果

JComponent に線を描画

追記: d_kami さんに改良して頂きました

InsetとJFrame#setSizeを使わずにJComponent#setPreferredSizeとJFrame#packを使うようにした - 他のやり方 - マイペースなプログラミング日記

comp.setPreferredSize(new Dimension(300, 300));
win.add(comp);
win.pack();

確かにsetPreferredSizeでコンポーネントのサイズを直接指定したほうが今プログラムの文脈に沿っています。私のほうはコンポーネントでなくJFrameのサイズの指定ですから。また、オーバーライドしたpaintComponent()でgetWidth()やgetHeight()を二度使うのであれば、一度ローカル変数に格納することでオーバヘッドを下げるのも大切ですね。日頃からの習慣にしないと。 とても勉強になりました。ありがとうございます。

参考サイト

NetBeans から Subversion でコミットをする際のエラーの解決法の一例

· 約1分
Yu Sasaki
Enterprise Security Manager / Advisor

Windows版NetBeans6.5でソースをインポートまたはコミットする際に以下のようなエラーが発生する場合がある。

'.' is not a working copy Can't open file '.svn/entries': No such file or directory

これはNetBeansが使用するsvnクライアントがcygwinのものだった場合に生じるエラーのようだ。 未だcygwin環境のsvn以外のsvnをインストールしていない場合は下のアドレスからダウンロードする。 subversion: Subversion Packages その後、メニューバーの「ツール」→「オプション」から設定画面を開いて、「その他」タブ→「バージョン管理」画面のSubversion画面を開く。左にあるリストメニューからSubversionを選択し、最初の設定項目である_「SVN実行可能ファイルパス」_を設定すれば正常にインポート、コミットできるようになる。 ちなみに、cygwinのでなければ↑のsvnパッケージでなくともOK。

参考サイト

  • Nabble - Netbeans IDE Users - Problems with SVN, svn/entities file doesn't exists

人工無脳を作ってみる (1)入力文の末尾に文字列を追加

· 約2分
Yu Sasaki
Enterprise Security Manager / Advisor

さて、最初は単純にユーザの入力文の末尾に予め定義されている文字列を付け足して応答するだけのものです。

ソースコード

package info.yukun.chatterbot;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class SimpleChatterBot {
private String botName = "chatterbot";
private String callStr = "なにかしゃべってよ(>_<)";
private String[] suffixResponses = {
"ってアレですね、わかります(^^)b",
"ですか?わかりません(>_<)",
"って何?日本語でおk('`)b"};
public void go() {
try {
BufferedReader stdReader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("INPUT : ");
String response;
String input;
while ((input = stdReader.readLine()) != null) { // ユーザの入力待ち
if (input.equals("")) { // 入力が無かった
response = callStr;
} else {
response = decorateInput(input) + getSuffixResponse();
}
System.out.print(botName + ": " + response);
System.out.print("\nINPUT : ");
}
stdReader.close();
System.out.println("\nPROGRAM END");
} catch (Exception e) {
e.getStackTrace();
System.exit(-1); // プログラムを終了
}
}
private String getSuffixResponse() {
int rand = (int) (Math.random() * suffixResponses.length);
return suffixResponses[rand];
}
private String decorateInput(String input) {
return "「" + input + "」";
}
public static void main(String[] args) {
SimpleChatterBot bot = new SimpleChatterBot();
bot.go();
}
}

getSuffixResponse()メソッド内で使われているMath.random()は、

static double random() 0.0 以上で、1.0 より小さい正の符号の付いた double 値を返します。

ですので、「Math.random() * 配列の長さ」 は「0~配列の長さ-1」 を意味します。

実行結果の例

INPUT : こんにちは
chatterbot: 「こんにちは」って何?日本語でおk('`)b
INPUT : え、
chatterbot: 「え、」ですか?わかりません(>_<)
INPUT : いえ、聞き返しただけです。
chatterbot: 「いえ、聞き返しただけです。」って何?日本語でおk('`)b
INPUT :
chatterbot: なにかしゃべってよ(>_<)
INPUT : 最近どうですか?
chatterbot: 「最近どうですか?」ってアレですね、わかります(^^)b
INPUT :
PROGRAM END

なんだかー、それはかとなくばかにしていますねf^^; 最初はJavaで書いていきますが、実装する機能の種類やリリースする環境によっては恐らく途中でOOをサポートする他の言語に変更するかも。

Java: ユーザからの(標準)入力を取得 - System.inとInputStreamReaderクラス

· 約2分
Yu Sasaki
Enterprise Security Manager / Advisor

コマンドプロンプトからキーボード(標準)入力を取得するプログラムです。 肝心の標準入力を取得する手続きはSystem.inフィールドですが、これはバイトストリームでの読み込みを行うメソッドしか持たないので、InputStreamReaderクラスでラップすることでバイトストリームを文字列に変換出来るメソッドに任せます(read()メソッド)。 しかし、InputStreamReader#read()メソッドは一文字毎にしか読み込めず非効率な面があるので、最後にBufferedReaderクラスでラップすることで入力文字をバッファに格納し一行まとめて読み込めるようにします。(readLine()メソッド)。 このように、高水準のコンポーネントにSystem.inのような低水準のコンポーネントを渡して、その中で低水準メソッドを制御する手法はTemplate Methodパターンに通じるものがあるかも。The Open-Closed Principleですね。

ソースコード

import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ReadLineSample {
public static void main(String[] args) {
try {
BufferedReader stdReader =
new BufferedReader(new InputStreamReader(System.in));
System.out.print("INPUT : ");
String line;
while ((line = stdReader.readLine()) != null) { // ユーザの一行入力を待つ
if (line.equals("")) line = "<空文字>";
System.out.print("OUTPUT: " + line);
System.out.print("\nINPUT : ");
}
stdReader.close();
System.out.println("\nPROGRAM END");
} catch (Exception e) {
e.getStackTrace();
System.exit(-1); // プログラムを終了
}
}
}

実行結果

文字列を入力した後Enterキーを押すと入力した文字がOUTPUTされます。

INPUT : Hello World!
OUTPUT: Hello World!
INPUT : こんにちは。
OUTPUT: こんにちは。
INPUT :
OUTPUT: <空文字>
INPUT :
PROGRAM END

プログラムを終了する際は、プロンプト上でCtrl+CかCtrl+Zを押してください。それでreadLine()の戻り値はnullとなりwhileループを抜けます。ここでの注意は、単に文字を何も入力せずEnterキーだけ打つと空文字を返すことです(≠null)。 対して、C言語でこういった処理の場合は環境に合わせた改行文字も読み込こんでいます。たぶん、JavaではInputStreamReaderのreadのどこかの段階でその辺は上手く処理されているのかな?気が向いた時に確認してみようかな。