ошибка sonarqube в статической переменной календаря

#java #sonarqube

Вопрос:

У меня объявлена следующая переменная :

 private static Calendar calendar = Calendar.getInstance();
 

Я использую эту переменную «календарь» в статическом методе, как показано ниже :

 myStaticMethod(String reqDate){
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    Date some_date;
    long seconds = 0;
    int value = 10;
    try {
        some_date = df.parse(reqDate);
        calendar.setTime(some_date);
        calendar.add(Calendar.DATE, value);
        Date effValueDate = calendar.getTime();
        seconds = (effValueDate .getTime() - System.currentTimeMillis()) / 1000;
    } catch (ParseException e) {
        //---Do---something----
    }
}
 

Я получаю следующую ошибку гидролокатора :

 Make "calendar" an instance variable.
Not all classes in the standard Java library were written to be thread-safe. 
Using them in a multi-threaded manner is highly likely to cause data problems or exceptions at runtime.    
This rule raises an issue when an instance of Calendar, DateFormat, 
javax.xml.xpath.XPath, or javax.xml.validation.SchemaFactory is marked static.
 

Это мое решение, но я не уверен, что качество решения достаточно хорошее.

 myStaticMethod(String reqDate) {
    Calendar calendar = Calendar.getInstance();
    // the do the next processing
}
 

Итак, как я могу исправить ошибку… могу ли я использовать локальную Calendar переменную в этом случае вместо переменной класса или есть какой-либо другой разумный способ решить эту проблему.

Комментарии:

1. Я не вижу ничего плохого в использовании локальной переменной календаря (за исключением того, что вам действительно следует заменить эти устаревшие классы на классы из пакета java.time). Объект календаря содержит информацию о дате, так почему же он должен быть статической переменной класса в первую очередь? В конце концов, ваша переменная даты является локальной, так почему переменная календаря должна отличаться?

2. Я рекомендую вам не использовать DateFormat , SimpleDateFormat , Date и Calendar . Все эти классы плохо спроектированы и давно устарели, первые два, в частности, печально известны своими проблемами. Вместо этого используйте LocalDate и другие классы из java.time, современный API даты и времени Java .

Ответ №1:

Предупреждение сонара вызвано тем, что calendar объект может быть обновлен из нескольких потоков. Либо, как вы сказали, вы можете объявить метод calendar локальным для метода.

ИЛИ 1) Создайте синхронизированный блок в своем коде. (лучше использовать местное calendar )

 Date effValueDate ;
synchronized(calendar) {
    calendar.setTime(some_date);
    calendar.add(Calendar.DATE, value);
    effValueDate = calendar.getTime();
}
 
  1. РЕКОМЕНДУЕТСЯ: Используйте новые классы API java для даты и времени ( java.time ).
 // or use DateTimeFormatter.ISO_LOCAL_DATE
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd");

LocalDateTime date = LocalDate.parse(reqDate, pattern).plusDays(value).atStartOfDay();
Duration duration= Duration.between(date, LocalDateTime.now());
long seconds = duration.getSeconds();           
 

Узнайте больше о новом API

Комментарии:

1. Спасибо за ваше предложение. Я использую рекомендуемый подход, поскольку нахожу его более значимым.

2.@Som при необходимости лучше использовать новый API вместо старого java.util.time.Date baeldung.com/migrating-to-java-8-date-time-api

Ответ №2:

java.время

Поскольку вы, похоже, приняли рекомендацию Гаутама М. использовать java.time, современный API даты и времени Java, я подумал, что в качестве дополнения я перепишу ваш метод с использованием java.time. Возможно, мне не нужно добавлять, что я полностью согласен с этой рекомендацией.

 public static void myStaticMethod(String reqDate) {
    int value = 10;
    try {
        LocalDate dateThen = LocalDate.parse(reqDate).plusDays(value);
        ZonedDateTime dateTimeThen = dateThen.atStartOfDay(ZoneId.systemDefault());
        long seconds = ChronoUnit.SECONDS.between(Instant.now(), dateTimeThen);
        System.out.println(seconds);
    } catch (DateTimeParseException dtpe) {
        //---Do---something----
        System.out.println(dtpe);
    }
}
 

Мне кажется, что это не только проще, но и более естественно для чтения, чем исходный код с использованием Calendar и других плохо разработанных классов из Java 1.0 и 1.1.

Я использую тот факт, что ваш формат строки-это формат ISO 8601 для даты, формат, который LocalDate анализируется по умолчанию, то есть без какого-либо явного форматирования.

Я попробовал этот звонок в своем часовом поясе (Европа/Копенгаген):

     myStaticMethod("2021-06-28");
 

Выход был:

587995

Ссылки