ConcurrentHashMap application compiled with JDK 8 but targeting JRE 7

Today I came across a very unexpected error, and while I was able to find a way to fix the problem as a whole, I'm not sure that I fully understand why she did what she did.

The code I'm working with was originally written using the JDK 7 JDK 7 environment. In the code I used ConcurrentHashMap and had to iterate over the keys on the map. For this, I used map.keySet() , which, according to JavaDocs, should have returned Set<K> . This worked fine until our build environment switched to JDK8.

When we switched to JDK8, I ensured that I would call the target / source for 1.7 when calling javac. Therefore, I was very surprised when the code started crashing when it wanted to iterate through the map keys. No error was selected, no exceptions, the thread just stopped. After some research, I found that the Java8 implementation for the ConcurrentHashMap the .keySet() method returns KeySetView<K,V> .

I fixed the problem by switching from using map.keySet() to getting Enumeration<K> using map.keys() .

Now I guess that although the project was compiled with Java7 targeting since JDK8 was used, the Java8 libraries were included, but why didn't it cause an error or exception when it got into a mismatch?

As the code snippet is set here:

 class MapProcessing { private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<String, Object>(); public MapProcessing() { map.put("First",new Object()); map.put("Second",new Object()); map.put("Third",new Object()); } public void processing() { // when calling this type of loop causes a freeze on our system. for(String key : map.keySet()) { System.out.println(key); } } public void working() { // This is what I had to do to fix the problem. Enumeration<String> keys = map.keys(); while(keys.hasMoreElements()) { String key = keys.nextElement(); System.out.println(key); } } } 

We compile using Oracle JDK 8 build 40, using target for 1.7 and source 1.7 in javac on a Windows 2012 server.

This code works using JVM 7 build 25 running on a Windows 2012 server.

+8
java iteration concurrenthashmap
source share
2 answers

If I compile your code with Java 8 and javac -source 1.7 -target 1.8, and then run it with Java 7, I will get

 Exception in thread "main" java.lang.NoSuchMethodError:
   java.util.concurrent.ConcurrentHashMap.keySet () Ljava / util / concurrent / ConcurrentHashMap $ KeySetView;
     at stackoverflowt.Test.processing (Test.java:20)
     at stackoverflowt.Test.main (Test.java:27)   

This is because the byte code looks like

 public void processing ();
     Code:
        0: aload_0       
        1: getfield # 4 // Field map: Ljava / util / concurrent / ConcurrentHashMap;
        4: invokevirtual # 10 // Method java / util / concurrent / ConcurrentHashMap.keySet :() Ljava / util / concurrent / ConcurrentHashMap $ KeySetView;
        7: invokevirtual # 11 // Method java / util / concurrent / ConcurrentHashMap $ KeySetView.iterator :() Ljava / util / Iterator;
       10: astore_1      

and explicitly reference ConcurrentHashMap $ KeySetView which is not in Java 7. I am on a Mac with Java 1.7.0_79 and 1.8.0_45

If you change the code to (use only the map interface):

 private Map<String, Object> map = new ConcurrentHashMap<String, Object>(); 

then it works for me. Then the bytecode looks like

 public void processing ();
     Code:
        0: aload_0       
        1: getfield # 4 // Field map: Ljava / util / Map;
        4: invokeinterface # 10, 1 // InterfaceMethod java / util / Map.keySet :() Ljava / util / Set;
        9: invokeinterface # 11, 1 // InterfaceMethod java / util / Set.iterator :() Ljava / util / Iterator;
       14: astore_1      
+12
source share

Whenever you create a project using the new JDK using the -source argument targeting the older version, you will get a warning from this compiler:

warning: [options] bootstrap class path not set in conjunction with -source 1.7

This blog post talks about what that means.

You basically get this warning because Java compiles it using the old language rules, but against the new class library ... and there are some compatibility issues with versions of Java 8 as Oracle moves some of the inner classes.

The fix is ​​to use the -bootclasspath argument to point it to rt.jar from the old version when compiling.

+2
source share

All Articles