java 线程“main”中的异常java.lang.NoSuchMethodError:java.util.concurrent.ConcurrentHashMap.keySet()Ljava /

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 线程“main”中的异常java.lang.NoSuchMethodError:java.util.concurrent.ConcurrentHashMap.keySet()Ljava / 相关的知识,希望对你有一定的参考价值。

#!/usr/bin/env bash
# Tested on Ubuntu with WebUpd8 install of Oracle JDK 8
/usr/lib/jvm/java-8-oracle/bin/javac -source 1.7 -target 1.7 HelloCovariance.java
/usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java HelloCovariance
Interaction of Covariance and Java Cross-compile
================================================

Here is a Java class with a compatibility problem:

HelloCovariance.java:
```java
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class HelloCovariance {
  public static void main(String[] args) {
    ConcurrentHashMap<String, String> properties = new ConcurrentHashMap<>();
    Set<String> keySet = properties.keySet();
  }
}
```

Here is a session log that seems implausible:

```plain
$ /usr/lib/jvm/java-8-oracle/bin/javac -source 1.7 -target 1.7 HelloCovariance.java 
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
$ /usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java HelloCovariance 
Exception in thread "main" java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
	at HelloCovariance.main(HelloCovariance.java:7)
```

Why does this **NoSuchMethodError** happen?

Compare the JavaDoc for **ConcurrentHashMap#keySet()** in Java 1.7 and 1.8:
 * http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html#keySet()
 * http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#keySet--

Notably the Java 1.7 **ConcurrentHashMap#keySet()** returns a `Set<K>` while the 1.8 **ConcurrentHashMap#keySet()** returns a `ConcurrentHashMap.KeySetView<K,V>`.

How can this work?  It turns out that a overriding method is allowed to return a sub-type of the parent methods return type.  This is due to covariance.  This is useful in certain cases where you know the concrete types and want to avail of them somehow.

You'll notice that there is a warning about bootstrap classpath.  It turns out those bootstrap classpath warnings have a lot of merit.  The safest fix is clearly to compile with a bootstrap classpath.

Failing that you can avoid the unnecessary use of a concrete type for a variable here.

Using the general **Map** interface in place of the concrete **ConcurrentHashMap** type here side-steps the coupling to the Java 8 return type and will allow this code to be compiled with Java 8 and run on Java 7.

HelloSidestep.java:
```java
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class HelloSidestep {
  public static void main(String[] args) {
    Map<String, String> properties = new ConcurrentHashMap<>();
    Set<String> keySet = properties.keySet();
  }
}
```

```plain
$ /usr/lib/jvm/java-8-oracle/bin/javac -source 1.7 -target 1.7 HelloCovariance.java 
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
$ /usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java HelloCovariance 
```

Hey look!  No crash.  This is not really the right fix, and you will be playing whack-a-mole with similar bugs in a large system. The correct and recommended fix is to use a bootstrap classpath.

```plain
$ /usr/lib/jvm/java-8-oracle/bin/javac -source 1.7 -target 1.7 HelloCovariance.java -bootclasspath /usr/lib/jvm/java-1.7.0-openjdk-amd64/jre/lib/rt.jar
$ /usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java HelloCovariance 
```

Now we get no warnings and no crash.

This is not a new problem, but it seems like there is still a lot of confusion around it.

Here are some useful resources to consider:

 * https://blogs.oracle.com/darcy/entry/how_to_cross_compile_for
 * http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/javac.html#crosscomp-example
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class HelloCovariance {
  public static void main(String[] args) {
    ConcurrentHashMap<String, String> properties = new ConcurrentHashMap<>();
    Set<String> keySet = properties.keySet();
  }
}

以上是关于java 线程“main”中的异常java.lang.NoSuchMethodError:java.util.concurrent.ConcurrentHashMap.keySet()Ljava / 的主要内容,如果未能解决你的问题,请参考以下文章

我的代码上的线程“main”java.util.NoSuchElementException 中的异常?

线程“main”中的 Java 异常 java.lang.StringIndexOutOfBoundsException 错误

如何修复运行时错误-线程“main”java.util.NoSuchElementException中的异常

HTTPClient 示例 - 线程“main”中的异常 java.lang.NoSuchFieldError: INSTANCE

线程“主”java.lang.ArrayIndexOutOfBoundsException 中的异常:Calculator.main 中的 0(Calculator.java:25)[重复]

为啥我在代码中的线程“main”java.lang.StringIndexOutOfBoundsException 错误中收到异常?