プログラマメモ2 - programmer no memo2

僕のリファクタリング elseをなくすようにする 2006/06/29
2008/03/23

Java言語を使用して、あるメソッドを実装したとする例えば、

void method(){
if(condition){
a();
} else {
b();
}
return;
}


僕ならまずこう変更する。

void method(){
if(condition){
a();
return;
}
b();
}


僕のリファクタリング
(1)
if文のelseをなくすようにする。
(2)
さっさとreturnさせる。
(3)
elseの中でif文をネストさせないようにする。


勝手にアフェリエイト(アマゾンの書籍にリンクしています)
リファクタリング―プログラムの体質改善テクニック

Thread.yieldまた別の使い道 2006/06/28
2006/11/26

Thread.yieldメソッドについての別の使い道についてのコメントをメールでいただきましたので、掲載します。



以前、



「ほとんどのプログラマによるThread.yieldの唯一の使い方は、テスト中にプログラムの平行性を意図的に増加させることです。」

「Effective Java」P.194



と書いたものについてへのコメントとなります。



引用は承諾済みです。



これ以外の理由として、スレッドが TSS で動作していた場合に、次のようなテクニックがあります。



synchronized ブロック内にいるときに TSS の時間切れで他のスレッドに CPU が渡されたとします。



CPU を渡されたスレッドがこの synchronized ブロックを待っていた場合、ブロックされているためせっかく割り当てられた CPU 時間をすべて synchronized ブロック待ちに使うことになります。



この余計な待ちを少なくするために、synchronized ブロックの直前で Thread.yield を呼びます。

次にこのスレッドが処理されるときには、一回で synchronized ブロックを抜けられる可能性が大きくなり、誰かが synchronized ブロック内にいるために起きる余計な synchronized ブロック待ちを避けられます。





重たい排他処理に入る前に Thread.yield を一回実行しておくことで、割り当てられる CPU 時間のスタートを仕切りなおして、できるだけ短いターン(できたら 1 ターンで)で排他処理を通り過ぎよう、というのがその意図というわけです。



2006-06-28 H氏のメールより



ちなみに、TSSはTime Sharing Systemのことですね。

TSSのwikipedia(日本語版)での説明

Javaとクロージャ 2006/06/26
2006/11/26

2006/07の雑誌「JavaWORLD」のJavaコーディング道場(text:中村光志)でクロージャについての記事があった。
恥ずかしながら「クロージャ」についてよくわかっていない。
というわけでクロージャについて調べてみた。

上記の雑誌には

クロージャとは、メソッドを定義した文脈と関連づけられたメソッドのことです。
※言語によっては、「ブロック」や「ラムダ式」と呼ばれることもある。

2006/07の雑誌「JavaWORLD」のJavaコーディング道場(text:中村光志)


とあった。

Smalltalkではブロックとよばれるもののようです。



finalizeの実装(オーバライド) 2006/06/26
2006/11/26

個人的には、Object#finalize()は実装せずに、後始末が必要な処理は早い段階で明示的に後始末メソッドを作って行うようにしたほうがよいと思う。



この根拠は、

(1)

finalizeの呼び出しは、JVMに依存している。

(2)

finalizeの処理が時間かかる場合にアプリケーション全体の動作にたいする影響にたいしての危惧

(3)

super.finalize()の呼び出しにたいする注意が必要になる



finalizeの呼び出しに過渡なきたいをしたくないというのが本音。

プログラマができる後始末はちゃちゃとすませたほうが吉なのではないだろうか。

たしか、Syste.gc()の呼び出しはすすめられていなかったと思う。

※もとネタを探し中



といいつつも

ではどういったときにプログラマはfinalizeを実装したほうがよいのだろうか。

JNI(Java Native Interface)を利用したりして実メモリ操作に近い処理をしているような場合だろうか。



Javaのソースコードを簡単に調べてみた。

なんとなくパターンがある感じ。



(A)

java.awt.Font

で実装しているコードがあった。

これはあきらかにネイティブなものにたいする後始末パターン。

下記のような感じ。



/** ネイティブコール */

private native void pDispose();

/** overrideされている */

