Ответ 1
Я использую это обходное решение и, кажется, работает.
private final Map<ImageView, Request> mPendingRequests =
new ConcurrentHashMap<ImageView, Request>();
Недавно я обновил свой 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
не будет выбрано во время выполнения.
Я использую это обходное решение и, кажется, работает.
private final Map<ImageView, Request> mPendingRequests =
new ConcurrentHashMap<ImageView, Request>();
Вы используете специальную реализацию ConcurrentHashMap
Объявление 'java.util.concurrent.ConcurrentHashMap' появляется в /system/framework/core -oj.jar
который не имеет метода keySet()
вы можете объявить ConcurrentMap
интерфейс:
ConcurrentMap mSomeMap = new ConcurrentHashMap();
затем используйте вот так:
for (Long id : mSomeMap.keySet())
просто введите его в Map<?, ?>
:
for (Long id : ((Map< Long, ?>)mSomeMap).keySet())