diff --git a/src/java.base/share/classes/java/text/CharacterIteratorFieldDelegate.java b/src/java.base/share/classes/java/text/CharacterIteratorFieldDelegate.java index 4d0788491ac..33b811e9ecd 100644 --- a/src/java.base/share/classes/java/text/CharacterIteratorFieldDelegate.java +++ b/src/java.base/share/classes/java/text/CharacterIteratorFieldDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ class CharacterIteratorFieldDelegate implements Format.FieldDelegate { } public void formatted(Format.Field attr, Object value, int start, int end, - StringBuffer buffer) { + Format.StringBuf buffer) { if (start != end) { if (start < size) { // Adjust attributes of existing runs @@ -93,7 +93,7 @@ class CharacterIteratorFieldDelegate implements Format.FieldDelegate { } public void formatted(int fieldID, Format.Field attr, Object value, - int start, int end, StringBuffer buffer) { + int start, int end, Format.StringBuf buffer) { formatted(attr, value, start, end, buffer); } diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index ccb6cc4a04f..cf951ebf81f 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -514,7 +514,13 @@ public class ChoiceFormat extends NumberFormat { @Override public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition status) { - return format((double)number, toAppendTo, status); + return format((double) number, StringBufFactory.of(toAppendTo), status).asStringBuffer(); + } + + @Override + StringBuf format(long number, StringBuf toAppendTo, + FieldPosition status) { + return format((double) number, toAppendTo, status); } /** @@ -531,6 +537,12 @@ public class ChoiceFormat extends NumberFormat { @Override public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition status) { + return format(number, StringBufFactory.of(toAppendTo), status).asStringBuffer(); + } + + @Override + StringBuf format(double number, StringBuf toAppendTo, + FieldPosition status) { // find the number int i; for (i = 0; i < choiceLimits.length; ++i) { diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 25fd9923b06..e3fc7632535 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -552,6 +552,35 @@ public final class CompactNumberFormat extends NumberFormat { && ((BigInteger) number).bitLength() < 64)) { return format(((Number) number).longValue(), toAppendTo, fieldPosition); + } else if (number instanceof BigDecimal) { + return format((BigDecimal) number, StringBufFactory.of(toAppendTo), fieldPosition).asStringBuffer(); + } else if (number instanceof BigInteger) { + return format((BigInteger) number, StringBufFactory.of(toAppendTo), fieldPosition).asStringBuffer(); + } else if (number instanceof Number) { + return format(((Number) number).doubleValue(), toAppendTo, fieldPosition); + } else { + throw new IllegalArgumentException("Cannot format " + + number.getClass().getName() + " as a number"); + } + } + + @Override + StringBuf format(Object number, + StringBuf toAppendTo, + FieldPosition fieldPosition) { + + if (number == null) { + throw new IllegalArgumentException("Cannot format null as a number"); + } + + if (number instanceof Long || number instanceof Integer + || number instanceof Short || number instanceof Byte + || number instanceof AtomicInteger + || number instanceof AtomicLong + || (number instanceof BigInteger + && ((BigInteger) number).bitLength() < 64)) { + return format(((Number) number).longValue(), toAppendTo, + fieldPosition); } else if (number instanceof BigDecimal) { return format((BigDecimal) number, toAppendTo, fieldPosition); } else if (number instanceof BigInteger) { @@ -560,7 +589,7 @@ public final class CompactNumberFormat extends NumberFormat { return format(((Number) number).doubleValue(), toAppendTo, fieldPosition); } else { throw new IllegalArgumentException("Cannot format " - + number.getClass().getName() + " as a number"); + + number.getClass().getName() + " as a number"); } } @@ -591,12 +620,21 @@ public final class CompactNumberFormat extends NumberFormat { public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) { + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + return format(number, StringBufFactory.of(result), fieldPosition.getFieldDelegate()).asStringBuffer(); + } + + @Override + StringBuf format(double number, StringBuf result, + FieldPosition fieldPosition) { + fieldPosition.setBeginIndex(0); fieldPosition.setEndIndex(0); return format(number, result, fieldPosition.getFieldDelegate()); } - private StringBuffer format(double number, StringBuffer result, + private StringBuf format(double number, StringBuf result, FieldDelegate delegate) { boolean nanOrInfinity = decimalFormat.handleNaN(number, result, delegate); @@ -681,12 +719,21 @@ public final class CompactNumberFormat extends NumberFormat { public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) { + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + return format(number, StringBufFactory.of(result), fieldPosition.getFieldDelegate()).asStringBuffer(); + } + + @Override + StringBuf format(long number, StringBuf result, + FieldPosition fieldPosition) { + fieldPosition.setBeginIndex(0); fieldPosition.setEndIndex(0); return format(number, result, fieldPosition.getFieldDelegate()); } - private StringBuffer format(long number, StringBuffer result, FieldDelegate delegate) { + private StringBuf format(long number, StringBuf result, FieldDelegate delegate) { boolean isNegative = (number < 0); if (isNegative) { number = -number; @@ -757,15 +804,15 @@ public final class CompactNumberFormat extends NumberFormat { * of the prefix and the suffix fields can be * obtained using {@link NumberFormat.Field#PREFIX} * and {@link NumberFormat.Field#SUFFIX} respectively. - * @return the {@code StringBuffer} passed in as {@code result} + * @return the {@code StringBuf} passed in as {@code result} * @throws ArithmeticException if rounding is needed with rounding * mode being set to {@code RoundingMode.UNNECESSARY} * @throws NullPointerException if any of the given parameter * is {@code null} * @see FieldPosition */ - private StringBuffer format(BigDecimal number, StringBuffer result, - FieldPosition fieldPosition) { + private StringBuf format(BigDecimal number, StringBuf result, + FieldPosition fieldPosition) { Objects.requireNonNull(number); fieldPosition.setBeginIndex(0); @@ -773,7 +820,7 @@ public final class CompactNumberFormat extends NumberFormat { return format(number, result, fieldPosition.getFieldDelegate()); } - private StringBuffer format(BigDecimal number, StringBuffer result, + private StringBuf format(BigDecimal number, StringBuf result, FieldDelegate delegate) { boolean isNegative = number.signum() == -1; @@ -843,15 +890,15 @@ public final class CompactNumberFormat extends NumberFormat { * prefix and the suffix fields can be obtained * using {@link NumberFormat.Field#PREFIX} and * {@link NumberFormat.Field#SUFFIX} respectively. - * @return the {@code StringBuffer} passed in as {@code result} + * @return the {@code StringBuf} passed in as {@code result} * @throws ArithmeticException if rounding is needed with rounding * mode being set to {@code RoundingMode.UNNECESSARY} * @throws NullPointerException if any of the given parameter * is {@code null} * @see FieldPosition */ - private StringBuffer format(BigInteger number, StringBuffer result, - FieldPosition fieldPosition) { + private StringBuf format(BigInteger number, StringBuf result, + FieldPosition fieldPosition) { Objects.requireNonNull(number); fieldPosition.setBeginIndex(0); @@ -859,7 +906,7 @@ public final class CompactNumberFormat extends NumberFormat { return format(number, result, fieldPosition.getFieldDelegate(), false); } - private StringBuffer format(BigInteger number, StringBuffer result, + private StringBuf format(BigInteger number, StringBuf result, FieldDelegate delegate, boolean formatLong) { boolean isNegative = number.signum() == -1; @@ -936,7 +983,7 @@ public final class CompactNumberFormat extends NumberFormat { * {@code NumberFormat.Field.SIGN} and * {@code NumberFormat.Field.PREFIX} fields */ - private void appendPrefix(StringBuffer result, String prefix, + private void appendPrefix(StringBuf result, String prefix, FieldDelegate delegate) { append(result, expandAffix(prefix), delegate, getFieldPositions(prefix, NumberFormat.Field.PREFIX)); @@ -952,7 +999,7 @@ public final class CompactNumberFormat extends NumberFormat { * {@code NumberFormat.Field.SIGN} and * {@code NumberFormat.Field.SUFFIX} fields */ - private void appendSuffix(StringBuffer result, String suffix, + private void appendSuffix(StringBuf result, String suffix, FieldDelegate delegate) { append(result, expandAffix(suffix), delegate, getFieldPositions(suffix, NumberFormat.Field.SUFFIX)); @@ -968,7 +1015,7 @@ public final class CompactNumberFormat extends NumberFormat { * @param positions a list of {@code FieldPosition} in the given * string */ - private void append(StringBuffer result, String string, + private void append(StringBuf result, String string, FieldDelegate delegate, List positions) { if (!string.isEmpty()) { int start = result.length(); @@ -1134,7 +1181,7 @@ public final class CompactNumberFormat extends NumberFormat { public AttributedCharacterIterator formatToCharacterIterator(Object obj) { CharacterIteratorFieldDelegate delegate = new CharacterIteratorFieldDelegate(); - StringBuffer sb = new StringBuffer(); + StringBuf sb = StringBufFactory.of(); if (obj instanceof Double || obj instanceof Float) { format(((Number) obj).doubleValue(), sb, delegate); diff --git a/src/java.base/share/classes/java/text/DateFormat.java b/src/java.base/share/classes/java/text/DateFormat.java index a67ba676836..e29b3f0509f 100644 --- a/src/java.base/share/classes/java/text/DateFormat.java +++ b/src/java.base/share/classes/java/text/DateFormat.java @@ -346,6 +346,19 @@ public abstract class DateFormat extends Format { throw new IllegalArgumentException("Cannot format given Object as a Date"); } + @Override + final StringBuf format(Object obj, StringBuf toAppendTo, + FieldPosition fieldPosition) { + if (obj instanceof Date) { + return format((Date) obj, toAppendTo, fieldPosition); + } else if (obj instanceof Number) { + return format(new Date(((Number) obj).longValue()), + toAppendTo, fieldPosition); + } else { + throw new IllegalArgumentException("Cannot format given Object as a Date"); + } + } + /** * Formats a {@link Date} into a date-time string. The formatted * string is appended to the given {@code StringBuffer}. @@ -371,6 +384,11 @@ public abstract class DateFormat extends Format { public abstract StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition); + StringBuf format(Date date, StringBuf toAppendTo, + FieldPosition fieldPosition) { + throw new UnsupportedOperationException("Subclasses should override this method"); + } + /** * Formats a {@link Date} into a date-time string. * @@ -379,8 +397,14 @@ public abstract class DateFormat extends Format { */ public final String format(Date date) { - return format(date, new StringBuffer(), - DontCareFieldPosition.INSTANCE).toString(); + if ("java.text".equals(getClass().getPackageName()) + && "java.text".equals(numberFormat.getClass().getPackageName())) { + return format(date, StringBufFactory.of(), + DontCareFieldPosition.INSTANCE).toString(); + } else { + return format(date, new StringBuffer(), + DontCareFieldPosition.INSTANCE).toString(); + } } /** diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 04acca1ceb5..cc8e9e8662c 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -556,9 +556,9 @@ public class DecimalFormat extends NumberFormat { ((BigInteger)number).bitLength () < 64)) { return format(((Number)number).longValue(), toAppendTo, pos); } else if (number instanceof BigDecimal) { - return format((BigDecimal)number, toAppendTo, pos); + return format((BigDecimal)number, StringBufFactory.of(toAppendTo), pos).asStringBuffer(); } else if (number instanceof BigInteger) { - return format((BigInteger)number, toAppendTo, pos); + return format((BigInteger)number, StringBufFactory.of(toAppendTo), pos).asStringBuffer(); } else if (number instanceof Number) { return format(((Number)number).doubleValue(), toAppendTo, pos); } else { @@ -566,6 +566,28 @@ public class DecimalFormat extends NumberFormat { } } + @Override + final StringBuf format(Object number, + StringBuf toAppendTo, + FieldPosition pos) { + if (number instanceof Long || number instanceof Integer || + number instanceof Short || number instanceof Byte || + number instanceof AtomicInteger || + number instanceof AtomicLong || + (number instanceof BigInteger && + ((BigInteger) number).bitLength() < 64)) { + return format(((Number) number).longValue(), toAppendTo, pos); + } else if (number instanceof BigDecimal) { + return format((BigDecimal) number, toAppendTo, pos); + } else if (number instanceof BigInteger) { + return format((BigInteger) number, toAppendTo, pos); + } else if (number instanceof Number) { + return format(((Number) number).doubleValue(), toAppendTo, pos); + } else { + throw new IllegalArgumentException("Cannot format given Object as a Number"); + } + } + /** * Formats a double to produce a string. * @param number The double to format @@ -588,6 +610,12 @@ public class DecimalFormat extends NumberFormat { @Override public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) { + return format(number, StringBufFactory.of(result), fieldPosition).asStringBuffer(); + } + + @Override + StringBuf format(double number, StringBuf result, + FieldPosition fieldPosition) { // If fieldPosition is a DontCareFieldPosition instance we can // try to go to fast-path code. boolean tryFastPath = false; @@ -619,8 +647,8 @@ public class DecimalFormat extends NumberFormat { * mode being set to RoundingMode.UNNECESSARY * @return The formatted number string */ - StringBuffer format(double number, StringBuffer result, - FieldDelegate delegate) { + StringBuf format(double number, StringBuf result, + FieldDelegate delegate) { boolean nanOrInfinity = handleNaN(number, result, delegate); if (nanOrInfinity) { @@ -666,7 +694,7 @@ public class DecimalFormat extends NumberFormat { * @param delegate notified of locations of sub fields * @return true, if number is a NaN; false otherwise */ - boolean handleNaN(double number, StringBuffer result, + boolean handleNaN(double number, StringBuf result, FieldDelegate delegate) { if (Double.isNaN(number) || (Double.isInfinite(number) && multiplier == 0)) { @@ -691,7 +719,7 @@ public class DecimalFormat extends NumberFormat { * @return true, if number is a {@code Double.NEGATIVE_INFINITY} or * {@code Double.POSITIVE_INFINITY}; false otherwise */ - boolean handleInfinity(double number, StringBuffer result, + boolean handleInfinity(double number, StringBuf result, FieldDelegate delegate, boolean isNegative) { if (Double.isInfinite(number)) { if (isNegative) { @@ -720,7 +748,7 @@ public class DecimalFormat extends NumberFormat { return false; } - StringBuffer doubleSubformat(double number, StringBuffer result, + StringBuf doubleSubformat(double number, StringBuf result, FieldDelegate delegate, boolean isNegative) { synchronized (digitList) { int maxIntDigits = super.getMaximumIntegerDigits(); @@ -761,6 +789,14 @@ public class DecimalFormat extends NumberFormat { fieldPosition.setBeginIndex(0); fieldPosition.setEndIndex(0); + return format(number, StringBufFactory.of(result), fieldPosition.getFieldDelegate()).asStringBuffer(); + } + + StringBuf format(long number, StringBuf result, + FieldPosition fieldPosition) { + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + return format(number, result, fieldPosition.getFieldDelegate()); } @@ -774,8 +810,8 @@ public class DecimalFormat extends NumberFormat { * mode being set to RoundingMode.UNNECESSARY * @see java.text.FieldPosition */ - StringBuffer format(long number, StringBuffer result, - FieldDelegate delegate) { + StringBuf format(long number, StringBuf result, + FieldDelegate delegate) { boolean isNegative = (number < 0); if (isNegative) { number = -number; @@ -849,8 +885,8 @@ public class DecimalFormat extends NumberFormat { * mode being set to RoundingMode.UNNECESSARY * @see java.text.FieldPosition */ - private StringBuffer format(BigDecimal number, StringBuffer result, - FieldPosition fieldPosition) { + private StringBuf format(BigDecimal number, StringBuf result, + FieldPosition fieldPosition) { fieldPosition.setBeginIndex(0); fieldPosition.setEndIndex(0); return format(number, result, fieldPosition.getFieldDelegate()); @@ -865,8 +901,8 @@ public class DecimalFormat extends NumberFormat { * mode being set to RoundingMode.UNNECESSARY * @return The formatted number string */ - StringBuffer format(BigDecimal number, StringBuffer result, - FieldDelegate delegate) { + StringBuf format(BigDecimal number, StringBuf result, + FieldDelegate delegate) { if (multiplier != 1) { number = number.multiply(getBigDecimalMultiplier()); } @@ -908,8 +944,8 @@ public class DecimalFormat extends NumberFormat { * mode being set to RoundingMode.UNNECESSARY * @see java.text.FieldPosition */ - private StringBuffer format(BigInteger number, StringBuffer result, - FieldPosition fieldPosition) { + private StringBuf format(BigInteger number, StringBuf result, + FieldPosition fieldPosition) { fieldPosition.setBeginIndex(0); fieldPosition.setEndIndex(0); @@ -926,8 +962,8 @@ public class DecimalFormat extends NumberFormat { * mode being set to RoundingMode.UNNECESSARY * @see java.text.FieldPosition */ - StringBuffer format(BigInteger number, StringBuffer result, - FieldDelegate delegate, boolean formatLong) { + StringBuf format(BigInteger number, StringBuf result, + FieldDelegate delegate, boolean formatLong) { if (multiplier != 1) { number = number.multiply(getBigIntegerMultiplier()); } @@ -986,7 +1022,7 @@ public class DecimalFormat extends NumberFormat { public AttributedCharacterIterator formatToCharacterIterator(Object obj) { CharacterIteratorFieldDelegate delegate = new CharacterIteratorFieldDelegate(); - StringBuffer sb = new StringBuffer(); + StringBuf sb = StringBufFactory.of(); if (obj instanceof Double || obj instanceof Float) { format(((Number)obj).doubleValue(), sb, delegate); @@ -1779,7 +1815,7 @@ public class DecimalFormat extends NumberFormat { * Complete the formatting of a finite number. On entry, the digitList must * be filled in with the correct digits. */ - private StringBuffer subformat(StringBuffer result, FieldDelegate delegate, + private StringBuf subformat(StringBuf result, FieldDelegate delegate, boolean isNegative, boolean isInteger, int maxIntDigits, int minIntDigits, int maxFraDigits, int minFraDigits) { @@ -1821,7 +1857,7 @@ public class DecimalFormat extends NumberFormat { * @param maxFraDigits maximum fraction digits * @param minFraDigits minimum fraction digits */ - void subformatNumber(StringBuffer result, FieldDelegate delegate, + void subformatNumber(StringBuf result, FieldDelegate delegate, boolean isNegative, boolean isInteger, int maxIntDigits, int minIntDigits, int maxFraDigits, int minFraDigits) { @@ -2108,7 +2144,7 @@ public class DecimalFormat extends NumberFormat { *

* This is used by {@code subformat} to add the prefix/suffix. */ - private void append(StringBuffer result, String string, + private void append(StringBuf result, String string, FieldDelegate delegate, FieldPosition[] positions, Format.Field signAttribute) { diff --git a/src/java.base/share/classes/java/text/DontCareFieldPosition.java b/src/java.base/share/classes/java/text/DontCareFieldPosition.java index 33c086d370b..3117c67e786 100644 --- a/src/java.base/share/classes/java/text/DontCareFieldPosition.java +++ b/src/java.base/share/classes/java/text/DontCareFieldPosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,10 +36,10 @@ class DontCareFieldPosition extends FieldPosition { private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() { public void formatted(Format.Field attr, Object value, int start, - int end, StringBuffer buffer) { + int end, Format.StringBuf buffer) { } public void formatted(int fieldID, Format.Field attr, Object value, - int start, int end, StringBuffer buffer) { + int start, int end, Format.StringBuf buffer) { } }; diff --git a/src/java.base/share/classes/java/text/FieldPosition.java b/src/java.base/share/classes/java/text/FieldPosition.java index 7b9d23bafcb..92d0e9a2e6d 100644 --- a/src/java.base/share/classes/java/text/FieldPosition.java +++ b/src/java.base/share/classes/java/text/FieldPosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -290,7 +290,7 @@ public class FieldPosition { private boolean encounteredField; public void formatted(Format.Field attr, Object value, int start, - int end, StringBuffer buffer) { + int end, Format.StringBuf buffer) { if (!encounteredField && matchesField(attr)) { setBeginIndex(start); setEndIndex(end); @@ -299,7 +299,7 @@ public class FieldPosition { } public void formatted(int fieldID, Format.Field attr, Object value, - int start, int end, StringBuffer buffer) { + int start, int end, Format.StringBuf buffer) { if (!encounteredField && matchesField(attr, fieldID)) { setBeginIndex(start); setEndIndex(end); diff --git a/src/java.base/share/classes/java/text/Format.java b/src/java.base/share/classes/java/text/Format.java index 81efc27acf4..6aa6b866bae 100644 --- a/src/java.base/share/classes/java/text/Format.java +++ b/src/java.base/share/classes/java/text/Format.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,8 @@ public abstract class Format implements Serializable, Cloneable { } /** - * Formats an object to produce a string. This is equivalent to + * Formats an object to produce a string. + * This method returns a string that would be equal to the string returned by *

* {@link #format(Object, StringBuffer, FieldPosition) format}(obj, * new StringBuffer(), new FieldPosition(0)).toString(); @@ -160,7 +161,11 @@ public abstract class Format implements Serializable, Cloneable { * object */ public final String format (Object obj) { - return format(obj, new StringBuffer(), new FieldPosition(0)).toString(); + if ("java.text".equals(getClass().getPackageName())) { + return format(obj, StringBufFactory.of(), new FieldPosition(0)).toString(); + } else { + return format(obj, new StringBuffer(), new FieldPosition(0)).toString(); + } } /** @@ -185,6 +190,12 @@ public abstract class Format implements Serializable, Cloneable { StringBuffer toAppendTo, FieldPosition pos); + StringBuf format(Object obj, + StringBuf toAppendTo, + FieldPosition pos) { + throw new UnsupportedOperationException("Subclasses should override this method"); + } + /** * Formats an Object producing an {@code AttributedCharacterIterator}. * You can use the returned {@code AttributedCharacterIterator} @@ -394,7 +405,7 @@ public abstract class Format implements Serializable, Cloneable { * NOT modify it. */ public void formatted(Format.Field attr, Object value, int start, - int end, StringBuffer buffer); + int end, StringBuf buffer); /** * Notified when a particular region of the String is formatted. @@ -408,6 +419,38 @@ public abstract class Format implements Serializable, Cloneable { * NOT modify it. */ public void formatted(int fieldID, Format.Field attr, Object value, - int start, int end, StringBuffer buffer); + int start, int end, StringBuf buffer); + } + + /** + * StringBuf is the minimal common interface of {@code StringBuffer} and {@code StringBuilder}. + * It is used by the various {@code Format} implementations as the internal string buffer. + */ + sealed interface StringBuf + permits StringBufFactory.StringBufferImpl, StringBufFactory.StringBuilderImpl { + + int length(); + + String substring(int start, int end); + + String substring(int start); + + StringBuf append(char c); + + StringBuf append(String str); + + StringBuf append(int i); + + StringBuf append(char[] str, int offset, int len); + + StringBuf append(CharSequence s, int start, int end); + + StringBuf append(StringBuffer sb); + + boolean isProxyStringBuilder(); + + StringBuffer asStringBuffer(); + + StringBuilder asStringBuilder(); } } diff --git a/src/java.base/share/classes/java/text/ListFormat.java b/src/java.base/share/classes/java/text/ListFormat.java index bc155605934..5cd0e9e3651 100644 --- a/src/java.base/share/classes/java/text/ListFormat.java +++ b/src/java.base/share/classes/java/text/ListFormat.java @@ -356,7 +356,7 @@ public final class ListFormat extends Format { public String format(List input) { Objects.requireNonNull(input); - return format(input, new StringBuffer(), + return format(input, StringBufFactory.of(), DontCareFieldPosition.INSTANCE).toString(); } @@ -381,6 +381,18 @@ public final class ListFormat extends Format { Objects.requireNonNull(obj); Objects.requireNonNull(toAppendTo); + return format(obj, StringBufFactory.of(toAppendTo)).asStringBuffer(); + } + + @Override + StringBuf format(Object obj, StringBuf toAppendTo, FieldPosition pos) { + Objects.requireNonNull(obj); + Objects.requireNonNull(toAppendTo); + + return format(obj, toAppendTo); + } + + private StringBuf format(Object obj, StringBuf toAppendTo) { if (obj instanceof Object[] objs) { return generateMessageFormat(objs).format(objs, toAppendTo, DontCareFieldPosition.INSTANCE); } else if (obj instanceof List objs) { diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index 8f939f8af26..74a3e627c18 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -1027,12 +1027,13 @@ public class MessageFormat extends Format { public final StringBuffer format(Object[] arguments, StringBuffer result, FieldPosition pos) { - return subformat(arguments, result, pos, null); + return subformat(arguments, StringBufFactory.of(result), pos, null).asStringBuffer(); } /** * Creates a MessageFormat with the given pattern and uses it - * to format the given arguments. This is equivalent to + * to format the given arguments. + * This method returns a string that would be equal to the string returned by *
* (new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString() *
@@ -1076,6 +1077,12 @@ public class MessageFormat extends Format { public final StringBuffer format(Object arguments, StringBuffer result, FieldPosition pos) { + return subformat((Object[]) arguments, StringBufFactory.of(result), pos, null).asStringBuffer(); + } + + @Override + final StringBuf format(Object arguments, StringBuf result, + FieldPosition pos) { return subformat((Object[]) arguments, result, pos, null); } @@ -1116,7 +1123,7 @@ public class MessageFormat extends Format { */ public AttributedCharacterIterator formatToCharacterIterator(Object arguments) { Objects.requireNonNull(arguments, "arguments must not be null"); - StringBuffer result = new StringBuffer(); + StringBuf result = StringBufFactory.of(); ArrayList iterators = new ArrayList<>(); subformat((Object[]) arguments, result, null, iterators); @@ -1472,7 +1479,7 @@ public class MessageFormat extends Format { * {@code arguments} array is not of the type * expected by the format element(s) that use it. */ - private StringBuffer subformat(Object[] arguments, StringBuffer result, + private StringBuf subformat(Object[] arguments, StringBuf result, FieldPosition fp, List characterIterators) { // note: this implementation assumes a fast substring & index. // if this is not true, would be better to append chars one by one. @@ -1582,9 +1589,9 @@ public class MessageFormat extends Format { /** * Convenience method to append all the characters in - * {@code iterator} to the StringBuffer {@code result}. + * {@code iterator} to the StringBuf {@code result}. */ - private void append(StringBuffer result, CharacterIterator iterator) { + private void append(StringBuf result, CharacterIterator iterator) { if (iterator.first() != CharacterIterator.DONE) { char aChar; diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 28f116042e9..b905f3bd8af 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -315,6 +315,23 @@ public abstract class NumberFormat extends Format { } } + @Override + StringBuf format(Object number, + StringBuf toAppendTo, + FieldPosition pos) { + if (number instanceof Long || number instanceof Integer || + number instanceof Short || number instanceof Byte || + number instanceof AtomicInteger || number instanceof AtomicLong || + (number instanceof BigInteger && + ((BigInteger) number).bitLength() < 64)) { + return format(((Number) number).longValue(), toAppendTo, pos); + } else if (number instanceof Number) { + return format(((Number) number).doubleValue(), toAppendTo, pos); + } else { + throw new IllegalArgumentException("Cannot format given Object as a Number"); + } + } + /** * {@inheritDoc Format} * @@ -347,8 +364,13 @@ public abstract class NumberFormat extends Format { if (result != null) return result; - return format(number, new StringBuffer(), - DontCareFieldPosition.INSTANCE).toString(); + if ("java.text".equals(getClass().getPackageName())) { + return format(number, StringBufFactory.of(), + DontCareFieldPosition.INSTANCE).toString(); + } else { + return format(number, new StringBuffer(), + DontCareFieldPosition.INSTANCE).toString(); + } } /* @@ -367,8 +389,13 @@ public abstract class NumberFormat extends Format { * @see java.text.Format#format */ public final String format(long number) { - return format(number, new StringBuffer(), - DontCareFieldPosition.INSTANCE).toString(); + if ("java.text".equals(getClass().getPackageName())) { + return format(number, StringBufFactory.of(), + DontCareFieldPosition.INSTANCE).toString(); + } else { + return format(number, new StringBuffer(), + DontCareFieldPosition.INSTANCE).toString(); + } } /** @@ -394,6 +421,12 @@ public abstract class NumberFormat extends Format { StringBuffer toAppendTo, FieldPosition pos); + StringBuf format(double number, + StringBuf toAppendTo, + FieldPosition pos) { + throw new UnsupportedOperationException("Subclasses should override this method"); + } + /** * Specialization of format. * @@ -417,6 +450,12 @@ public abstract class NumberFormat extends Format { StringBuffer toAppendTo, FieldPosition pos); + StringBuf format(long number, + StringBuf toAppendTo, + FieldPosition pos) { + throw new UnsupportedOperationException("Subclasses should override this method"); + } + /** * Parses text from the beginning of the given string to produce a {@code Number}. *

diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index dbc7235cbc4..9f2513eb4b8 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -968,11 +968,18 @@ public class SimpleDateFormat extends DateFormat { FieldPosition pos) { pos.beginIndex = pos.endIndex = 0; + return format(date, StringBufFactory.of(toAppendTo), pos.getFieldDelegate()).asStringBuffer(); + } + + @Override + final StringBuf format(Date date, StringBuf toAppendTo, + FieldPosition pos) { + pos.beginIndex = pos.endIndex = 0; return format(date, toAppendTo, pos.getFieldDelegate()); } // Called from Format after creating a FieldDelegate - private StringBuffer format(Date date, StringBuffer toAppendTo, + private StringBuf format(Date date, StringBuf toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); @@ -1024,7 +1031,7 @@ public class SimpleDateFormat extends DateFormat { */ @Override public AttributedCharacterIterator formatToCharacterIterator(Object obj) { - StringBuffer sb = new StringBuffer(); + StringBuf sb = StringBufFactory.of(); CharacterIteratorFieldDelegate delegate = new CharacterIteratorFieldDelegate(); @@ -1130,7 +1137,7 @@ public class SimpleDateFormat extends DateFormat { * Private member function that does the real date/time formatting. */ private void subFormat(int patternCharIndex, int count, - FieldDelegate delegate, StringBuffer buffer, + FieldDelegate delegate, StringBuf buffer, boolean useDateFormatSymbols) { int maxIntCount = Integer.MAX_VALUE; @@ -1320,7 +1327,11 @@ public class SimpleDateFormat extends DateFormat { } int num = (value / 60) * 100 + (value % 60); - CalendarUtils.sprintf0d(buffer, num, width); + if (buffer.isProxyStringBuilder()) { + CalendarUtils.sprintf0d(buffer.asStringBuilder(), num, width); + } else { + CalendarUtils.sprintf0d(buffer.asStringBuffer(), num, width); + } break; case PATTERN_ISO_ZONE: // 'X' @@ -1340,7 +1351,11 @@ public class SimpleDateFormat extends DateFormat { value = -value; } - CalendarUtils.sprintf0d(buffer, value / 60, 2); + if (buffer.isProxyStringBuilder()) { + CalendarUtils.sprintf0d(buffer.asStringBuilder(), value / 60, 2); + } else { + CalendarUtils.sprintf0d(buffer.asStringBuffer(), value / 60, 2); + } if (count == 1) { break; } @@ -1348,7 +1363,11 @@ public class SimpleDateFormat extends DateFormat { if (count == 3) { buffer.append(':'); } - CalendarUtils.sprintf0d(buffer, value % 60, 2); + if (buffer.isProxyStringBuilder()) { + CalendarUtils.sprintf0d(buffer.asStringBuilder(), value % 60, 2); + } else { + CalendarUtils.sprintf0d(buffer.asStringBuffer(), value % 60, 2); + } break; default: @@ -1382,7 +1401,7 @@ public class SimpleDateFormat extends DateFormat { /** * Formats a number with the specified minimum and maximum number of digits. */ - private void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer) + private void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuf buffer) { // Optimization for 1, 2 and 4 digit numbers. This should // cover most cases of formatting date/time related items. @@ -1425,7 +1444,17 @@ public class SimpleDateFormat extends DateFormat { numberFormat.setMinimumIntegerDigits(minDigits); numberFormat.setMaximumIntegerDigits(maxDigits); - numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE); + if (buffer.isProxyStringBuilder()) { + //User can set numberFormat with a user-defined NumberFormat which + //not override format(long, StringBuf, FieldPosition). + if ("java.text".equals(numberFormat.getClass().getPackageName())) { + numberFormat.format((long) value, buffer, DontCareFieldPosition.INSTANCE); + } else { + buffer.append(numberFormat.format((long) value, new StringBuffer(), DontCareFieldPosition.INSTANCE)); + } + } else { + numberFormat.format((long) value, buffer.asStringBuffer(), DontCareFieldPosition.INSTANCE); + } } @@ -2565,5 +2594,4 @@ public class SimpleDateFormat extends DateFormat { originalNumberFormat = numberFormat; } } - } diff --git a/src/java.base/share/classes/java/text/StringBufFactory.java b/src/java.base/share/classes/java/text/StringBufFactory.java new file mode 100644 index 00000000000..bfad0c1093d --- /dev/null +++ b/src/java.base/share/classes/java/text/StringBufFactory.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.text; + +import java.text.Format.StringBuf; + +/** + * {@code StringBufFactory} creates implementations of {@code Format.StringBuf}, + * which is an interface with the minimum overlap required to support {@code StringBuffer} + * and {@code StringBuilder} in {@code Format}. This allows for {@code StringBuilder} to be used + * in place of {@code StringBuffer} to provide performance benefits for JDK internal + * {@code Format} subclasses. + */ +final class StringBufFactory { + + private StringBufFactory() { + } + + static StringBuf of(StringBuffer sb) { + return new StringBufferImpl(sb); + } + + static StringBuf of(StringBuilder sb) { + return new StringBuilderImpl(sb); + } + + static StringBuf of() { + return new StringBuilderImpl(); + } + + final static class StringBufferImpl implements StringBuf { + private final StringBuffer sb; + + StringBufferImpl(StringBuffer sb) { + this.sb = sb; + } + + @Override + public int length() { + return sb.length(); + } + + @Override + public String substring(int start, int end) { + return sb.substring(start, end); + } + + @Override + public String substring(int start) { + return sb.substring(start); + } + + @Override + public StringBuf append(char c) { + sb.append(c); + return this; + } + + @Override + public StringBuf append(String str) { + sb.append(str); + return this; + } + + @Override + public StringBuf append(int i) { + sb.append(i); + return this; + } + + @Override + public StringBuf append(char[] str, int offset, int len) { + sb.append(str, offset, len); + return this; + } + + @Override + public StringBuf append(CharSequence s, int start, int end) { + sb.append(s, start, end); + return this; + } + + @Override + public StringBuf append(StringBuffer asb) { + sb.append(asb); + return this; + } + + @Override + public boolean isProxyStringBuilder() { + return false; + } + + @Override + public StringBuffer asStringBuffer() { + return sb; + } + + @Override + public StringBuilder asStringBuilder() { + throw new AssertionError("Can't cast StringBuffer to StringBuilder"); + } + + @Override + public String toString() { + return sb.toString(); + } + } + + final static class StringBuilderImpl implements StringBuf { + private final StringBuilder sb; + + StringBuilderImpl(StringBuilder sb) { + this.sb = sb; + } + + StringBuilderImpl() { + this.sb = new StringBuilder(); + } + + @Override + public int length() { + return sb.length(); + } + + @Override + public String substring(int start, int end) { + return sb.substring(start, end); + } + + @Override + public String substring(int start) { + return sb.substring(start); + } + + @Override + public StringBuf append(char c) { + sb.append(c); + return this; + } + + @Override + public StringBuf append(String str) { + sb.append(str); + return this; + } + + @Override + public StringBuf append(int i) { + sb.append(i); + return this; + } + + @Override + public StringBuf append(char[] str, int offset, int len) { + sb.append(str, offset, len); + return this; + } + + @Override + public StringBuf append(CharSequence s, int start, int end) { + sb.append(s, start, end); + return this; + } + + @Override + public StringBuf append(StringBuffer asb) { + sb.append(asb); + return this; + } + + + @Override + public boolean isProxyStringBuilder() { + return true; + } + + @Override + public StringBuffer asStringBuffer() { + throw new AssertionError("Can't cast StringBuilder to StringBuffer"); + } + + @Override + public StringBuilder asStringBuilder() { + return sb; + } + + @Override + public String toString() { + return sb.toString(); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/text/DateFormatterBench.java b/test/micro/org/openjdk/bench/java/text/DateFormatterBench.java new file mode 100644 index 00000000000..f9a6340a0fb --- /dev/null +++ b/test/micro/org/openjdk/bench/java/text/DateFormatterBench.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.text; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +@State(Scope.Benchmark) +public class DateFormatterBench { + + private Date date; + + private Object objDate; + + @Setup + public void setup() { + date = new Date(); + objDate = new Date(); + } + + private DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL, Locale.ENGLISH); + + @Benchmark + public String testFormatDate() { + return dateFormat.format(date); + } + + @Benchmark + public String testFormatObject() { + return dateFormat.format(objDate); + } + + public static void main(String... args) throws Exception { + Options opts = new OptionsBuilder().include(DateFormatterBench.class.getSimpleName()).shouldDoGC(true).build(); + new Runner(opts).run(); + } +} diff --git a/test/micro/org/openjdk/bench/java/text/ListFormatterBench.java b/test/micro/org/openjdk/bench/java/text/ListFormatterBench.java new file mode 100644 index 00000000000..008f4b17148 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/text/ListFormatterBench.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.text; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.text.ListFormat; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +@State(Scope.Benchmark) +public class ListFormatterBench { + + private List data; + + @Setup + public void setup() { + data = List.of("foo", "bar", "baz", "qux", "quux", "quuz"); + } + + private ListFormat listFormat = ListFormat.getInstance(); + + @Benchmark + public String testListFormat() { + return listFormat.format(data); + } + + public static void main(String... args) throws Exception { + Options opts = new OptionsBuilder().include(ListFormatterBench.class.getSimpleName()).shouldDoGC(true).build(); + new Runner(opts).run(); + } +} diff --git a/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java b/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java new file mode 100644 index 00000000000..5d3399cb46d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.text; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +@State(Scope.Benchmark) +public class MessageFormatterBench { + + private Object[][] values; + + @Setup + public void setup() { + values = new Object[][]{ + new Object[]{Integer.valueOf(13), "MyDisk1"}, + new Object[]{Float.valueOf(25.6f), "MyDisk2"}, + new Object[]{Double.valueOf(123.89), "MyDisk3"}, + new Object[]{Long.valueOf(1234567), "MyDisk4"}, + }; + } + + private MessageFormat messageFormat = new MessageFormat("There is {0} GB of free space on the {1}.", Locale.ENGLISH); + + @Benchmark + @OperationsPerInvocation(4) + public void testMessageFormat(final Blackhole bh) { + for (Object[] value : values) { + bh.consume(messageFormat.format(value)); + } + } + + public static void main(String... args) throws Exception { + Options opts = new OptionsBuilder().include(MessageFormatterBench.class.getSimpleName()).shouldDoGC(true).build(); + new Runner(opts).run(); + } +}