protected void finalize() throws Throwable {

if (this.peer != null) {

pDispose();

}

super.finalize();

}





(B)

java.awt.Window

これは、登録していたものから自分を削除するパターン(かな?)

で下記のような感じ。



protected void finalize() throws Throwable {

if (parent != null) {

((Window)parent).removeOwnedWindow(weakThis);

}

super.finalize();

}





(C)

javax.imageio.stream.ImageInputStreamImpl

これは、おそらくクローズしわすれ防止パターン。

下記のような感じのコード。



protected void finalize() throws Throwable {

if (!isClosed) {

try {

close();

} catch (IOException e) {}

}

super.finalize();

}





気がついたことがあるsuper.finalize()の呼び方が下のほうにある。



いまいちよくわかってないので、引き続き考えていきたい。

SwingUtilitiesのinvokeLater、invokeAndWaitはいつつかうべき? 2006/06/26
2006/11/26

Swingを使ったプログラミングででてくる

SwingUtilities.invokeLater(...)

をどのようなときに使えばよいのだろうか。



実はよくわかっていない。



こういったコードをみかける。



SwingUtilities.invokeAndWait(new Runnable() {

public void run() {

button.setEnabled(false);

}

});





Javadocには下記のように説明されています。





保留中のすべての AWT イベントが処理されたあとに発生します。

Javadoc 日本語版





invokeLaterを試してみるサンプルをつくる試み。

未完です。



import javax.swing.SwingUtilities;

import java.awt.BorderLayout;

import javax.swing.JPanel;

import javax.swing.JFrame;

import javax.swing.JMenuBar;

import javax.swing.JMenu;

import javax.swing.JMenuItem;

import java.awt.GridBagLayout;

import javax.swing.JButton;

import java.awt.GridBagConstraints;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;



