PocketPetとは?

Javaに対する批判

について
関連サイト JAVA JAVA

ウィキペディア

出典: フリー百科事典『ウィキペディア(Wikipedia)』(最終更新 2007年11月2日 (金) 07:36。)

Javaに対しては、優れた技術だと評価する人々がいる一方で、批判も少なくない。Javaは、ソフトウェアに関する複雑さを管理する問題に対して、革新的な方法を提供するという目標のもとで、開発された。多くの人々は、Java技術は、この期待に対して満足できる答えを提供したと評価している。しかしJavaにも欠点が無いわけではないし、どのようなプログラミング作法にも適応しているわけではない。また、どのような環境や要件にも普遍的に適応しているわけではない。

目次

クラスパス

Javaプログラムを実行する際、すべてのサードパーティのライブラリはクラスパスに存在する必要がある。これは移植性の障壁となる。なぜならばクラスパスの文法はプラットフォームに依存するからである(Windowsベースのシステムはサブディレクトリを区切るためにバックスラッシュ "\" を使用し、パス区切りにセミコロン ";" を使用している。[1] だが一方、他の多くのプラットフォームではサブディレクトリ区切りにスラッシュ "/" を、パス区切りにコロン ":" が使われる)。[2]

各々の.jar.zipアーカイブは、クラスパスにおいて明示的に名前がつけられる必要がある。この抜け道として、アスタリスク(*)で終わるクラスパスを指定することで、そのディレクトリにある.jarや.JARで終わるすべてのファイル名にマッチさせることができる。しかしながら、.zipや.classファイルのようなものはマッチしない。[1][2]

解決策・代替策

これらのクラスパス問題は環境変数CLASSPATHを使用せず、サン・マイクロシステムズが推奨する-classpathオプションを使用することで解決する。開発時は、-classpathオプションは、バッチファイルmakeApache Ant統合開発環境を使うことで利便な方法で指定することができる。Javaアプリケーションを利用したい実行エンドユーザに対しては、開発者が実行時には、マニフェストファイルにクラスパスを記述するか、FatJarやOneJar[3]という、複数のJarファイルを一つにまとめるツールを使うことで解決できる。

ライセンス

SunのJavaの財産的価値はフリーソフトウェアコミュニティで議論を呼んだ。なぜならばサン・マイクロシステムズ (Sun) のJavaの実装はフリーソフトウェアではなかったため、フリーソフトウェアや主にDebian$100ラップトップFedora Core のようなGPL互換ライセンスが要求されるプロジェクトにはSunのJavaを含めることはできなかった。 [4][5]

サン・マイクロシステムズ (Sun) は JavaOne 2006 で、Javaはオープンソースソフトウェアになるだろうと公表した。この声明はSun Softwareの上級副社長 Rich Green によって公表された。「オープンソースソフトウェアにするか否かという問題はない。どのような方法でオープンソースにするかが問題である。つまり我々はこれを実行する。」 [6]

2006年7月には、Sunの最高技術責任者 Robert Brewin はJavaは2007年6月に部分的にオープンソースになるが、全体のプラットフォームが完全なオープンソースになるには時間がかかるだろうとコメントしている。[7]

2006年11月13日はSunは標準版Java実行環境は2007年3月にGPLの下でリリースされる予定であることを公表した。[8] Java実行環境のソースコードはGPLの下で利用可能になる予定である。リチャード・ストールマンによると、これはJavaの罠の終焉を意味するとのことである。マーク・シャトルワースはJavaのオープンソース化についての最初のSunによる発表を「フリーソフトウェアコミュニティにとっての確かなマイルストーン」と評価した。[8][9]

解決策・代替案

Javaのライセンスの問題は、徐々に解決されつつある。時間が解決していると言える面もあるといえる。今後も、新たなライセンスの問題に直面しそうであれば、Java Community Process に提案するよう働きかけてみるという手段もある。フリーソフトウェア財団Eclipse Foundation など他のオープンソースコミュニティの助けを借りることで問題を解決に向けて進めることができる可能性がある。

リソース管理

Javaはメモリを管理するが、他のリソース(JDBCデータベース接続など)は管理しない。これらはC++でメモリを解放する必要があったのと同様、プログラマによって解放されなければならない。

メモリ管理

Javaはガベージコレクションによるメモリ管理機能を備える。これによって、完全ではないもののはプログラマがメモリリークを起こすようなプログラムを作ってしまう危険性を減らした。Javaでは、オブジェクトは常にヒープ領域に(JITコンパイラによって最適化されてスタックレジスタに割り当てられない限り)確保される。ローカル変数はスタックレジスタに確保される。C++ではオブジェクトをヒープ領域に割り当てるかスタック領域に割り当てるかをプログラマが選択することができたが、Javaではそれが不可能になっている。

オブジェクトはガベージコレクションによって管理されるが、Javaはプログラマに、ガベージコレクションがいつ起こるかを保証しない。たとえSystem.gc()を用いてもプログラマはガベージコレクションを阻止することも特定のオブジェクトを解放することもできない。これはプログラミングを簡易にしメモリリークの可能性を軽減するが、より効果的なメモリ処理を行うための柔軟性が犠牲になっている。Cアセンブリのような低水準言語はこの柔軟性を提供する。

C++などで書かれた多くのプログラムはメモリリークの犠牲になりがちだが、問題はメモリリークだけではない。ファイルハンドルやデータベース、ネットワーク接続のような他のリソースのリークは特に例外が投げられたときに常に起こりうる。 C++ではRAIIと呼ばれるイディオムによっていずれの問題も克服することができるが、Javaプログラマは忘れずにfinally節でリソースを解放する必要があり、Javaが何を解放するかということとプログラマは何を解放しなければならないのかということをきちんと理解する必要がある。

解決策・代替案

この問題は、メモリを増設する、最大ヒープメモリサイズを拡大するなどで解決できるケースもある。ウィークリファレンス(SoftReference)を用いることで多少の解決策になることはある。だが、JREJDKのバージョンが特定の古いものであることが要因となっていることもある。最新版のJREやJDKで実行、開発すれば問題発生率を下げることもできる。

finally節は、次世代のJava ( Java SE 7 ) で利用可能になる可能性があるクロージャで解決できることもある。これらは、場合によっては、ライブラリフレームワークによって解決できることもある。ファイル入出力の場合、Jakarta Commons IO、データベース接続のときは Jakarta Commons DBUtils、Hibernateや Apache Cayenne などのオブジェクトリレーショナルマッピングフレームワークを用いることでfinally節のことをあまり多く気にしなくても良いようにする手段がある。

言語選択

プリミティブ対オブジェクト / オートボクシング

Javaの設計者らは、現在他の言語にあるいくつかの機能(多重継承演算子多重定義タプルなど)を実装しないことを決めた。

総称型ジェネリクス)が Java 5.0 に導入されたとき、すでにJavaにはクラスの大規模な枠組みがあった(それらの多くはすでに非推奨となっていた)、そして後方互換性を保つため、総称型の実装方法として既存のクラスを維持することを可能にする(コンパイル時の)型消去(型削除、type erasure)が選ばれた。これは、他の言語と比べると、総称型の導入によって提供される機能を限定してしまう結果になった。[10][11]

