提问人:Wirling 提问时间:9/27/2019 最后编辑:Wirling 更新时间:9/28/2019 访问量:341
如何修复由 DecimalFormat.format 上的同步问题导致的 NullPointerException
How to fix NullPointerException caused by synchronization issue on DecimalFormat.format
问:
我正在使用 DecimalFormat 类格式化 BigDecimal,但我有很多崩溃报告。我自己无法重现这个问题,但是我知道 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或如何修复它。 首先,我确定我的变量和参数不是 null。 调试或日志记录不是一个选项,因为我无法重现此问题。 最后,NullPointer 甚至不是由我的代码引起的。 所以我认为这真的是一个我无法解决的独特情况。
我还遇到了引发 nullpointer 的 Android 代码。我认为值得一提的是,大多数崩溃都发生在华为设备上。我发现的另一个区别是,某些 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)
答: 暂无答案
评论
decimalFormat
putLittleEndianInts
内部,这只有在数组参数为 时才有可能,该参数来自包装的BigInteger.digits
,即 。BigDecimal
null
transient