この章では、JDK 1.1 で推奨されないメソッドについて、およびその一覧を示します。
あるメソッドが重要とみなされなくなったためにクラスから削除される可能性があるので使用すべきではないとき、そのメソッドは推奨されません。こうしたことが起きるのは、クラスに変更が加えられていくと、メソッド名が変更されたり、新しいメソッドが追加されたり、属性が変更されるなど、そのクラスの API が変更されるためです。新しい API への移行を促すため、推奨されないクラスおよびメソッドのマニュアル (API ドキュメント) には、コメントとして「@deprecated」という印が付けられています。次の表に、推奨されないメソッドの一覧を示します。
表 4-1 推奨されないメソッドクラス | メソッド | 推奨するメソッドまたは代替法 |
java.awt.BorderLayout | addLayoutComponent() | addLayoutComponent(component,object) |
java.awt.CardLayout | addLayoutComponent() | addLayoutComponent(component,object) |
java.awt.CheckboxGroup | getCurrent() | getSelectedCheckbox() |
setCurrent() | setSelectedCheckbox() | |
java.awt.Choice | countItems() | getItemCount() |
java.awt.Component | getPeer() | |
enable() | setEnabled(true) | |
disable() | setEnabled(false) | |
show() | setVisible(true) | |
hide() | setVisible(false) | |
location() | getLocation() | |
move() | setLocation() | |
size() | getSize() | |
resize() | setSize() | |
bounds() | getBounds() | |
reshape() | setBounds() | |
preferredSize() | getPreferredSize() | |
minimumSize() | getMinimumSize() | |
layout() | doLayout() | |
inside() | contains() | |
locate() | getComponentAt() | |
deliverEvent() | dispatchEvent() | |
postEvent() | dispatchEvent() | |
handleEvent() | processEvent() | |
mouseDown() | processMouseEvent() | |
mouseDrag() | processMouseMotionEvent() | |
mouseUp() | processMouseEvent(MouseEvent) | |
mouseMove() | processMouseMotionEvent() | |
mouseEnter() | processMouseEvent() | |
mouseExit() | processMouseEvent() | |
keyDown() | processKeyEvent() | |
keyUp() | processKeyEvent() | |
action() | コンポーネント破棄アクションイベントに対する ActionListener として登録してください。 | |
gotFocus() | processFocusEvent() | |
lostFocus() | processFocusEvent() | |
nextFocus() | transferFocus() | |
java.awt.Container | countComponents() | getComponentCount() |
insets() | getInsets() | |
preferredSize() | getPreferredSize() | |
minimumSize() | getMinimumSize() | |
deliverEvent() | dispatchEvent() | |
locate() | getComponentAt() |
表 4-2 推奨されないメソッド
クラス | メソッド | 推奨するメソッドまたは代替法 |
java.awt.FontMetrics | getMaxDescent() | getMaxDescent() |
java.awt.Frame | setCursor() | Component 中の setCursor() メソッド |
getCursorType() | Component 中の getCursor() メソッド | |
java.awt.Graphics | getClipRect() | getClipBounds() |
java.awt.List | countItems() | getItemCount() |
clear() | removeAll() | |
isSelected() | isIndexSelected() | |
allowsMultipleSelections() | isMultipleMode() | |
setMultipleSelections() | setMultipleMode() | |
preferredSize() | getPreferredSize() | |
minimumSize() | getMinimumSize() | |
delItems() | public としては使用しないでください。package private 用に残されています。 | |
java.awt.Menu | countItems() | getItemCount() |
java.awt.MenuBar | countMenus() | getMenuCount() |
java.awt.MenuComponents | getPeer() | |
postEvent() | dispatchEvent() | |
java.awt.MenuContainer | postEvent() | dispatchEvent() |
java.awt.MenuItem | enable() | setEnabled(true) |
disable() | setEnabled(false) | |
java.awt.Polygon | getBoundingBox() | getBounds() |
inside() | contains() | |
java.awt.Rectangle | reshape() | setBounds() |
move() | setLocation() | |
resize() | setSize() | |
inside() | contains() | |
java.awt.ScrollPane | layout() | doLayout() |
java.awt.Scrollbar | getVisible() | getVisibleAmount() |
setLineIncrement() | setUnitIncrement() | |
getLineIncrement() | getUnitIncrement() | |
setPageIncrement() | setBlockIncrement() | |
getPageIncrement() | getBlockIncrement() | |
java.awt.TextArea | insertText() | insert() |
appendText() | append() | |
replaceText() | replaceRange() | |
preferredSize() | getPreferredSize() | |
minimumSize() | getMinimumSize() | |
java.awt.TextField | setEchoCharacter() | setEchoChar() |
preferredSize() | getPreferredSize() | |
minimumSize() | getMinimumSize() | |
java.awt.Window | postEvent() | dispatchEvent() |
java.io.ByteArrayOutputStream | toString() | toString(String enc) または toString()。これらは、プラットフォームのデフォルトの文字コードを使用します。 |
java.io.DataInputStream | readLine() | BufferedReader.readLine() |
java.io.PrintStream | printStream() | PrintWriter class |
java.io.StreamTokenizer | streamTokenizer() | 入力ストリームを文字ストリームに変換してください。 |
java.lang.Character | isJavaLetter() | isJavaIdentifierStart(char) |
isJavaLetterOrDigit() | isJavaIdentifierPart(char) | |
isSpace() | isWhitespace(char) | |
java.lang.ClassLoader | defineClass() | defineClass(java.lang.String,byte[],int,int) |
java.lang.Runtime | getLocalizedInputStream() | InputStreamReader および BufferedReader クラス |
getLocalizedOutputStream() | OutputStreamWriter、BufferedWriter、PrintWriter クラスを使用してください |
表 4-3 推奨されないメソッド
クラス | メソッド | 推奨するメソッドまたは代替法 |
java.lang.String | string() | 文字コード名を取得するかまたはデフォルトの文字コードを使用する、String コンストラクタを使用してください。 |
getBytes() | getBytes(String enc)または getBytes() | |
java.lang.System | getenv() | java.lang.System.getProperty メソッドのシステムプロパティおよび Boolean, Integer, または Long プリミティブ型の対応する get TypeName メソッドを使用してください。 |
java.lang.Thread | resume() | 「推奨されないスレッドメソッド」 を参照。 |
java.lang.Thread | stop() | 「推奨されないスレッドメソッド」 を参照。 |
java.lang.Thread | suspend() | 「推奨されないスレッドメソッド」 を参照。 |
java.util.Date | getYear() | Calendar.get(Calendar.YEAR)-1900 |
setYear() | Calendar.set(Calendar.YEAR+1900) | |
getMonth() | Calendar.get(Calendar.MONTH) | |
setMonth() | Calendar.set(Calendar.MONTH,int month) | |
getDate() | Calendar.get(Calendar.DAY_OF_MONTH) | |
setDate() | Calendar.set(Calendar.DAY_OF_MONTH, int date) | |
getDay() | Calendar.get(Calendar.DAY_OF_WEEK) | |
getHours() | Calendar.get(Calendar.HOUR_OF_DAY) | |
setHours() | Calendar.set(Calendar.HOUR_OF_DAY,int hours) | |
getMinutes() | Calendar.get(Calendar.MINUTE) | |
setMinutes() | Calendar.set(Calendar.MINUTE,int minutes) | |
getSeconds() | Calendar.get(Calendar.SECOND) | |
setSeconds() | Calendar.set(Calendar.SECOND,int seconds) | |
parse() | DateFormat.parse(String s) | |
getTimezoneOffset() | Calendar.get(Calendar.ZONE_OFFSET)+ Calendar.get(Calendar.DST_OFFSET) | |
toLocaleString() | DateFormat.format(Date date) | |
toGMTString() | DateFormat.format(Date date) (GMT タイムゾーンを使用) | |
UTC() | Calendar.set(year+1900,month,date,hrs, min,sec) または GregorianCalendar(year+1900,month, date,hrs,min,sec) (UTC タイムゾーンを使用)、その後に Calendar.getTime().getTime() |
Thread.stop、Thread.suspend、Thread.resume メソッドは、JDK 1.1 では推奨されません。Thread.stop は、本質的に安全でないためです。スレッドを停止すると、スレッドがロックしたモニターをすべてロック解除してしまいます。ThreadDeath 例外がスタックを上に移動した場合に、モニターのロックは解除されます。これらのモニターによって以前に保護されたオブジェクトが不整合の状態になっている場合、その他のスレッドはこれらのオブジェクトが不整合の状態にあるとみなします。そのようなオブジェクトは破損しているとみなされます。
破損しているオブジェクトに対して動作するスレッドは、明示的または非明示的に不特定に動作します。検査が行われない他の例外とは異なり、ThreadDeath はこのようなスレッドを警告メッセージを表示せずに停止します。このように、プログラムが破損しているということを示す警告が、ユーザーには何も通知されません。その後予期しない時に、プログラムが破損していることがわかります。
Thread.stop を、より安全にスレッドを終了させるコードに置き換えてください。ほとんどの stop() は、対象となるスレッドの実行を停止するかどうかを判定する変数を変更するコードに置き換えることができ、また置き換える必要があります。そのスレッドは、定期的にその変数を検査するようにする必要があります。スレッドを停止するようにその変数が示している場合は、スレッドは通常どおりに run() メソッドから返るようにします。たとえば、次のような start()、stop()、run() メソッドがアプレットに含まれているとします。
public void start() { blinker = new Thread(this); blinker.start(); } public void stop() { blinker.stop(); // UNSAFE! } public void run() { Thread thisThread = Thread.currentThread(); while (true) { try { Thread.sleep(interval); } catch (InterruptedException e){ } repaint(); } } |
アプレットの stop() および run() メソッドを以下のように変更することによって、Thread.stopを使用しなくて済みます。
public void stop() { blinker = null; } public void run() { Thread thisThread = Thread.currentThread(); while (blinker == thisThread) { try { Thread.sleep(interval); } catch (InterruptedException e){ } repaint(); } } |
また、Thread.suspend は、本質的にデッドロックを引き起こす可能性があるため、推奨されません。この Thread.resume も、他のコードに書き換える必要があります。スレッドが中断された時に、そのスレッドが重要なシステム資源を保護するモニターをロックしていると、ターゲットスレッドの実行が再開されるまで、他のスレッドはこのシステム資源にアクセスすることはできません。ターゲットの実行を再開するスレッドが Thread.resume を呼び出す前にモニターをロックしようとすると、デッドロックが発生します。
このようなデッドロックが発生すると通常はプロセスがフリーズして応答しなくなるので、デッドロックが発生したことがわかります。前述の Thread.stop の場合と同様に、適切なスレッドの状態 (active または suspended) を示す変数をスレッドに持たせる必要があります。スレッドが中断されたときには、スレッドは Object.wait を使用して待機します。スレッドが再開されたときには、Object.notify によってスレッドが再開されたことがターゲットスレッドに通知されます。たとえば、以下のように blinker というスレッドの状態を切り替えるイベントハンドラ mousePressed が、アプレットに含まれているとします。
public void mousePressed(MouseEvent e) { e.consume(); if (threadSuspended) blinker.resume(); else blinker.suspend(); // DEADLOCK-PRONE! threadSuspended = !threadSuspended; } |
上記のイベントハンドラを以下のように変更することによって、Thread.suspend および Thread.resume を使用せずに済みます。
public synchronized void mousePressed(MouseEvent e) { e.consume(); threadSuspended = !threadSuspended; if (!threadSuspended) notify(); } |
ループを実行するために、次のコードを追加します。
synchronized(this) { while (threadSuspended) wait(); } |
wait() メソッドは InterruptedException をスローするので、try ... catch 節の中に置く必要があります。sleep と同じ節の中に wait() メソッドを置くこともできます。スレッドが再開された時にウィンドウがただちに再描画 (repaint ) されるように、check は sleep よりも後に置いてください。たとえば次のように run() を記述します。
public void run() { while (true) { try { Thread.sleep(interval); synchronized(this) { while (threadSuspended) wait(); } } catch (InterruptedException e){ } repaint(); } } |
notify() が mousePressed() メソッドの中にあり、run() メソッドの中の wait() が synchronized ブロック中にあることに注意してください。これは Java 言語で必要とされていることで、wait() と notify() が適切にシリアライズされるようにします。つまり、中断されたスレッドが notify() を認識できずに中断したままになる可能性がある競合状態が発生するのを防ぎます。