Javaのプリミティブ型はオブジェクトではない。プリミティブ型は値への参照ではなく値そのものをスタック領域に保持している。これはパフォーマンスの理由により行われた。このためJavaは純粋なオブジェクト指向言語と見なされてない。またこのことによりリフレクションがより複雑になっている。しかし、Java 5.0 は、コンパイル中に要求された場合にプリミティブ型を対応するプリミティブラッパークラスのオブジェクトに自動変換する機能(オートボクシング)をサポートしている。オートボクシングではNullPointerExceptionが投げられる可能性がある。オートボクシングは暗黙のうちに起こる(キャストやメソッド呼び出しを伴わない)ため、このNullPointerExceptionという非チェック例外はJavaプログラムのコードに目を通しただけでは明確にはならない恐れがある。

非virtualメソッド

Javaはメソッドを非virtualにする手段を提供しない(オーバーライドを禁止するためにfinal修飾子を使用することで"sealed"(シールド、封印、密閉)にすることはできる)。これは派生クラスに、同じ名前の関係の無いメソッドを定義させる方法がないことを意味する。これは基底クラスが別の人間によって設計されるときに問題となることがあり、また、新しいバージョンが、派生クラスで同じ名前のメソッドがすでに存在するときに、同じ名前とシグネチャのメソッドを導入することで問題となることがある。これは、どちらのクラスの設計者の意図にも反して、派生クラスのメソッドが基底クラスのメソッドを暗黙のうちにオーバーライドするであろうことを意味する。これらのバージョン問題にある程度適合するために Java 5.0 は@Override アノテーションを導入しているが、後方互換性を保つには、それをデフォルトでは強制できない。

