Как исправить исключение NullPointerException, вызванное проблемой синхронизации на DecimalFormat.format - PullRequest
0 голосов
/ 27 сентября 2019

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

Я просто не знаю, что может быть причиной этой проблемы, потому что я уверен, что BigDecimal не равен NULL, и я каждый раз создаю новый экземпляр DecimalFormat.Есть что-то, что я упустил?

Единственное, что я могу придумать, - это синхронизировать метод.Но я не уверен, что это поможет, и я бы предпочел не использовать его, так как это замедлит процесс.

Это один из сбоев:

java.lang.RuntimeException: 
  at java.lang.reflect.Constructor.newInstance0 (Constructor.java)
  at java.lang.reflect.Constructor.newInstance (Constructor.java:343)
  at androidx.loader.content.ModernAsyncTask$3.done (ModernAsyncTask.java:164)
  at java.util.concurrent.FutureTask.finishCompletion (FutureTask.java:383)
  at java.util.concurrent.FutureTask.setException (FutureTask.java:252)
  at java.util.concurrent.FutureTask.run (FutureTask.java:271)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
  at java.lang.Thread.run (Thread.java:764)
Caused by: java.lang.NullPointerException: 
  at java.math.BigInt.putLittleEndianInts (BigInt.java:175)
  at java.math.BigInteger.getBigInt (BigInteger.java:322)
  at java.math.BigInteger.toString (BigInteger.java:856)
  at java.math.BigDecimal.toString (BigDecimal.java:2204)
  at android.icu.text.DigitList_Android.set (DigitList_Android.java:724)
  at android.icu.text.DecimalFormat_ICU58_Android.format (DecimalFormat_ICU58_Android.java:1202)
  at android.icu.text.DecimalFormat_ICU58_Android.format (DecimalFormat_ICU58_Android.java:1187)
  at java.text.DecimalFormat.format (DecimalFormat.java:709)
  at java.text.DecimalFormat.format (DecimalFormat.java:634)
  at java.text.Format.format (Format.java:157)
  at com.myapp.formatter.Format.formatAmount (Format.java:230)
  at com.myapp.formatter.MyContentProvider.query (MyContentProvider.java:123)
  at android.content.ContentProvider.query (ContentProvider.java:1057)
  at android.content.ContentProvider.query (ContentProvider.java:1149)
  at android.content.ContentProvider$Transport.query (ContentProvider.java:241)
  at android.content.ContentResolver.query (ContentResolver.java:802)
  at android.content.ContentResolver.query (ContentResolver.java:752)
  at androidx.core.content.ContentResolverCompat.query (ContentResolverCompat.java:81)
  at androidx.loader.content.CursorLoader.loadInBackground (CursorLoader.java:63)
  at androidx.loader.content.CursorLoader.loadInBackground (CursorLoader.java:41)
  at androidx.loader.content.AsyncTaskLoader.onLoadInBackground (AsyncTaskLoader.java:307)
  at androidx.loader.content.AsyncTaskLoader$LoadTask.doInBackground$532ebdd5 (AsyncTaskLoader.java:60)
  at androidx.loader.content.AsyncTaskLoader$LoadTask.doInBackground$42af7916 (AsyncTaskLoader.java:48)
  at androidx.loader.content.ModernAsyncTask$2.call (ModernAsyncTask.java:141)
  at java.util.concurrent.FutureTask.run (FutureTask.java:266)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
  at java.lang.Thread.run (Thread.java:764)

И этокод:

public static String formatAmount(BigDecimal bigDecimal, boolean includeCents, boolean includeCurrency)
{
    String formattedAmount = "";
    if (bigDecimal != null)
    {
        DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(getLocale());
        DecimalFormat decimalFormat;
        if (includeCurrency)
        {
            decimalFormat = new DecimalFormat("¤\u00A0#,##0.00;¤\u00A0-#,##0.00", decimalFormatSymbols);
        }
        else
        {
            decimalFormat = new DecimalFormat("#,##0.00;-#,##0.00", decimalFormatSymbols);
        }

        int fractionDigits = includeCents ? 2 : 0;
        bigDecimal.setScale(fractionDigits, BigDecimal.ROUND_DOWN);

        decimalFormat.setMinimumFractionDigits(fractionDigits);
        decimalFormat.setMaximumFractionDigits(fractionDigits);

        // exception happens on next line.
        formattedAmount = decimalFormat.format(bigDecimal);
    }
    return formattedAmount;
}