public class TestFrame extends JFrame {



private static final long serialVersionUID = 1L;



private JPanel jContentPane = null;

private JMenuBar jJMenuBar = null;

private JMenu jMenu = null;

private JMenuItem jMenuItem = null;

private JMenu jMenu1 = null;

private JPanel jPanel = null;

private JButton jButton = null;

private JButton jButton1 = null;

private JButton jButton2 = null;



private JMenuItem jMenuItem1 = null;



private JMenuItem jMenuItem2 = null;



private TestFrame.ExecuteActionCommand executeActionCommand = null; // @jve:decl-index=0:visual-constraint="463,138"



private JMenuBar getJJMenuBar() {

if (jJMenuBar == null) {

jJMenuBar = new JMenuBar();

jJMenuBar.add(getJMenu());

}

return jJMenuBar;

}



private JMenu getJMenu() {

if (jMenu == null) {

jMenu = new JMenu();

jMenu.setText("menu");

jMenu.add(getJMenu1());

}

return jMenu;

}



private JMenuItem getJMenuItem() {

if (jMenuItem == null) {

jMenuItem = new JMenuItem();

jMenuItem.setText("take long time..");

jMenuItem.setActionCommand("act1");

jMenuItem.addActionListener(getExecuteActionCommand());

}

return jMenuItem;

}



/**

* This method initializes jMenu1

*

* @return javax.swing.JMenu

*/

private JMenu getJMenu1() {

if (jMenu1 == null) {

jMenu1 = new JMenu();

jMenu1.setText("menu");

jMenu1.add(getJMenuItem());

jMenu1.add(getJMenuItem1());

jMenu1.add(getJMenuItem2());

}

return jMenu1;

}



private JPanel getJPanel() {

if (jPanel == null) {

GridBagConstraints gridBagConstraints2 = new GridBagConstraints();

gridBagConstraints2.gridx = 0;

gridBagConstraints2.gridy = 2;

GridBagConstraints gridBagConstraints1 = new GridBagConstraints();

gridBagConstraints1.gridx = 0;

gridBagConstraints1.gridy = 1;

GridBagConstraints gridBagConstraints = new GridBagConstraints();

gridBagConstraints.gridx = 0;

gridBagConstraints.gridy = 0;

jPanel = new JPanel();

jPanel.setLayout(new GridBagLayout());

jPanel.add(getJButton(), gridBagConstraints);

jPanel.add(getJButton1(), gridBagConstraints1);

jPanel.add(getJButton2(), gridBagConstraints2);

}

return jPanel;

}



private JButton getJButton() {

if (jButton == null) {

jButton = new JButton();

jButton.setActionCommand("act1");

jButton.setText("take long time..");

jButton.addActionListener(getExecuteActionCommand());



}

return jButton;

}



private JButton getJButton1() {

if (jButton1 == null) {

jButton1 = new JButton();

jButton1.setText("act2");

jButton1.setActionCommand("act2");

jButton1.addActionListener(getExecuteActionCommand());

}

return jButton1;

}



private JButton getJButton2() {

if (jButton2 == null) {

jButton2 = new JButton();

jButton2.setText("act3");

jButton2.setActionCommand("act3");

jButton2.addActionListener(getExecuteActionCommand());

}

return jButton2;

}



private JMenuItem getJMenuItem1() {

if (jMenuItem1 == null) {

jMenuItem1 = new JMenuItem();

jMenuItem1.setText("act2");

jMenuItem1.setActionCommand("act2");

jMenuItem1.addActionListener(getExecuteActionCommand());

}

return jMenuItem1;

}



private JMenuItem getJMenuItem2() {

if (jMenuItem2 == null) {

jMenuItem2 = new JMenuItem();

jMenuItem2.setText("act2");

jMenuItem2.setActionCommand("act2");

jMenuItem2.addActionListener(getExecuteActionCommand());

}

return jMenuItem2;

}



private TestFrame.ExecuteActionCommand getExecuteActionCommand() {

if (executeActionCommand == null) {

executeActionCommand = new TestFrame.ExecuteActionCommand();

}

return executeActionCommand;

}



public static void main(String[] args) {



SwingUtilities.invokeLater(new Runnable() {

public void run() {

TestFrame thisClass = new TestFrame();

thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

thisClass.setVisible(true);

}

});

}



public TestFrame() {

super();

initialize();

}



private void initialize() {

this.setSize(300, 200);

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.setJMenuBar(getJJMenuBar());

this.setContentPane(getJContentPane());

this.setTitle("JFrame");

}



private JPanel getJContentPane() {

if (jContentPane == null) {

jContentPane = new JPanel();

jContentPane.setLayout(new BorderLayout());

jContentPane.add(getJPanel(), BorderLayout.CENTER);

}

return jContentPane;

}



class ExecuteActionCommand implements ActionListener {



public void actionPerformed(ActionEvent e) {

String actionCommand = e.getActionCommand();

action(actionCommand);

}



public void action(String actionCommand) {

if (eq(actionCommand, "act1")) {

try {

System.out.println("take long time action...");

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

System.out.println("wake up!!");

}

return;

}



if (eq(actionCommand, "act2")) {



System.out.println(Thread.currentThread());



SwingUtilities.invokeLater(new Runnable() {



public void run() {

jButton.setEnabled(false);

System.out.println("@_@!!" + Thread.currentThread());

}



});



SwingUtilities.invokeLater(new Runnable() {



public void run() {

try {

jButton2.setEnabled(false);

System.out.println("take long time action...");

System.out.println(Thread.currentThread());

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

System.out.println("wake up!!");



}

}



});



System.out.println("==== THIS LINE");

return;

}

if (eq(actionCommand, "act3")) {

System.out.println("act3...");

Runnable runnable = new Runnable() {



public void run() {

try {

System.out.println("Hoooo "

+ Thread.currentThread().getName());

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

System.out.println("wake up["

+ Thread.currentThread().getName() + "]");

}

}



};

Thread thread = new Thread(runnable);

thread.start();

return;

}

}

}



protected static boolean eq(Object object, Object object2) {

return object == null ? object2 == null : object.equals(object2);

}

}





プログラマメモ: ロックのサンプルをつくってみた 2006/06/23
2006/11/26

プログラマメモ: ロックのサンプルをつくってみた



以前書いた記事への補完です。

適当にアップしてます。

#どこかの機会できちんとまとめたいです。



より厳密にスレッドの実験を行う場合は、

Thread.yield();

を使うといいようです。