単一パラダイム

Javaは主に単一パラダイム言語である。Java 5.0 に登場した static imports の追加はこれまでのJavaよりも手続きパラダイムによりよく順応する。

例外処理

JavaではC++でオプションとされていた例外処理の仕様を取り込んだが、この際チェック対象の例外に対応するthrow文を必須とした。例外のチェックは小規模なシステムにとっては役立つが、大規模なシステムについても有益であるかどうかについては統一的な見解には至っていない。特に上位のコードでは下位のコードから発生するエラーを意識したくない(例:NamingException(名前解決例外))。名前クラスの作成者は名前解決例外をチェック対象の例外として上位コードに対応を強制するか、コンパイル時のチェックを使わずに下位のコードからの例外を連鎖的に通知するかを選択する必要がある。

クロージャ

匿名内部クラスは基本的なクロージャを提供するが、これは完全ではなく、クラスのメンバーとしてかFinal型で宣言する必要がある。これは、変数のスコープを抜けたときに削除できるような、様々な寿命に対応したスタックモデルをJVM実装者が選択出来るようにするためである。例えば"Runnable"をクロージャとして使用した場合、単純にコードを大括弧で括って書くことが出来ないため、コードを入れるために"run"メソッドを宣言する必要がある。

浮動小数点演算

Javaの浮動小数点数演算は主にIEEE 754(二進化浮動小数点数演算標準)をベースとしているが、例えばIEEE 754に必須とされる例外フラグや方向指定の丸めなどの、 いくつかの機能については"strictfp"修飾子を指定した場合でもサポートされない。Javaの仕様として知られているものはJava自体の問題ではないが、浮動小数点数演算を行う上で避けて通れない問題である。 [12][13]

ルックアンドフィール

Swingプラットフォームを使って、Javaで書かれたアプリケーションのグラフィカルユーザインタフェース (GUI) のルックアンドフィール(Look and feel、直訳すると「外観と操作感」)は、大抵ネイティブのアプリケーションのものと異なる。 プログラマはネイティブのウィジェットを表示するAWT(ネイティブであるためOSのプラットフォームと同じ見た目を提供する)を使うことを選択することができる。しかしAWTツールキットは、高度なウィジェットのラッピングを必要としかつ様々なサポートされたプラットフォームで移植性を犠牲にしない高度なGUIプログラミングには、向いていない。そして、SwingとAWTにはとりわけ高水準ウィジェットにおいてAPIが大きく異なる。

Swingツールキットは全てJavaで実装されている。Swingツールキットはネイティブアプリケーションとは異なるルックアンドフィールを持つという問題がある。一方でSwingツールキットのウィジェットはネイティブなツールキットの機能に限定されないという利点がある。この利点は全てのプラットフォームで利用できることが保証される最も基本的な描画機構を使ってウィジェットを再実装していることによる。不幸にも、(2006年8月の時点で)Java実行環境 (JRE) のデフォルトのインストールでは、デフォルトの埋め込みMetal(メタル) ルックアンドフィールの代わりに、システムの「ネイティブ」なルックアンドフィールを使わなかった。プログラマがネイティブなルックアンドフィールを設定するようにしないならば、ユーザーは外観がネイティブアプリケーションのそれとは非常に異なるアプリケーションに遭遇するだろう。 Mac OS X の配布元に限って含まれる アップルコンピュータ自身のJava実行環境の最適化バージョンは、デフォルトで「デフォルト」をセットし、"Aqua" のルックアンドフィールを実装し、Macintosh上のSwingアプリケーションは、ネイティブなソフトウェアに似た外観を提供している。Mac OS X の環境でさえ、プログラマはそのアプリケーションがAquaのように見えることを確実とするために、若干の余分の仕事をまだしなければならない(例えば、それらはメニューバーが Microsoft Windows のようにアプリケーションウィンドウ内部ではなくOS Xメニューバー内部に表示させるために、システムプロパティをセットする必要がある)。

解決策・代替案