Редактировать: Я не знаю, почему мой вопрос помечен как дубликат.Дело не в том, что я не знаю, что такое NullPointer или как его исправить.Прежде всего я уверен, что мои переменные и параметры не равны нулю.Отладка или ведение журнала не вариант, потому что я не могу воспроизвести эту проблему.И, наконец, NullPointer даже не вызван моим кодом.Так что я думаю, что это действительно уникальная ситуация, которую я не могу исправить самостоятельно.

Я также натолкнулся на код Android , на котором отображается нулевой указатель.И я думаю, что стоит упомянуть, что большинство сбоев происходит на устройствах Huawei.Еще одно отличие, которое я обнаружил, заключается в том, что для некоторых версий Android трассировка стека отличается.Первая трассировка стека была для устройств с Android 9. И это трассировка стека в более низких версиях Android (7, 8.0 и 8.1):

java.lang.RuntimeException: 
  at java.lang.reflect.Constructor.newInstance0 (Constructor.java)
  at java.lang.reflect.Constructor.newInstance (Constructor.java:334)
  at androidx.loader.content.ModernAsyncTask$3.done (ModernAsyncTask.java:164)
  at java.util.concurrent.FutureTask.finishCompletion (FutureTask.java:383)
  at java.util.concurrent.FutureTask.setException (FutureTask.java:252)
  at java.util.concurrent.FutureTask.run (FutureTask.java:271)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1162)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:636)
  at java.lang.Thread.run (Thread.java:784)
Caused by: java.lang.NullPointerException: 
  at java.math.BigInt.putLittleEndianInts (BigInt.java:173)
  at java.math.BigInteger.getBigInt (BigInteger.java:322)
  at java.math.BigInteger.toString (BigInteger.java:856)
  at java.math.BigDecimal.toString (BigDecimal.java:2204)
  at android.icu.text.DigitList.set (DigitList.java:721)
  at android.icu.text.DecimalFormat.format (DecimalFormat.java:1187)
  at android.icu.text.DecimalFormat.format (DecimalFormat.java:1172)
  at java.text.DecimalFormat.format (DecimalFormat.java:658)
  at java.text.DecimalFormat.format (DecimalFormat.java:592)
  at java.text.Format.format (Format.java:157)
  at com.myapp.formatter.Format.formatAmount (Format.java:230)
  at com.myapp.formatter.MyContentProvider.query (MyContentProvider.java:123)
  at android.content.ContentProvider.query (ContentProvider.java:1059)
  at android.content.ContentProvider.query (ContentProvider.java:1151)
  at android.content.ContentProvider$Transport.query (ContentProvider.java:243)
  at android.content.ContentResolver.query (ContentResolver.java:766)
  at android.content.ContentResolver.query (ContentResolver.java:716)
  at androidx.core.content.ContentResolverCompat.query (ContentResolverCompat.java:81)
  at androidx.loader.content.CursorLoader.loadInBackground (CursorLoader.java:63)
  at androidx.loader.content.CursorLoader.loadInBackground (CursorLoader.java:41)
  at androidx.loader.content.AsyncTaskLoader.onLoadInBackground (AsyncTaskLoader.java:307)
  at androidx.loader.content.AsyncTaskLoader$LoadTask.doInBackground$532ebdd5 (AsyncTaskLoader.java:60)
  at androidx.loader.content.AsyncTaskLoader$LoadTask.doInBackground$42af7916 (AsyncTaskLoader.java:48)
  at androidx.loader.content.ModernAsyncTask$2.call (ModernAsyncTask.java:141)
  at java.util.concurrent.FutureTask.run (FutureTask.java:266)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1162)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:636)
  at java.lang.Thread.run (Thread.java:784)
...