「ほとんどのプログラマによるThread.yieldの唯一の使い方は、テスト中にプログラムの平行性を意図的に増加させることです。」

「Effective Java」P.194





とありました。





会社でJavaに詳しい人に教えていただきました。



より厳密に動作するようにしてみました。

絶対要件

処理のa b cと決まった順序で実行されることを保証することです。





public class TestThread_synchronized_block {



Lock lock;



public static void main(String[] args) {



final TestThread_synchronized_block testLock = new TestThread_synchronized_block();



new Thread(createRunnable(testLock)).start();

new Thread(createRunnable(testLock)).start();

new Thread(createRunnable(testLock)).start();



}



public static Runnable createRunnable(final TestThread_synchronized_block th) {

return new Runnable() {

public void run() {

try {

while (true) {

th.go();

Thread.sleep(10);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

};



}



public TestThread_synchronized_block() {

this.lock = new Lock();

}



int checkCont = 0;



public void go() throws InterruptedException {

if (!lock.lock()) {

return;

}

try {

Thread.yield(); // (1) ここで他スレッドに処理が移る

a();

Thread.yield(); // (2) ここで他スレッドに処理が移る

b();

Thread.yield(); // (3) ここで他スレッドに処理が移る

c();

Thread.yield(); // (4) ここで他スレッドに処理が移る

if (checkCont == 3) {

System.out.println("not broken!!");

} else {

System.out.println("BROKEN!!");

System.exit(0);

}

} finally {

checkCont = 0;

lock.release();

}



}



public void a() throws InterruptedException {

System.out.println(" process a " + Thread.currentThread());

checkCont++;

}



public void b() throws InterruptedException {

System.out.println(" process b " + Thread.currentThread());

checkCont++;

}



public void c() throws InterruptedException {

System.out.println(" process c " + Thread.currentThread());

checkCont++;

}



class Lock {



private boolean locked = false;



public boolean lock() {

/*

* using synchronized block

*/

synchronized (this) {

if (locked) {

return false;

}

locked = true;



return true;

}



}



public void release() {

/*

* using synchronized block

*/

synchronized (this) {

this.locked = false;

}

}



}



}







厳密に動く別バージョンです。





public class TestThread_another_version {

private volatile Lock lock = new Lock();



public static void main(String[] args) {

final TestThread_another_version testLock = new TestThread_another_version();

new Thread(createRunnable(testLock)).start();

new Thread(createRunnable(testLock)).start();

new Thread(createRunnable(testLock)).start();

}



public static Runnable createRunnable(final TestThread_another_version th) {

return new Runnable() {

public void run() {

try {

while (true) {

th.go();

Thread.sleep(3);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

};



}



public TestThread_another_version() {

}

int checkCont = 0;

public void go() throws InterruptedException {

if (lock.tryLock()) {

try {

Thread.yield();

a();

Thread.yield();

b();

Thread.yield();

c();

Thread.yield();

if (checkCont == 3) {

System.out.println("not broken!!");

} else {

System.out.println("BROKEN!!");

System.exit(0);

}

}

finally {

checkCont = 0;

lock.unLock();

}

}

}



public void a() throws InterruptedException {

System.out.println (" process a " + Thread.currentThread());

checkCont++;

}



public void b() throws InterruptedException {

System.out.println(" process b " + Thread.currentThread ());

checkCont++;

}



public void c() throws InterruptedException {

System.out.println(" process c " + Thread.currentThread());

checkCont++;

}



private static final class Lock {

public synchronized boolean tryLock() {

Thread.yield();

if (locked) {

Thread.yield();

return false;

} else {

Thread.yield();

locked = true;

Thread.yield();

return true;

}

}



public void unLock() {

Thread.yield();

locked = false;

Thread.yield();

}



private volatile boolean locked;

}

}





NYSLのもといただいたコードです。





public final class TestThread_4 {

public static void main(String[] args) {

final TestThread_4 testLock = new TestThread_4();

for (int i = 0, n = 10; i < n; ++i) {

new Thread(createRunnable(testLock)).start();

}

}



public static Runnable createRunnable(final TestThread_4 testThread_4) {

return new Runnable() {

public void run() {

while (true) {

testThread_4.go();

}

}

};

}



public void go() {

Thread.yield();

if (lock.tryLock()) {

try {

Thread.yield();

a();

Thread.yield();

b();

Thread.yield();

c();

Thread.yield();

}

finally {

lock.unLock();

}

}

}



public void a() {

System.out.println(" process a " + Thread.currentThread() + ": " + this.toString());

}



public void b() {

System.out.println(" process b " + Thread.currentThread() + ": " + this.toString());

}



public void c() {

System.out.println(" process c " + Thread.currentThread() + ": " + this.toString());

}



private static final class Lock {

public synchronized boolean tryLock() {

if (locked) {

return false;

} else {

locked = true;

return true;

}

}



public synchronized void unLock() {

locked = false;

}



private volatile boolean locked;

}



private volatile Lock lock = new Lock();

}



SWING モーダルダイアログを出した後に、フレームを表示すると操作ができなくなってしまう。 2006/06/22
2006/11/26

「モーダルダイアログを出した後に、フレームを表示すると操作ができなくなってしまう。」

という現象を発現させてみます。



発現手順

  1. フレームを表示します。
  2. モーダルダイアログを表示します。
  3. 別スレッドでフレームを重ねて表示します。




モーダルダイアログをフレームでサンドウィッチする状態をつくると、中にはさまれたダイアログにたいする操作ができなくなります。



ようするにプログラムの仕組みが悪いといわれればそれまですが。。。



問題を発現するためのサンプルコードです。

実行環境によっては発現しないかもしれません。ダイアログを別フレームで覆い隠してあとから表示すれば発現すると思います。





import java.awt.Rectangle;



import javax.swing.JFrame;

import javax.swing.JOptionPane;



public class TestHideDailog {



public static boolean showYesNoDialog(String title, String message) {



int ret = JOptionPane.showConfirmDialog(null, message, title,

JOptionPane.YES_NO_OPTION);

if (ret == JOptionPane.YES_OPTION)

return true;

return false;

}



public static Runnable createDialogRunnable(final String title, final String message){

return new Runnable() {

public void run() {

showYesNoDialog(title, message);

}};

}

public static void main(String[] args) throws InterruptedException {





Runnable runnableFrame = new Runnable() {

public void run() {

JFrame frame = new JFrame();

frame.setBounds(new Rectangle(300, 300, 900, 500));

frame.setVisible(true);

}

};



new Thread(runnableFrame).start();

new Thread(createDialogRunnable("dialog1", "@_@!1")).start();

new Thread(createDialogRunnable("dialog2", "@_@!2")).start();

new Thread(createDialogRunnable("dialog3", "@_@!3")).start();

Thread.sleep(1000);//need wait!!

new Thread(runnableFrame).start();

}

}





下記に解決のためのサンプルコードを提示します。



解決策として、モーダルダイアログからフォーカスがはずれた場合にダイアログにフォーカスを戻すようにしてみます。



下記のコードは一部、JDKのJOptionPaneのコードを参考にしています。



import java.awt.Component;

import java.awt.HeadlessException;

import java.awt.Rectangle;

import java.awt.event.WindowEvent;

import java.awt.event.WindowFocusListener;



import javax.swing.Icon;

import javax.swing.JDialog;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.SwingUtilities;



public class TestHideDailog_solved {



public static boolean showYesNoDialog(String title, String message) {



int ret = showOptionDialog(null, message, title,

JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,

null, null);

if (ret == JOptionPane.YES_OPTION)

return true;

return false;

}



public static Runnable createDialogRunnable(final String title,

final String message) {

return new Runnable() {

public void run() {

showYesNoDialog(title, message);

}

};

}



public static void main(String[] args) throws InterruptedException {



Runnable runnableFrame = new Runnable() {

public void run() {

JFrame frame = new JFrame();

frame.setBounds(new Rectangle(300, 300, 900, 500));

frame.setVisible(true);

}

};



new Thread(runnableFrame).start();

new Thread(createDialogRunnable("dialog1", "@_@!1")).start();

new Thread(createDialogRunnable("dialog2", "@_@!2")).start();

new Thread(createDialogRunnable("dialog3", "@_@!3")).start();

Thread.sleep(1000);// need wait!!

new Thread(runnableFrame).start();

}



/**

* swing(JOptionPane) java source is be used as reference.

*/

public static int showOptionDialog(Component parentComponent,

Object message, String title, int optionType, int messageType,

Icon icon, Object[] options, Object initialValue)

throws HeadlessException {



JOptionPane pane = new JOptionPane(message, messageType, optionType,

icon, options, initialValue);



pane.setInitialValue(initialValue);

pane.setComponentOrientation(((parentComponent == null) ? JOptionPane

.getRootFrame() : parentComponent).getComponentOrientation());



final JDialog dialog = pane.createDialog(parentComponent, title);





WindowFocusListener focusListener = new WindowFocusListener() {



public void windowGainedFocus(WindowEvent e) {

}



/*

* フォーカスをダイアログに変更する。

*/

public void windowLostFocus(WindowEvent e) {

SwingUtilities.invokeLater(new Runnable() {

public void run() {

dialog.requestFocus();

}

});

}



};

dialog.addWindowFocusListener(focusListener);



pane.selectInitialValue();

dialog.show();

dialog.dispose();



Object selectedValue = pane.getValue();



if (selectedValue == null)

return JOptionPane.CLOSED_OPTION;

if (options == null) {

if (selectedValue instanceof Integer)

return ((Integer) selectedValue).intValue();

return JOptionPane.CLOSED_OPTION;

}

for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) {

if (options[counter].equals(selectedValue))

return counter;

}

return JOptionPane.CLOSED_OPTION;

}

}









別の解決策です。 JDK1.5(Tiger)を使用している場合、 Window#setAlwaysOnTop(true)を使用すると解決します。 参考: http://www.javainthebox.net/laboratory/J2SE1.5/GUI/WindowLocation/WindowLocation.html





JDK1.5にはWindow操作のためのいくつかの機能が追加されているようです。



import java.awt.Component;

import java.awt.HeadlessException;

import java.awt.Rectangle;



import javax.swing.Icon;

import javax.swing.JDialog;

import javax.swing.JFrame;

import javax.swing.JOptionPane;



public class TestHideDailog_solved_jdk15 {



public static boolean showYesNoDialog(String title, String message) {



int ret = showOptionDialog(null, message, title,

JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,

null, null);

if (ret == JOptionPane.YES_OPTION)

return true;

return false;

}



public static Runnable createDialogRunnable(final String title,

final String message) {

return new Runnable() {

public void run() {

showYesNoDialog(title, message);

}

};

}



public static void main(String[] args) throws InterruptedException {



Runnable runnableFrame = new Runnable() {

public void run() {

JFrame frame = new JFrame();

frame.setBounds(new Rectangle(300, 300, 900, 500));

frame.setVisible(true);

}

};



new Thread(runnableFrame).start();

new Thread(createDialogRunnable("dialog1", "@_@!1")).start();

new Thread(createDialogRunnable("dialog2", "@_@!2")).start();

new Thread(createDialogRunnable("dialog3", "@_@!3")).start();

Thread.sleep(1000);// need wait!!

new Thread(runnableFrame).start();

}



/**

* swing(JOptionPane) java source is be used as reference.

*/

public static int showOptionDialog(Component parentComponent,

Object message, String title, int optionType, int messageType,

Icon icon, Object[] options, Object initialValue)

throws HeadlessException {



JOptionPane pane = new JOptionPane(message, messageType, optionType,

icon, options, initialValue);



pane.setInitialValue(initialValue);

pane.setComponentOrientation(((parentComponent == null) ? JOptionPane

.getRootFrame() : parentComponent).getComponentOrientation());



final JDialog dialog = pane.createDialog(parentComponent, title);



pane.selectInitialValue();

dialog.setAlwaysOnTop(true);

dialog.show();

dialog.dispose();



Object selectedValue = pane.getValue();



if (selectedValue == null)

return JOptionPane.CLOSED_OPTION;

if (options == null) {

if (selectedValue instanceof Integer)

return ((Integer) selectedValue).intValue();

return JOptionPane.CLOSED_OPTION;

}

for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) {

if (options[counter].equals(selectedValue))

return counter;

}

return JOptionPane.CLOSED_OPTION;

}

}



Anonymous Inner Classes - Anonymous Inner Classes tutorial 2006/06/22
2006/11/26

下記のリンクをみていてちょっとインスパイアされた。

Anonymous Inner Classes - Anonymous Inner Classes tutorial



まさか、そういった現場はないと思うけど、あるクラスの指定されたメソッドだけしか実装してはいけないというルールをつきつけられても、その中で、クラス定義して、内部匿名クラスを使って、なんとかがんばれるかもしれない。。。





public static void print(){

class MyPrintLogic {

public String print(){

return "";

}

};

MyPrintLogic myPrintLogic = new MyPrintLogic(){

@Override

public String print() {

return "override.";

}

};



System.out.println(myPrintLogic.print());



}







さらに匿名クラスに新しくメソッドを追加して実行してみる。

使いずらい。

#注目してもらいたところだけ色を変えている。





public static void test() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{

class A {

};

A a = new A(){

public void b(){

System.out.println("i am a.");

}

};



Method f = a.getClass().getDeclaredMethod("b", null);

f.invoke(a, null);



}



initializer block 2006/06/22
2006/11/26

下記のリンクをたまたまみていて、初期化のためのinitializer blockにはっと気がついた。

Anonymous Inner Classes - Anonymous Inner Classes tutorial



別にすごく役にたつとは思えないが、なんとなくかっこいいかな。





public class TestInitializeBlock {





{

a = "a";

b = "b";

}



String a;

String b;



public String toString() {

return "a:" + a + " b:" + b;

}



public static void main(String[] args) {

System.out.println(new TestInitializeBlock());



}



}

「Thread-Per-Message」パターンを利用して、処理結果を受け取ることができるようにしたサンプル 2006/06/21
2006/11/26

おそらくそんなにまちがってないとは思う。

下記のようにしてみた。





/**

* 「Thread-Per-Message」パターンを利用して、処理結果を受け取ることができるようにしたサンプル。

*

* @author S.Nakawaka

*/

public class ThreadSample {



public static void main(String[] args) throws InterruptedException {

work();

}



public static void ok(String s) {

System.out.println("@_@!:" + s);

}



public static void work() throws InterruptedException {



/*

* executeを実装

*/

final ICommand command = new ICommand(){



ICommand.Handler handler;



public void execute() {

try {

// 時間がかかる処理をシュミレート

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

handler.setValue("done!!");

}

public void setHandler(Handler handler) {

this.handler = handler;

}

};



/*

* 結果を受信するためのクラスを定義

*/

ICommand.Handler handler = new ICommand.Handler() {

public void setValue(String s) {

ok(s);

}

};



// ハンドラをセット

command.setHandler(handler);

new Thread(new Runnable() {

public void run() {

command.execute();

}

}).start();

System.out.println("*** go");

}



/**

*

* @author S.Nakawaka

*/

interface ICommand {

public void execute();

public void setHandler(Handler handler);

interface Handler {

public void setValue(String s);

}

}

}







インターフェイス使うことにより、匿名クラスでクラスの定義を行えるようにしてみた。

ハンドラーはそれを使うクラスに結びつけることを強調するために



interface aaaa{

interface bbbb{



}

}



というふうにしてみた。

スレッド難しいねー「この仕事、やっといてね」 2006/06/20
2006/11/26

クライアントアプリケーションの応答性を高めるためには、やはりスレッドを効率的につかわないといけない。

現在、多用しているパターンがある。

一般には「Thread-Per-Message」といわれているらしい。

参考:
http://www.amazon.co.jp/gp/product/4797319127/250-1571157-9350645?v=glance&n=465392

http://www.hyuki.com/dp/cat2_ThreadPerMessage.html
だいたいこんな感じのコードになる。


protected void work() {
new Thread(new Runnable() {
public void run() {
// 《ここで勝手に仕事しといてね》
}
}).start();
}


勝手に仕事してもらうので、仕事をやめてもらうのが大変だ。

このままでは勝手に仕事をしてもらうだけなので、
仕事の結果を得る方法
途中で仕事をやめてもらう方法
を考えないといけない。

ロックのサンプルをつくってみた 2006/06/06
2006/11/26

2006-06-23 ここの記事は厳密性に欠けています。

シーケンスが保たれない可能性があります。






こんなのつくってみた。

みそは、try{}finally{}

かならずfinallyを通る。



synchronizedをとると

実行のシーケンス

get lock

a

b

c

release lock

とはならない。







package quicklunch.jeu;



public class TestLock {



Lock lock;



public static void main(String[] args) {



final TestLock testLock = new TestLock();



Runnable runnable = new Runnable() {

public void run() {

try {

while (true) {

testLock.go();

Thread.sleep(1);

}

} catch (InterruptedException e) {



e.printStackTrace();

}

}

};

Thread thread1 = new Thread(runnable);

Thread thread2 = new Thread(runnable);

Thread thread3 = new Thread(runnable);

thread1.start();

thread2.start();

thread3.start();

}



public TestLock() {

this.lock = new Lock();

}



public void go() throws InterruptedException {

if (lock.isLocked()) {

return;

}

try {

lock.setLocked(true);

a();

b();

c();

} finally {

lock.setLocked(false);

}



}



public void a() {

System.out.println("process a " + Thread.currentThread());

}



public void b() throws InterruptedException {

System.out.println("process b " + Thread.currentThread());

Thread.sleep(0);

}



public void c() throws InterruptedException {

System.out.println("process c " + Thread.currentThread());

Thread.sleep(0);

//throw new RuntimeException("Wooooo");

}



class Lock {

boolean locked;



public synchronized boolean isLocked() {



return locked;

}



public synchronized void setLocked(boolean locked) {

if (locked) {

System.out.println("get lock!!" + Thread.currentThread());

} else {

System.out.println("release lock!!" + Thread.currentThread());

}



this.locked = locked;

}



}



}







sleepする時間が短いと、synchronizedがどういうふうに効いているかわからなくなる感じがする。

下記は、ロックをとるのと、チェックを同時にさせているので上のソースよりは厳密性がたかまっていると思う。





public class TestLock {



Lock lock;



public static void main(String[] args) {



final TestLock testLock = new TestLock();



Runnable runnable = new Runnable() {

public void run() {

try {

while (true) {

testLock.go();

Thread.sleep(0);

}

} catch (InterruptedException e) {



e.printStackTrace();

}

}

};

Thread thread1 = new Thread(runnable);

Thread thread2 = new Thread(runnable);

Thread thread3 = new Thread(runnable);

thread1.start();

thread2.start();

thread3.start();

}



public TestLock() {

this.lock = new Lock();

}



public void go() throws InterruptedException {

if (!lock.lock()) {

return;

}

try {

a();

b();

c();

} finally {

lock.release();

}



}



public void a() {

System.out.println("process a " + Thread.currentThread());

}



public void b() throws InterruptedException {

System.out.println("process b " + Thread.currentThread());

Thread.sleep(10);

}



public void c() throws InterruptedException {

System.out.println("process c " + Thread.currentThread());

Thread.sleep(70);

// throw new RuntimeException("Wooooo");

}



class Lock {

boolean locked;



public synchronized boolean lock() {

if (this.locked) {

return false;

}

System.out.println("get lock!!" + Thread.currentThread());

this.locked = true;

return true;

}



public synchronized void release() {

System.out.println("release lock!!" + Thread.currentThread());

this.locked = false;

}



}



}

[java]内部クラスの使い方 2006/06/05
2006/11/26

内部クラスの使い方を研究しています。



public class TestScope {



public static void main(String[] args) {

TestScope testScope = new TestScope();

testScope.getInneClass().print();

testScope.getInneClass().changeOk(true);

testScope.getInneClass().print();

}



protected boolean isOk = false;

InnerClass innerClass;

public TestScope(){

this.innerClass = new InnerClass();

}



public InnerClass getInneClass(){

return this.innerClass;

}



public class InnerClass {

public InnerClass(){



}



public void print(){

System.out.println(TestScope.this.isOk);

}

public void changeOk(boolean b){

TestScope.this.isOk = b;

}

}

}