Intereting Posts
Как преобразовать строки между прописными и строчными буквами в Java? Ошибка при создании нового проекта Maven в Eclipse Как загрузить файл с url с помощью Spring MVC? Сохранение сеанса Open in JUnit / JPA / Hibernate / Struts и тест интеграции Spring – нет сеанса или сеанса закрыты – исключение LazyInitialization получение соответствующего имени файла после нажатия кнопки Intellij Idea не показывает ошибок в окне инструмента сообщений после сборки Gradle Где сохранить фотографии на Android? Maven compile: пакета не существует окончательный переменный регистр в инструкции switch Java-streamи и синхронизированные блоки Шаблоны и советы по проверке бизнес-логики Есть ли обходной путь для низкой производительности Java при работе с огромными каталогами? Как JVM занимается дублированием JAR разных версий Parse.com: с помощью parseUser, как я могу сохранить данные в столбце, который я создал в синтаксическом анализе из classа? Согласованные результаты Equals (), но несогласованный результат TreeMap.containsKey ()

Как обнаружить неоднозначные вызовы методов, которые вызовут ClassCastException в Java 8?

Мы в настоящее время находимся в процессе переноса приложения с Java 7 на Java 8. После исправления некоторых проблем с компиляцией я наткнулся на проблему, похожую на следующий вопрос: ClassCast Error: Java 7 vs Java 8 .

Итак, вот пример кода, который показывает проблему:

public class Test { public static void main(String[] args) { System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception } @SuppressWarnings("unchecked") public static  T getVal(String param) { // do some computation based on param... return (T) result; // actual return type only depends on param so the caller knows what to expect } } 

Идея заключалась в том, что мы запустим, что вызывающий абонент знает ожидаемый тип, и это позволит избежать явного приведения ( я не говорю, что это была хорошая идея … ). Во многих случаях вызывающий абонент просто ожидает Object поэтому не было никакого скрытого приведения.

Как указано в вышеприведенном String.valueOf пример String.valueOf отлично работал на Java 7, потому что не было вывода типа, поэтому Object был принят. Теперь в Java 8 компилятор выбирает наиболее специфический тип (здесь char[] ), который вызывает ClastCastException во время выполнения.

Проблема в том, что у нас около 350 вызовов этого метода getVal . Есть ли способ обнаружить перегруженные вызовы методов, которые будут отличаться между Java 7 и Java 8? IE обнаруживает, когда компилятор Java 8 выберет другой метод из компилятора Java 7.

Лучшей альтернативой могло бы стать:

 public class Test { public static void main(String[] args) { System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception } @SuppressWarnings("unchecked") public static  T getVal(T param) { // do some computation based on param... return param; // actual return type only depends on param so the caller knows what to expect } } 

который будет работать как на Java 7, так и на Java 8.

В итоге решение было изменить getVal() чтобы вернуть Object :

  public static Object getVal(String param) { // do some computation based on param... return result; } 

и добавьте второй метод, который также принимает желаемый class в качестве параметра:

  public static  T getVal(String param, Class clazz) { return clazz.cast(getVal(param)); } 

затем исправить все проблемы компиляции (когда вызывающий Object не ожидал Object ), добавив соответствующий параметр classа.

Кроме того, было бы добавлено добавление роли, но это вызвало бы много предупреждений о безусловных переводах. Безусловный clazz самом деле по-прежнему существует (через параметр clazz ), но это позволяет легко идентифицировать всех вызывающих абонентов, которым требуется приведение, поскольку они используют метод с двумя параметрами.

Кроме того, и это очень специфично для этого случая – оказалось, что сам param часто являлся результатом вызова метода для некоторого TypedParam где T был ожидаемым типом возвращаемого значения getVal() и который также содержал class T.

Таким образом, я мог бы использовать дополнительный метод удобства:

  public static  T getVal(TypedParam param) { return getVal(param.stringValue(), param.getValueClass()); } 

и заменил все getVal(param.stringValue()) просто getVal(param) .

Это решение не разрешает общий случайобнаруживает перегруженные вызовы методов, которые будут отличаться между Java 7 и Java 8, но он разрешает его для методов, которые, как известно, вызывают эту проблему. И с тех пор мы не находили его в другом месте.