Depends on the app. Swing is still slow, but that's no so much related to the raw Java VM performance as it is related to Swing's poor design/implementation. Many people's impression of Java is colored by subjective UI performance. Go to eclipse.org and download the Eclipse IDE built in IBM's SWT, or go get Jazz, a pure Java Swing GUI alternative. Both are very very fast.
The Java HotSpot server compiler is very fast, and with the new ConcurrentGC and New I/O architecture, you can now write OpenGL apps that move arround enormous amounts of data, like the Java Canyon3D demo which has about 100M of geometry data.
About 2 years ago, a friend and I both implemented a certain block cipher cryptographic algorithm in both Java (me) and C++ (him). When both were using OO features, Java turned out to be actually faster because Java can even inline data dependent polymorphic (virtual) dispatches whereas C++ can't. But when he switched to C-style coding for the algorithm (no polymorphism, pass a struct around by ref), he beat Java 1.3.1 by about 20% with MSVC.
On raw computation stuff (e.g. do a matrix multiply) , JDK 1.4.1 will do close to C++ speeds, but once you introduce the APIs into the mix, depending on which API, it could be significantly slower. Also, it depends on whether the app creates lots of objects or not.
Java programmers typically create lots of objects, and a C++ app that does no dynamic heap allocation (only stack based) will trounce Java. However, usually such a Java program can be refactored with a custom allocator that avoids creating new objects on the heap. It's just that most people won't go through the trouble.
Java's not ready for writing Doom3, but for regular non-realtime apps, it's great (if you avoid Swing, or code carefully around Swing inefficiencies), and for server-side stuff it's great. I'm not gonna say Java is "as fast" or close to C speeds. But for what I use it for, it's good enough.
Honestly, the biggest problem with Java on the desktop today isn't performance, it's memory usage. Currently, each application exists in its own Java VM. That means if you run 3 apps, you have 3 copies of all the java.* packages compiled into RAM. So there is no sharing going on between processes of the core Java platform.
Java 1.5 (Tiger) will probably address this with the Isolation API (
http://www.jcp.org/en/jsr/detail?id=121) which will allow your computer to run one Java VM, where the standard Java APIs get loaded and compiled once, and then each application you launch will merely spawn a process which uses only an incremental amount of memory more (the memory used to compile your classes, but the memory use allocate on the heap)
This means no longer will you have a bunch of 64mb Java processes floating around. You'll have one master process, probably 32-64mb, and for each application you launch, you'll probably only eat marginally more heap.