この問題は、開発者がJavaのバージョンを Java SE 6 以降にアップグレードすることで解決する。Java SE 6 になってからJavaのデスクトップまわり、グラフィカルユーザインタフェース環境は一新され、開発効率は高まっているため、以前のバージョンよりも開発の手間はかからなくなっている。

パフォーマンス

一般

Javaプログラムのパフォーマンスに関して一般論を述べることは不可能である。なぜなら、実行時の性能は、言語自身が持つ固有の特性よりも、JavaコンパイラJava仮想マシンの品質に非常に大きく影響されるからである。Javaバイトコードの実行方法は、仮想マシンによって実行時に翻訳して実行する方法と、ロード時もしくは実行時に機械語にコンパイルしてハードウェアによって直接的に実行する方法がある。前者の翻訳実行する方法は機械語の実行よりも遅く、後者のロード時もしくは実行時にコンパイルして実行する方法は、最初のコンパイル時にパフォーマンスが犠牲になる。

この問題は現在に於いては、さほど大きな障壁にはなっていない。なぜならば、コンピュータの性能はムーアの法則によって刻一刻と進化しているからである。そしてJavaもバージョンアップするにつれて最適化技術を進歩させてきた。これによって、Javaの初回起動時のオーバーヘッドは誤差の範囲内になりつつある。C++ではJavaよりも高速にできるよう手動で最適化ができるが、C++でJavaの実行時最適化技術を真似することは困難である。

言語仕様による制約

Javaだけに限ったことではないが、パフォーマンス上の障壁となる言語仕様がいくつか存在する。それは例えば配列境界チェックや実行時型チェック、仮想関数などである(コンパイラ時の最適化で解消できるものもある)。また、言語仕様の欠落がパフォーマンスに影響する場合もある。例えば、Javaは構造体の配列や真の多次元配列を持たず、オブジェクト(や配列)への参照の配列が定義できるのみである。また、Javaでは関数から複数の値を返すためにはオブジェクトを使用する以外の方法がない。これらによってJavaのプログラムコードは、他の言語で書かれたコードよりも頻繁にヒープを使用しなければならなくなっている。

ガベージコレクション

不要オブジェクトの自動回収を行うガベージコレクションは明示的なメモリ開放に比べそのオーバーヘッドは大きいが、ガベージコレクタの実装やアプリケーションでのオブジェクトの利用状況によってその影響はまちまちに変化する。多くのJava仮想マシンは世代別ガベージコレクションの採用によって動的メモリ管理を高速化しているため、多くのアプリケーションでは高い性能を示している。

バイトコード対ネイティブコンパイル

ジャストインタイムコンパイル(JITコンパイル)とネイティブコンパイルの性能差はほとんど無いとされるが、よく議論の種にもなる。JITコンパイルには時間が掛かるため、短時間で終了するアプリケーションや巨大なプログラムでは問題となる。しかし、一旦ネイティブコードに変換すれば数値計算においてもネイティブコンパイルと同等の性能を示す。

Javaはメソッド呼び出しの明示的なインライン化をサポートしないものの、多くのJITコンパイラではバイトコード読み込み時にインライン展開を行い、また実行時のプロファイリングを利用してその効率をより高めている。HotSpot仮想マシンが採用している動的再コンパイルでは、実行時でしか取得できない情報を利用することで、多くのプログラミング言語が採用する静的コンパイル方式を超える性能を得る場合もある。

ハードウェアインタフェース

