Android-приложение с неправильным JDK (?) Каким-то образом

Недавно я обновил свой Android-проект для Android Studio 3. Я хотел использовать функции языка Java 8, поэтому добавил build.gradle:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

Затем я запускаю свое приложение на устройстве Android 8.0.0. Во время выполнения я вижу

java.lang.NoSuchMethodError: No virtual method keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView; in class Ljava/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'java.util.concurrent.ConcurrentHashMap' appears in /system/framework/core-oj.jar)

Я понимаю, что это связано с тем, что подпись keySet() была изменена в Java 8 от возврата Set<K> к возврату KeySetView<K,V>.

Линия, вызвавшая это исключение, выглядит следующим образом:

for (Long id : mSomeMap.keySet())

KeySetView реализует Set, это, безусловно, Iterable, поэтому, будет ли эта строка интерпретироваться как Java 7 или Java 8, я бы подумал, что она будет работать в любом случае. Мое понимание основ Java является отрывочным - что здесь происходит?

Обновление

Мое слабое понимание до сих пор таково:

Хотя Android теперь поддерживает некоторые функции языка Java 8, его API не идентичен Java 8. В частности, реализация Android ConcurrentHashMap.keySet() возвращает Set, а реализация Java 8 ConcurrentHashMap.keySet() возвращает KeySetView.

Как-то, Android Studio удалось скомпилировать мое приложение со стандартным Java 8 JDK, и поэтому во время выполнения ожидается найти метод с сигнатурой KeySetView<K,V> keySet(). Тем не менее, Android ConcurrentHashMap не имеет метода с этой сигнатурой, поэтому я получаю NoSuchMethodError.

Я не ближе к разработке того, как и почему Android Studio работает с несовместимым JDK. В структуре проекта проверяется флажок "Использовать встроенный JDK (рекомендуется)", поэтому я предполагаю, что Android Studio работает с JDK, входящим в комплект поставки.

Не решение

Большинство комментариев/ответов до сих пор указывали, что я могу просто объявить ConcurrentHashMap как Map, чтобы обойти это. Это обходное решение, а не решение. Если основная проблема заключается в том, что мое приложение создается с неправильным JDK, тогда могут быть и другие случаи, когда сигнатуры методов расходятся, и поскольку я не могу live test 100% путей кода в том, что является крупным проектом, я не могу гарантировать, что больше NoSuchMethodErrors не будет выбрано во время выполнения.

Ответы

Ответ 1

Я использую это обходное решение и, кажется, работает.

  private final Map<ImageView, Request> mPendingRequests =
            new ConcurrentHashMap<ImageView, Request>();

Ответ 2

Вы используете специальную реализацию ConcurrentHashMap

Объявление 'java.util.concurrent.ConcurrentHashMap' появляется в /system/framework/core -oj.jar

который не имеет метода keySet()

Ответ 3

вы можете объявить ConcurrentMap интерфейс:

ConcurrentMap mSomeMap = new ConcurrentHashMap();

затем используйте вот так:

for (Long id : mSomeMap.keySet())

Ответ 4

просто введите его в Map<?, ?>:

for (Long id : ((Map< Long, ?>)mSomeMap).keySet())