2
\$\begingroup\$

The code generates a list containing all possible combinations of the items of an array. Every triplet of items contains two operands and the third item containing "-0.0" or null, depending on the result of the given BiFunction applied to the operands. The list then is printed out, with additions for better readabilty (nulls are not printed, operation signs are inserted). The output looks like

 ...
 -0.0 *     -30.0 = 
 -0.0 *      -5.0 = 
 -0.0 *      -0.0 = 
 -0.0 *       0.0 = -0.0
 -0.0 *       6.0 = -0.0
 -0.0 *      40.0 = -0.0
 ...

There are tho methods intended to be used in a real project, they are marked with "(meant to be used in a real project)". Regarding formatting, it's my deliberate choice to write ifs with a single nested statement without curly braces -- I hate to read code written in a sparse manner, when I can see only 3 substantial lines of code on the screen, and I never write such a code.

I'd like to know:

  1. if the provided code conforms to the best practices regarding style (naming conventions, formatting etc);
  2. Is there a smarter, neater solution for the task;
  3. Are the comments intelligible enough (among others, my English is a concern);
  4. What is the "right" way to check if a double value is -0 (marked with "???")

The code:

package forquadruple.streamsandlambdas;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;

/**
 * 20.12.01 14:49:05
 * Builds and tests a list with the Cartesian products of the given operands
 * that are String representations of double values.
 * The list should consist of triplets of Strings, where each triplet
 * includes a pair of string representations of two double operands, and the third item of the triplet
 * should depend on the result of the given {@code BiFunction<Double, Double, Double> function} applied to the operands.<br>
 * If the result of the function is -0, the third item of the triplet should contain "-0.0",
 * otherwise it should be {@code null},
 * in other words, for any n<pre>
 * triplet[n*3 + 2] =
 *    (function(triplet[n*3], triplet[n*3 + 1]) == -0 ? "-0.0" : null)
 * </pre>
 * for example, for multiplication the list may contain the following triplets:
 * <pre>
 * "0", "-5", "-0",
 * "5", "-5", null,
 * </pre>
 */
public class TestListGeneration {

  private static final char[] OP_SIGNS = new char[] {'+', '-', '*', '/'};

  private static final String[] OPERANDS = new String[] {
    "-Infinity",
    "-30.0",
    "-5.0",
    "-0.0",
    "0.0",
    "6.0",
    "40.0",
    "Infinity",
    "NaN",
  };

  public static void main(String[] args) {
    new TestListGeneration().testGeneration();
  }

  /**
   * Build some sample lists and print their contents 
   */
  private void testGeneration() {
    final List<String> list = new ArrayList<>();

    final int sectionSize = (OPERANDS.length * OPERANDS.length + 1) * 3;      // To know when to add a gap between different operations

  // add lists for different operatins
    list.addAll(cartesianSquareWithMinusZeros(OPERANDS, (a, b) -> a + b));   // add sums of operands
    list.add(""); list.add(""); list.add(""); // Just a gap between operations, for better readability

    list.addAll(cartesianSquareWithMinusZeros(OPERANDS, (a, b) -> a - b));
    list.add(""); list.add(""); list.add("");

    list.addAll(cartesianSquareWithMinusZeros(OPERANDS, (a, b) -> a * b));
    list.add(""); list.add(""); list.add("");

    list.addAll(cartesianSquareWithMinusZeros(OPERANDS, (a, b) -> a / b));
    list.add(""); list.add(""); list.add("");

    printTheList(list, sectionSize);
  }

  /**
   * (meant to be used in a real project)
   * Builds a list of all possible pairs of operands (their Cartesian square)
   * supplemented with "-0.0" (if the result of the given operation applied to the operands is -0)
   * or with null (in all other cases).
   * @param operands -- an array containing string representations of double operands
   * @param operatoin -- the operation whose result affects the third
   * @return the resulting list 
   */
  public List<String> cartesianSquareWithMinusZeros(String[] operands, BiFunction<Double, Double, Double> operatoin) {
    final List<String> result = new ArrayList<>();
    Arrays.stream(OPERANDS).forEach(s1 -> {
      Arrays.stream(OPERANDS).forEach(s2 -> {
        result.add(s1);
        result.add(s2);
        result.add(isMinusZero(s1, s2, operatoin)? "-0.0" : null);
      });
    } );
    return result;
  }

  /**
   * (meant to be used in a real project)
   * Checks whether the given operation applied to the given operands results in -0
   * @param op1str -- 1st operand as a String
   * @param op2str -- 2nd operand as a String
   * @param operation -- the operation to perform on the operands
   * @return true, if the result of the operation is -0, false otherwise
   */
  private boolean isMinusZero(String op1str, String op2str, BiFunction<Double, Double, Double> operation) {
    final double op1 = Double.parseDouble(op1str);
    final double op2 = Double.parseDouble(op2str);

    // ??? is there a neater way to check if a value is -0?  
    return Double.doubleToLongBits(operation.apply(op1, op2)) == 0x8000_0000_0000_0000L;
  }

  /**
   * Prints the list, just to watch the contents of the list
   * @param list
   * @param sectionSize
   */
  private void printTheList(final List<String> list, final int sectionSize) {
    String s = "";
    char opSign = '+';
    for (int i = 0; i < list.size(); ) {

      if (i % sectionSize >= sectionSize - 3) // Just a gap between operations, for better readability
        opSign = ' ';                         // Will be an empty line
      else
        opSign = OP_SIGNS[i / sectionSize];   // Will be a line with the operands and (perhaps)

      say("%9s %s %9s %s %s",
          list.get(i++), opSign, list.get(i++),  // Operands separated by the operation sign
          opSign == ' ' ? ' ' : '=',             // and perhaps accompanied with the result
          (s = list.get(i++)) == null? "": s);   // replace nulls with empty strings
    }
  }

  /** print to console, just for convenience */
  public static void say()  { System.out.println(); }
  public static void say(Object o)  { System.out.println(o); }
  public static void say(String format, Object... args) { System.out.println(String.format(format, args)); }

}
\$\endgroup\$
1
\$\begingroup\$
  • There's no reason to use Arrays#stream to iterate an array. It's slower and requires all captured locals to be final, as opposed to a simple for (String s1 : OPERANDS) which compiles directly to a normal for loop.

  • 'Operation' is misspelled several times

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.