Javaはセキュリティと移植性を重視して設計されたので、Javaではマシンアーキテクチャとアドレス空間への直接アクセスをサポートしていない。スキャナ(デジタルカメラ、オーディオレコーダ、ビデオキャプチャないし実質的に直接メモリ空間の制御(一般的に、ドライバインストールを必要とするハードウェアやそれらの部品)を必要とする特定の一部のハードウェアを動かすことはJavaでは容易に実現できないことを意味する。この問題の実例はJavaのバージョン1.0で見られた。様々なプリンタドライバへのインタフェースコードがこの初期のJava実行環境に含まれず、プリンタへのアクセスが可能でなかった。

ネイティブコードとインタフェース

ハードウェアに直にアクセスするクライアントサイドまたはサーバーシステムは、ネイティブコードとJavaライブラリを橋渡しするJava Native Interface(JNI)を使って、C、C++およびアセンブリ言語とJavaを組み合わせる方法を取る。また、ハードウェアアクセスを担うネイティブコードとJavaとの通信をファイルやデータベース、共有メモリを介して行う方法もあるが、理想的なやり方ではない。

JNIを使うことで、プラットフォーム依存性、潜在的なデッドロックメモリリーク、場合によっては性能の著しい劣化などの問題が発生しうる。また、2つの異なるコードベースをメンテナンスするために必要となるコードの複雑性は、言うまでもない。しかし、それは、例えば.NET Framework 共通言語ランタイムのように、他の仮想マシン言語と共通する事例である(Platform Invocation Servicesを参照)。

解決策・代替案

現在では今のところ、Javaはまだまだハードウェア開発、デバイスドライバ開発には適していない点が多い。この問題について、JavaでUSBドライバ開発ができる Java Communication API という技術がすでにある。他にも、Jini対応機器を端末に接続すると、サーバから自動的にJava製ドライバを端末にダウンロードしてその機器を使うことができる技術Jiniというものが考えられている(JiniはしばしばJNI (Java Native Interface) と誤読することがあるので要注意である)。

一貫性のないJava仮想マシン実装

Javaは、Java仮想マシン (JVM) の上部で動くバイトコード言語である。異なるプラットフォームで実行できる能力と言語の互換性は、最終的にはJVM実装の安定性とJVMのバージョンに依存している。Javaは非常に様々なシステム上で動くとうたわれているが、最新のJVM (とJRE) はWindows、Linux、Solaris対応だけ活発に更新されている状況である。HP (Java for HP-UXなど)とIBM (for MVS、AIX、OS/400)は、それぞれのプラットフォームファミリー独自の実装を提供するが、必ずしも最新のサン・マイクロシステムズのリリースを反映していない。他のプラットフォームにおけるJVM実装も、たいてい今後も続くが、時々一般の実装例よりも何年か何ヶ月か遅れるので、互換性問題が生じる。具体的な例を示すと、Java 2 Platform Standard Edition 1.5(J2SE 1.5)をサン・マイクロシステムズがリリースしたのは2004年9月30日[14]だが、Mac OS X用J2SE 1.5をアップルコンピュータが公開したのは2005年3月[15]であり、5ヶ月余りの差が生じている。

移植性・互換性

Write once, run anywhere」(WORA、一度書けばどこでも動く)という言葉があるとおり、Javaの目標の一つにプラットフォーム非依存があげられる。 JavaコンパイラJava仮想マシン用の中間言語バイトコード)を生成する。 コンパイルされたJavaのプログラムは、Java仮想マシンを実行環境として動作する。 この仮想マシンがハードウェア間の差異を吸収することで、プラットフォーム非依存を実現している。 ただし、現時点では一部にプラットフォーム依存の部分があり、完全なプラットフォーム非依存ではない。

また、マルチプラットフォームにするということは、一部のプラットフォームにしかない独自の機能はJavaから使えないことを意味する。 例えば Windows 用グラフィックス APIDirectX はJavaから直接呼び出すことは出来ない。 そのため、橋渡しをするための拡張APIが提供されている。

またJavaではバージョン間の下位互換性・上位互換性の問題が議論の対象になっている。 Javaではバージョン間の互換性をある程度の水準まで達成している。 しかし、バージョンの異なる実行環境の取り扱いには課題が残っている。 例えば J2SE 1.4 実行環境用に書かれたプログラムは、実行環境に J2SE 1.3 を想定すると明示的に指定してコンパイルしなければ J2SE 1.3 実行環境では動かず、利用するライブラリが J2SE 1.4 以降から追加されたものである場合には J2SE 1.3 実行環境での実行を諦めなければならない。 J2SE 1.3 からの上位互換性は、J2SE 5.0 まで保証されている。 J2SE 1.3 以降のJavaプログラムでは下位互換性は保証されないが、Java実行環境 (JRE) の自動アップデート機能によって仮想マシンを最新バージョンにアップデートすれば解決できる。 JDK 1.1、J2SE 1.2 時代のJavaプログラムは、現在となっては古いため、上位互換性問題に引っかかる可能性がある。

その場合は、そのJavaプログラムを作った者に最新版のJavaコンパイラでもコンパイルが通るように直して貰うしかない。

解決策・代替案

