Javaに対する批判
不要オブジェクトの自動回収を行うガベージコレクションは明示的なメモリ解放に比べそのオーバーヘッドは大きいが、ガベージコレクタの実装やアプリケーションでのオブジェクトの利用状況によってその影響はまちまちに変化する。多くのJava仮想マシンは世代別ガベージコレクションの採用によって動的メモリ管理を高速化しているため、多くのアプリケーションでは高い性能を示している。
Javaでは、内部クラス、ローカルクラス、匿名クラスを使用することで、基本的なクロージャに近い記述が実現できる。しかしこれは完全ではなく、ローカルクラス/匿名クラス外の変数に対する参照を、ローカルクラス/匿名クラスのフィールドとして暗黙キャプチャできるように、final修飾子付きで宣言する必要がある。これは、変数のスコープを抜けたときに削除できるような、様々な寿命に対応したスタックモデルをJVM実装者が選択できるようにするためである。Java 8では実質的にfinalとみなせる変数は明示的にfinal修飾する必要がなくなったが、依然として再代入は許可されない。
また匿名クラスの構文も冗長であり、例えばRunnableインタフェースを要求する場面で、同インタフェースを実装する匿名クラスを定義する場合、単純なコードブロックとして定義することはできず、Runnable.run()メソッドを実装するようなクラスのブロックを定義する必要がある。Java 8ではラムダ式と関数型インタフェースによりこの問題を改善している。
しかし、バージョンの異なる実行環境の取り扱いには課題が残っている。例えばJ2SE 1.4実行環境用に書かれたプログラムは、実行環境にJ2SE 1.3を想定すると明示的に指定してコンパイルしなければJ2SE 1.3実行環境では動かず、利用するライブラリがJ2SE 1.4以降から追加されたものである場合にはJ2SE 1.3実行環境での実行を諦めなければならない。J2SE 1.3に対する後方互換性は、2世代先であるJ2SE 5.0まで保証されている。J2SE 1.3以降のJavaプログラムでは前方互換性は保証されないが、Java実行環境 (JRE) の自動アップデート機能によって仮想マシンを最新バージョンにアップデートすれば解決できる。JDK 1.1、J2SE 1.2 時代のJavaプログラムは、現在となっては古いため、後方互換性問題に引っかかる可能性がある。例えば、古いプログラムが新しいバージョンのJDK/JREで廃止されたAPIを使用している場合に問題となる。その場合は、そのJavaプログラム開発者に最新版のJavaコンパイラでもコンパイルが通るように修正してもらうしかない。