DoubleFormat.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.text.numbers;
- import java.text.DecimalFormatSymbols;
- import java.util.Objects;
- import java.util.function.DoubleFunction;
- import java.util.function.Function;
- import java.util.function.Supplier;
- /**
- * Enum containing standard double format types with methods to produce
- * configured formatter instances. This type is intended to provide a
- * quick and convenient way to create lightweight, thread-safe double format functions
- * for common format types using a builder pattern. Output can be localized by
- * passing a {@link DecimalFormatSymbols} instance to the
- * {@link Builder#formatSymbols(DecimalFormatSymbols) formatSymbols} method or by
- * directly calling the various other builder configuration methods, such as
- * {@link Builder#digits(String) digits}.
- *
- * <p><strong>Comparison with DecimalFormat</strong></p>
- * <p>
- * This type provides some of the same functionality as Java's own
- * {@link java.text.DecimalFormat}. However, unlike {@code DecimalFormat}, the format
- * functions produced by this type are lightweight and thread-safe, making them
- * much easier to work with in multi-threaded environments. They also provide performance
- * comparable to, and in many cases faster than, {@code DecimalFormat}.
- * </p>
- * <p>
- * It should be noted that the output {@code String} is created by formatting the output of
- * {@link Double#toString()}. This limits the output precision to the precision required
- * to exactly represent the input {@code double} and is dependent on the JDK implementation
- * of {@link Double#toString()}. A number formatted with the maximum
- * precision should be parsed to the same input {@code double}. This implementation
- * cannot extend the {@code String} to the required length to represent the exact decimal
- * value of the {@code double} as per
- * {@link java.math.BigDecimal#toString() BigDecimal#toString()}.
- * </p>
- * <p><strong>Examples</strong></p>
- * <pre>
- * // construct a formatter equivalent to Double.toString()
- * DoubleFunction<String> fmt = DoubleFormat.MIXED.builder().build();
- *
- * // construct a formatter equivalent to Double.toString() but using
- * // format symbols for a specific locale
- * DoubleFunction<String> fmt = DoubleFormat.MIXED.builder()
- * .formatSymbols(DecimalFormatSymbols.getInstance(locale))
- * .build();
- *
- * // construct a formatter equivalent to the DecimalFormat pattern "0.0##"
- * DoubleFunction<String> fmt = DoubleFormat.PLAIN.builder()
- * .minDecimalExponent(-3)
- * .build();
- *
- * // construct a formatter equivalent to the DecimalFormat pattern "#,##0.0##",
- * // where whole number groups of thousands are separated
- * DoubleFunction<String> fmt = DoubleFormat.PLAIN.builder()
- * .minDecimalExponent(-3)
- * .groupThousands(true)
- * .build();
- *
- * // construct a formatter equivalent to the DecimalFormat pattern "0.0##E0"
- * DoubleFunction<String> fmt = DoubleFormat.SCIENTIFIC.builder()
- * .maxPrecision(4)
- * .alwaysIncludeExponent(true)
- * .build()
- *
- * // construct a formatter equivalent to the DecimalFormat pattern "##0.0##E0",
- * // i.e. "engineering format"
- * DoubleFunction<String> fmt = DoubleFormat.ENGINEERING.builder()
- * .maxPrecision(6)
- * .alwaysIncludeExponent(true)
- * .build()
- * </pre>
- *
- * <p><strong>Implementation Notes</strong></p>
- * <p>
- * {@link java.math.RoundingMode#HALF_EVEN Half-even} rounding is used in cases where the
- * decimal value must be rounded in order to meet the configuration requirements of the formatter
- * instance.
- * </p>
- *
- * @since 1.10.0
- */
- public enum DoubleFormat {
- /**
- * Number format without exponents.
- * <p>
- * For example:
- * </p>
- *
- * <pre>
- * 0.0
- * 12.401
- * 100000.0
- * 1450000000.0
- * 0.0000000000123
- * </pre>
- */
- PLAIN(PlainDoubleFormat::new),
- /**
- * Number format that uses exponents and contains a single digit to the left of the decimal point.
- * <p>
- * For example:
- * </p>
- *
- * <pre>
- * 0.0
- * 1.2401E1
- * 1.0E5
- * 1.45E9
- * 1.23E-11
- * </pre>
- */
- SCIENTIFIC(ScientificDoubleFormat::new),
- /**
- * Number format similar to {@link #SCIENTIFIC scientific format} but adjusted so that the exponent value is always a multiple of 3, allowing easier
- * alignment with SI prefixes.
- * <p>
- * For example:
- * </p>
- *
- * <pre>
- * 0.0
- * 12.401
- * 100.0E3
- * 1.45E9
- * 12.3E-12
- * </pre>
- */
- ENGINEERING(EngineeringDoubleFormat::new),
- /**
- * Number format that uses {@link #PLAIN plain format} for small numbers and {@link #SCIENTIFIC scientific format} for large numbers. The number thresholds
- * can be configured through the {@link Builder#plainFormatMinDecimalExponent(int) plainFormatMinDecimalExponent} and
- * {@link Builder#plainFormatMaxDecimalExponent(int) plainFormatMaxDecimalExponent} properties.
- * <p>
- * For example:
- * </p>
- *
- * <pre>
- * 0.0
- * 12.401
- * 100000.0
- * 1.45E9
- * 1.23E-11
- * </pre>
- */
- MIXED(MixedDoubleFormat::new);
- /**
- * Base class for standard double formatting classes.
- */
- private abstract static class AbstractDoubleFormat implements DoubleFunction<String>, ParsedDecimal.FormatOptions {
- /** Maximum precision; 0 indicates no limit. */
- private final int maxPrecision;
- /** Minimum decimal exponent. */
- private final int minDecimalExponent;
- /** String representing positive infinity. */
- private final String positiveInfinity;
- /** String representing negative infinity. */
- private final String negativeInfinity;
- /** String representing NaN. */
- private final String nan;
- /** Flag determining if fraction placeholders should be used. */
- private final boolean fractionPlaceholder;
- /** Flag determining if signed zero strings are allowed. */
- private final boolean signedZero;
- /** String containing the digits 0-9. */
- private final char[] digits;
- /** Decimal separator character. */
- private final char decimalSeparator;
- /** Thousands grouping separator. */
- private final char groupingSeparator;
- /** Flag indicating if thousands should be grouped. */
- private final boolean groupThousands;
- /** Minus sign character. */
- private final char minusSign;
- /** Exponent separator character. */
- private final char[] exponentSeparatorChars;
- /** Flag indicating if exponent values should always be included, even if zero. */
- private final boolean alwaysIncludeExponent;
- /**
- * Constructs a new instance.
- *
- * @param builder builder instance containing configuration values
- */
- AbstractDoubleFormat(final Builder builder) {
- this.maxPrecision = builder.maxPrecision;
- this.minDecimalExponent = builder.minDecimalExponent;
- this.positiveInfinity = builder.infinity;
- this.negativeInfinity = builder.minusSign + builder.infinity;
- this.nan = builder.nan;
- this.fractionPlaceholder = builder.fractionPlaceholder;
- this.signedZero = builder.signedZero;
- this.digits = builder.digits.toCharArray();
- this.decimalSeparator = builder.decimalSeparator;
- this.groupingSeparator = builder.groupingSeparator;
- this.groupThousands = builder.groupThousands;
- this.minusSign = builder.minusSign;
- this.exponentSeparatorChars = builder.exponentSeparator.toCharArray();
- this.alwaysIncludeExponent = builder.alwaysIncludeExponent;
- }
- /** {@inheritDoc} */
- @Override
- public String apply(final double d) {
- if (Double.isFinite(d)) {
- return applyFinite(d);
- }
- if (Double.isInfinite(d)) {
- return d > 0.0 ? positiveInfinity : negativeInfinity;
- }
- return nan;
- }
- /**
- * Returns a formatted string representation of the given finite value.
- *
- * @param d double value
- */
- private String applyFinite(final double d) {
- final ParsedDecimal n = ParsedDecimal.from(d);
- int roundExponent = Math.max(n.getExponent(), minDecimalExponent);
- if (maxPrecision > 0) {
- roundExponent = Math.max(n.getScientificExponent() - maxPrecision + 1, roundExponent);
- }
- n.round(roundExponent);
- return applyFiniteInternal(n);
- }
- /**
- * Returns a formatted representation of the given rounded decimal value to {@code dst}.
- *
- * @param val value to format
- * @return a formatted representation of the given rounded decimal value to {@code dst}.
- */
- protected abstract String applyFiniteInternal(ParsedDecimal val);
- /** {@inheritDoc} */
- @Override
- public char getDecimalSeparator() {
- return decimalSeparator;
- }
- /** {@inheritDoc} */
- @Override
- public char[] getDigits() {
- return digits;
- }
- /** {@inheritDoc} */
- @Override
- public char[] getExponentSeparatorChars() {
- return exponentSeparatorChars;
- }
- /** {@inheritDoc} */
- @Override
- public char getGroupingSeparator() {
- return groupingSeparator;
- }
- /** {@inheritDoc} */
- @Override
- public char getMinusSign() {
- return minusSign;
- }
- /** {@inheritDoc} */
- @Override
- public boolean isAlwaysIncludeExponent() {
- return alwaysIncludeExponent;
- }
- /** {@inheritDoc} */
- @Override
- public boolean isGroupThousands() {
- return groupThousands;
- }
- /** {@inheritDoc} */
- @Override
- public boolean isIncludeFractionPlaceholder() {
- return fractionPlaceholder;
- }
- /** {@inheritDoc} */
- @Override
- public boolean isSignedZero() {
- return signedZero;
- }
- }
- /**
- * Builds configured format functions for standard double format types.
- */
- public static final class Builder implements Supplier<DoubleFunction<String>> {
- /** Default value for the plain format max decimal exponent. */
- private static final int DEFAULT_PLAIN_FORMAT_MAX_DECIMAL_EXPONENT = 6;
- /** Default value for the plain format min decimal exponent. */
- private static final int DEFAULT_PLAIN_FORMAT_MIN_DECIMAL_EXPONENT = -3;
- /** Default decimal digit characters. */
- private static final String DEFAULT_DECIMAL_DIGITS = "0123456789";
- /**
- * Gets a string containing the localized digits 0-9 for the given symbols object. The string is constructed by starting at the
- * {@link DecimalFormatSymbols#getZeroDigit() zero digit} and adding the next 9 consecutive characters.
- *
- * @param symbols symbols object
- * @return string containing the localized digits 0-9
- */
- private static String getDigitString(final DecimalFormatSymbols symbols) {
- final int zeroDelta = symbols.getZeroDigit() - DEFAULT_DECIMAL_DIGITS.charAt(0);
- final char[] digitChars = new char[DEFAULT_DECIMAL_DIGITS.length()];
- for (int i = 0; i < DEFAULT_DECIMAL_DIGITS.length(); ++i) {
- digitChars[i] = (char) (DEFAULT_DECIMAL_DIGITS.charAt(i) + zeroDelta);
- }
- return String.valueOf(digitChars);
- }
- /** Function used to construct format instances. */
- private final Function<Builder, DoubleFunction<String>> factory;
- /** Maximum number of significant decimal digits in formatted strings. */
- private int maxPrecision;
- /** Minimum decimal exponent. */
- private int minDecimalExponent = Integer.MIN_VALUE;
- /** Max decimal exponent to use with plain formatting with the mixed format type. */
- private int plainFormatMaxDecimalExponent = DEFAULT_PLAIN_FORMAT_MAX_DECIMAL_EXPONENT;
- /** Min decimal exponent to use with plain formatting with the mixed format type. */
- private int plainFormatMinDecimalExponent = DEFAULT_PLAIN_FORMAT_MIN_DECIMAL_EXPONENT;
- /** String representing infinity. */
- private String infinity = "Infinity";
- /** String representing NaN. */
- private String nan = "NaN";
- /** Flag determining if fraction placeholders should be used. */
- private boolean fractionPlaceholder = true;
- /** Flag determining if signed zero strings are allowed. */
- private boolean signedZero = true;
- /** String of digit characters 0-9. */
- private String digits = DEFAULT_DECIMAL_DIGITS;
- /** Decimal separator character. */
- private char decimalSeparator = '.';
- /** Character used to separate groups of thousands. */
- private char groupingSeparator = ',';
- /** If {@code true}, thousands groups will be separated by the grouping separator. */
- private boolean groupThousands;
- /** Minus sign character. */
- private char minusSign = '-';
- /** Exponent separator character. */
- private String exponentSeparator = "E";
- /** Flag indicating if the exponent value should always be included, even if zero. */
- private boolean alwaysIncludeExponent;
- /**
- * Builds a new instance that delegates double function construction to the given factory object.
- *
- * @param factory factory function
- */
- private Builder(final Function<Builder, DoubleFunction<String>> factory) {
- this.factory = factory;
- }
- /**
- * Sets the flag determining whether or not the zero string may be returned with the minus sign or if it will always be returned in the positive form.
- * For example, if set to {@code true}, the string {@code "-0.0"} may be returned for some input numbers. If {@code false}, only {@code "0.0"} will be
- * returned, regardless of the sign of the input number. The default value is {@code true}.
- *
- * @param signedZero if {@code true}, the zero string may be returned with a preceding minus sign; if {@code false}, the zero string will only be
- * returned in its positive form
- * @return this instance
- */
- public Builder allowSignedZero(final boolean signedZero) {
- this.signedZero = signedZero;
- return this;
- }
- /**
- * Sets the flag indicating if an exponent value should always be included in the formatted value, even if the exponent value is zero. This property
- * only applies to formats that use scientific notation, namely {@link DoubleFormat#SCIENTIFIC SCIENTIFIC}, {@link DoubleFormat#ENGINEERING
- * ENGINEERING}, and {@link DoubleFormat#MIXED MIXED}. The default value is {@code false}.
- *
- * @param alwaysIncludeExponent if {@code true}, exponents will always be included in formatted output even if the exponent value is zero
- * @return this instance
- */
- public Builder alwaysIncludeExponent(final boolean alwaysIncludeExponent) {
- this.alwaysIncludeExponent = alwaysIncludeExponent;
- return this;
- }
- /**
- * Builds a new double format function.
- *
- * @return format function
- * @deprecated Use {@link #get()}.
- */
- @Deprecated
- public DoubleFunction<String> build() {
- return get();
- }
- /**
- * Sets the decimal separator character, i.e., the character placed between the whole number and fractional portions of the formatted strings. The
- * default value is {@code '.'}.
- *
- * @param decimalSeparator decimal separator character
- * @return this instance
- */
- public Builder decimalSeparator(final char decimalSeparator) {
- this.decimalSeparator = decimalSeparator;
- return this;
- }
- /**
- * Sets the string containing the digit characters 0-9, in that order. The default value is the string {@code "0123456789"}.
- *
- * @param digits string containing the digit characters 0-9
- * @return this instance
- * @throws NullPointerException if the argument is {@code null}
- * @throws IllegalArgumentException if the argument does not have a length of exactly 10
- */
- public Builder digits(final String digits) {
- Objects.requireNonNull(digits, "digits");
- if (digits.length() != DEFAULT_DECIMAL_DIGITS.length()) {
- throw new IllegalArgumentException("Digits string must contain exactly " + DEFAULT_DECIMAL_DIGITS.length() + " characters.");
- }
- this.digits = digits;
- return this;
- }
- /**
- * Sets the exponent separator character, i.e., the string placed between the mantissa and the exponent. The default value is {@code "E"}, as in
- * {@code "1.2E6"}.
- *
- * @param exponentSeparator exponent separator string
- * @return this instance
- * @throws NullPointerException if the argument is {@code null}
- */
- public Builder exponentSeparator(final String exponentSeparator) {
- this.exponentSeparator = Objects.requireNonNull(exponentSeparator, "exponentSeparator");
- return this;
- }
- /**
- * Configures this instance with the given format symbols. The following values are set:
- * <ul>
- * <li>{@link #digits(String) digit characters}</li>
- * <li>{@link #decimalSeparator(char) decimal separator}</li>
- * <li>{@link #groupingSeparator(char) thousands grouping separator}</li>
- * <li>{@link #minusSign(char) minus sign}</li>
- * <li>{@link #exponentSeparator(String) exponent separator}</li>
- * <li>{@link #infinity(String) infinity}</li>
- * <li>{@link #nan(String) NaN}</li>
- * </ul>
- * The digit character string is constructed by starting at the configured {@link DecimalFormatSymbols#getZeroDigit() zero digit} and adding the next 9
- * consecutive characters.
- *
- * @param symbols format symbols
- * @return this instance
- * @throws NullPointerException if the argument is {@code null}
- */
- public Builder formatSymbols(final DecimalFormatSymbols symbols) {
- Objects.requireNonNull(symbols, "symbols");
- return digits(getDigitString(symbols)).decimalSeparator(symbols.getDecimalSeparator()).groupingSeparator(symbols.getGroupingSeparator())
- .minusSign(symbols.getMinusSign()).exponentSeparator(symbols.getExponentSeparator()).infinity(symbols.getInfinity()).nan(symbols.getNaN());
- }
- /**
- * Builds a new double format function.
- *
- * @return format function
- */
- @Override
- public DoubleFunction<String> get() {
- return factory.apply(this);
- }
- /**
- * Sets the character used to separate groups of thousands. Default value is {@code ','}.
- *
- * @param groupingSeparator character used to separate groups of thousands
- * @return this instance
- * @see #groupThousands(boolean)
- */
- public Builder groupingSeparator(final char groupingSeparator) {
- this.groupingSeparator = groupingSeparator;
- return this;
- }
- /**
- * If set to {@code true}, thousands will be grouped with the {@link #groupingSeparator(char) grouping separator}. For example, if set to {@code true},
- * the number {@code 1000} could be formatted as {@code "1,000"}. This property only applies to the {@link DoubleFormat#PLAIN PLAIN} format. Default
- * value is {@code false}.
- *
- * @param groupThousands if {@code true}, thousands will be grouped
- * @return this instance
- * @see #groupingSeparator(char)
- */
- public Builder groupThousands(final boolean groupThousands) {
- this.groupThousands = groupThousands;
- return this;
- }
- /**
- * Sets the flag determining whether or not a zero character is added in the fraction position when no fractional value is present. For example, if set
- * to {@code true}, the number {@code 1} would be formatted as {@code "1.0"}. If {@code false}, it would be formatted as {@code "1"}. The default value
- * is {@code true}.
- *
- * @param fractionPlaceholder if {@code true}, a zero character is placed in the fraction position when no fractional value is present; if
- * {@code false}, fractional digits are only included when needed
- * @return this instance
- */
- public Builder includeFractionPlaceholder(final boolean fractionPlaceholder) {
- this.fractionPlaceholder = fractionPlaceholder;
- return this;
- }
- /**
- * Sets the string used to represent infinity. For negative infinity, this string is prefixed with the {@link #minusSign(char) minus sign}.
- *
- * @param infinity string used to represent infinity
- * @return this instance
- * @throws NullPointerException if the argument is {@code null}
- */
- public Builder infinity(final String infinity) {
- this.infinity = Objects.requireNonNull(infinity, "infinity");
- return this;
- }
- /**
- * Sets the maximum number of significant decimal digits used in format results. A value of {@code 0} indicates no limit. The default value is
- * {@code 0}.
- *
- * @param maxPrecision maximum precision
- * @return this instance
- */
- public Builder maxPrecision(final int maxPrecision) {
- this.maxPrecision = maxPrecision;
- return this;
- }
- /**
- * Sets the minimum decimal exponent for formatted strings. No digits with an absolute value of less than <code>10<sup>minDecimalExponent</sup></code>
- * will be included in format results. If the number being formatted does not contain any such digits, then zero is returned. For example, if
- * {@code minDecimalExponent} is set to {@code -2} and the number {@code 3.14159} is formatted, the plain format result will be {@code "3.14"}. If
- * {@code 0.001} is formatted, then the result is the zero string.
- *
- * @param minDecimalExponent minimum decimal exponent
- * @return this instance
- */
- public Builder minDecimalExponent(final int minDecimalExponent) {
- this.minDecimalExponent = minDecimalExponent;
- return this;
- }
- /**
- * Sets the character used as the minus sign.
- *
- * @param minusSign character to use as the minus sign
- * @return this instance
- */
- public Builder minusSign(final char minusSign) {
- this.minusSign = minusSign;
- return this;
- }
- /**
- * Sets the string used to represent {@link Double#NaN}.
- *
- * @param nan string used to represent {@link Double#NaN}
- * @return this instance
- * @throws NullPointerException if the argument is {@code null}
- */
- public Builder nan(final String nan) {
- this.nan = Objects.requireNonNull(nan, "nan");
- return this;
- }
- /**
- * Sets the maximum decimal exponent for numbers formatted as plain decimal strings when using the {@link DoubleFormat#MIXED MIXED} format type. If the
- * number being formatted has an absolute value less than <code>10<sup>plainFormatMaxDecimalExponent + 1</sup></code> and greater than or equal to
- * <code>10<sup>plainFormatMinDecimalExponent</sup></code> after any necessary rounding, then the formatted result will use the
- * {@link DoubleFormat#PLAIN PLAIN} format type. Otherwise, {@link DoubleFormat#SCIENTIFIC SCIENTIFIC} format will be used. For example, if this value
- * is set to {@code 2}, the number {@code 999} will be formatted as {@code "999.0"} while {@code 1000} will be formatted as {@code "1.0E3"}.
- *
- * <p>
- * The default value is {@code 6}.
- *
- * <p>
- * This value is ignored for formats other than {@link DoubleFormat#MIXED}.
- *
- * @param plainFormatMaxDecimalExponent maximum decimal exponent for values formatted as plain strings when using the {@link DoubleFormat#MIXED MIXED}
- * format type.
- * @return this instance
- * @see #plainFormatMinDecimalExponent(int)
- */
- public Builder plainFormatMaxDecimalExponent(final int plainFormatMaxDecimalExponent) {
- this.plainFormatMaxDecimalExponent = plainFormatMaxDecimalExponent;
- return this;
- }
- /**
- * Sets the minimum decimal exponent for numbers formatted as plain decimal strings when using the {@link DoubleFormat#MIXED MIXED} format type. If the
- * number being formatted has an absolute value less than <code>10<sup>plainFormatMaxDecimalExponent + 1</sup></code> and greater than or equal to
- * <code>10<sup>plainFormatMinDecimalExponent</sup></code> after any necessary rounding, then the formatted result will use the
- * {@link DoubleFormat#PLAIN PLAIN} format type. Otherwise, {@link DoubleFormat#SCIENTIFIC SCIENTIFIC} format will be used. For example, if this value
- * is set to {@code -2}, the number {@code 0.01} will be formatted as {@code "0.01"} while {@code 0.0099} will be formatted as {@code "9.9E-3"}.
- *
- * <p>
- * The default value is {@code -3}.
- *
- * <p>
- * This value is ignored for formats other than {@link DoubleFormat#MIXED}.
- *
- * @param plainFormatMinDecimalExponent maximum decimal exponent for values formatted as plain strings when using the {@link DoubleFormat#MIXED MIXED}
- * format type.
- * @return this instance
- * @see #plainFormatMinDecimalExponent(int)
- */
- public Builder plainFormatMinDecimalExponent(final int plainFormatMinDecimalExponent) {
- this.plainFormatMinDecimalExponent = plainFormatMinDecimalExponent;
- return this;
- }
- }
- /**
- * Format class that uses engineering notation for all values.
- */
- private static final class EngineeringDoubleFormat extends AbstractDoubleFormat {
- /**
- * Constructs a new instance.
- *
- * @param builder builder instance containing configuration values
- */
- EngineeringDoubleFormat(final Builder builder) {
- super(builder);
- }
- /** {@inheritDoc} */
- @Override
- public String applyFiniteInternal(final ParsedDecimal val) {
- return val.toEngineeringString(this);
- }
- }
- /**
- * Format class producing results similar to {@link Double#toString()}, with plain decimal notation for small numbers relatively close to zero and
- * scientific notation otherwise.
- */
- private static final class MixedDoubleFormat extends AbstractDoubleFormat {
- /** Max decimal exponent for plain format. */
- private final int plainMaxExponent;
- /** Min decimal exponent for plain format. */
- private final int plainMinExponent;
- /**
- * Constructs a new instance.
- *
- * @param builder builder instance containing configuration values
- */
- MixedDoubleFormat(final Builder builder) {
- super(builder);
- this.plainMaxExponent = builder.plainFormatMaxDecimalExponent;
- this.plainMinExponent = builder.plainFormatMinDecimalExponent;
- }
- /** {@inheritDoc} */
- @Override
- protected String applyFiniteInternal(final ParsedDecimal val) {
- final int sciExp = val.getScientificExponent();
- if (sciExp <= plainMaxExponent && sciExp >= plainMinExponent) {
- return val.toPlainString(this);
- }
- return val.toScientificString(this);
- }
- }
- /**
- * Format class that produces plain decimal strings that do not use scientific notation.
- */
- private static final class PlainDoubleFormat extends AbstractDoubleFormat {
- /**
- * Constructs a new instance.
- *
- * @param builder builder instance containing configuration values
- */
- PlainDoubleFormat(final Builder builder) {
- super(builder);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- protected String applyFiniteInternal(final ParsedDecimal val) {
- return val.toPlainString(this);
- }
- }
- /**
- * Format class that uses scientific notation for all values.
- */
- private static final class ScientificDoubleFormat extends AbstractDoubleFormat {
- /**
- * Constructs a new instance.
- *
- * @param builder builder instance containing configuration values
- */
- ScientificDoubleFormat(final Builder builder) {
- super(builder);
- }
- /** {@inheritDoc} */
- @Override
- public String applyFiniteInternal(final ParsedDecimal val) {
- return val.toScientificString(this);
- }
- }
- /** Function used to construct instances for this format type. */
- private final Function<Builder, DoubleFunction<String>> factory;
- /**
- * Constructs a new instance.
- *
- * @param factory function used to construct format instances
- */
- DoubleFormat(final Function<Builder, DoubleFunction<String>> factory) {
- this.factory = factory;
- }
- /**
- * Creates a {@link Builder} for building formatter functions for this format type.
- *
- * @return builder instance
- */
- public Builder builder() {
- return new Builder(factory);
- }
- }