この問題も、サン・マイクロシステムズのJavaコーディング規約をJavaプログラマが守っていればほぼ起きることがなく、Javaソースコード上のimport宣言や新しく加わったJavaキーワード(enum や assert)と重複するものが無ければほぼ心配することもなくなる。とくに、多くの場合において、これらの問題はコーディング規約だけでなく、統合開発環境CheckStyleFindBugsなど各種ツールなどによって解決できるケースがある。Javaプログラマは、日頃からCheckStyleやFindBugsを使ってプログラミングしていれば、上位互換性の問題につき当たる可能性は下がる。

その他

  • 2億9千万年問題: 西暦2000年近辺で2000年問題が話題になった当時には「Javaには2000年問題は存在しない」と言われていたが、2億9千万年問題と言われるものが存在する。西暦292,471,208年には時刻が桁溢れを起こし西暦1970年に戻ってしまうという問題がある。

関連項目

  1. ^ a bSetting the class path” (Windows). Java SE 6 Documentation, JDK Development Tools Reference. Sun Microsystems. Accessed 2007-01-27.
  2. ^ a bSetting the class path” (Solaris and Linux). Java SE 6 Documentation, JDK Development Tools Reference. Sun Microsystems. Accessed 2007-01-27.
  3. ^ [http://www-06.ibm.com/jp/developerworks/java/041217/j_j-onejar.html developerWorks > Java technology > One-JARでアプリケーションの配布を単純化する カスタムのクラスローダーによるパワー・プログラミング]
  4. ^ さらに、一部の専門家は Java SCSL ライセンスは誰もがJavaのフリーソフトウェアクリーンルーム実装に貢献するために著作権を放棄するライセンス条項に同意することを要求していると、主張している。しかしながら、サン・マイクロシステムズの人々は、改訂されたJavaライセンス条項の下ではもはや問題ではなくなったと主張している。"What full-fledged Java development platforms are available in Debian?""Debian FAQ". 2006-12-08閲覧.
  5. ^ Java SE Tainting Issues"Java.net: The Source for Java Technology Collaboration. 2006-12-09閲覧..
  6. ^ Galli, Peter (2006-05-16). “Open-Source Java? Not If but How” eWeek. 2006-12-09閲覧.. Sunの論点は彼らが、非互換分岐なしにオープンソースJavaを欲しがる方法であった Phipps, Simon (2006-05-26). “Forks Aren't A Problem” 2006-12-09閲覧.。 これは次のJavaOneでSunの最高経営責任者を務めるジョナサン・シュワルツのコメントにより説明される可能性がある。彼のブログではこう語っている。「我々はオープンソースJavaの厳粛な前進を行っているが(GPLライセンスが議論中であるというは皮肉にもかかわらず)、何が一番大事であるかに議論の焦点をあてている。一番大事なこととはソースコードを入手する機会ではない(ソースコードはすでに広く利用可能である)。一番大事なことは互換性を確固とすることである。」 Schwartz, Jonathan (2006-06-25). “60 Days into the Job&” 2006-12-09閲覧..
  7. ^ Krill, Paul (2006-06-24). “Sun CTO: Incremental open-sourcing of Java is the way” Computer World. 2006-12-09閲覧.
  8. ^ a b Sun Opens Java” Sun Microsystems: 2006-11-13. 2006-12-09閲覧.
  9. ^ Sun 'releases' Java to the world” BBC News: 2006-11-13. 2006-12-09閲覧.
  10. ^ Generics in Java” Object Computing, Inc.. 2006-12-09閲覧.
  11. ^ What's Wrong With Java: Type Erasure” 2006-12-06. 2006-12-09閲覧.
  12. ^ Kahan, W.; Joseph D. Darcy (1998-03-01). “How Java's Floating-Point Hurts Everyone Everywhere” (PDF) 2006-12-09閲覧.
  13. ^ Types, Values, and Variables” Sun Microsystems. 2006-12-09閲覧.
  14. ^ Sun Microsystems, Inc. (2004-09-30). “Sun Ships New Version of Java Platform” 2007年10月15日閲覧.
  15. ^ Apple Inc. (2005-03-16). “About Java 2 Platform Standard Edition (J2SE) 5.0 Release 1 for Tiger” 2007年10月15日閲覧.

外部リンク

Wikibooks
ウィキブックスJava関連の教科書や解説書があります。
ウィキペディアでの『Javaに対する批判』の改訂履歴
Text is available under GNU Free Documentation License

今日の旬ワード

1. AKB48
5. 遊助
9. mixi
10. Cocco