1
\$\begingroup\$

I'm at an intermediate-ish level in java programming in school (using repl.it), and I have a math related project I'm working on. After the user inputs their own measurements, "calculating......." is outputted into the console and the periods are "animated" so to say. The code works fine but I'm convinced there has to be a way to condense this mess of 50 some odd lines that just moves some dots around, any input is greatly appreciated.

class Main {
  public static void main(String[] args) {
System.out.print("\n\n\n\ncalculating.......");
for(int i = 0; i < 3; ++i) {
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b  ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b   ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b    ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b\b     ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b\b\b      ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b\b\b\b       ");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b.");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b..");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b...");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b....");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b\b.....");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b\b\b......");
  try {Thread.sleep(200);
  } catch (InterruptedException e) {
    e.printStackTrace();}
  System.out.print("\b\b\b\b\b\b\b.......");
}
}
}
\$\endgroup\$
0
3
\$\begingroup\$
  1. Write a function. You have code that is repetitious? Write a function to hide it away!

    private static void show_string(String s) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.print(s);
    }
    
  2. In fact, write several functions! Use function names to explain what you are doing. Also, it would be good if you wrote the functions in such a way as to facilitate other refactorings:

    public static final int ANIMATION_DELAY_MSEC = 200;
    public static final String BKSP = "\b";
    public static final String DOT = ".";
    public static final String SPACE = " ";
    
    private static void delay_msec(int msec) {
        try {
            Thread.sleep(msec);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }      
    }
    
    private static void print_ntimes(String s, int n) {
        if (n < 0) n = 0;
        for (int i = 0; i < n; ++i)
           System.out.print(s);
    }
    
    private static void hide_dots(int count) {
        print_ntimes(BKSP, count);
        print_ntimes(SPACE, count);
    }
    
    private static void show_dots(int count) {
        print_ntimes(BKSP);
        print_ntimes(DOT);
    }
    
    
    // main
    {
        // ...
        for (int i = 0; i < MAX_DOTS; ++i) {
            hide_dots(i); 
            delay_msec(ANIMATION_DELAY_MSEC);
        }
    
        for (int i = 0; i < MAX_DOTS; ++i) { 
            show_dots(i);
            delay_msec(ANIMATION_DELAY_MSEC);
        }
        // ...
    }
    
\$\endgroup\$
2
\$\begingroup\$

@aghast makes many good points, but I'd add a few more.

Firstly, the string being printed can be simplified. In the first half of the processing, a single period character is being cleared at each step, so "\b \b" could be used. In the second half, we're just adding one period...

Secondly, on Unix-like systems standard output is line-buffered, so no output appears until either a new line is written or flush() is called.

Thirdly, the handling of InterruptedException is ugly. If a sleep received an interrupt in this context we'd probably want to restart it for the remaining time not dump a stack trace. So you'd need to have calculated an end time for the sleep and recalculate the sleep time on interrupt. I'd therefore wrap the sleep in a loop, but I can imagine a recursive approach working.

Finally, I'd prefer to stick to Java conventions, so in place of @aghast's "functions" I'd use the term "methods", and I'd use camelCase naming rather than snake_case so methods were called (for example) hideDots rather than hide_dots.

\$\endgroup\$
2
\$\begingroup\$

First Welcome to CodeReview.

Some comments on your code:

  1. The code need a clear indentation, most IDE can help formatting code easily with one shortcut.

  2. You may separate sections with new line, it will ease readability, also it may help to spot new method candidate.

  3. If your see a value repeated many times in your method/class, it's preferable to declare it as constant.

  4. Main method is too long, better to create methods (or classes) with only one responsibility.

  5. I see no testing in your code, starting with test before writing production code, gives more understanding of the feature and also help to refactor your code later with confidence, so you may give TDD a try.

  6. Better to give a descriptive name to your class instead of generic one like Main for better readability.

  7. Thank you! I learnt how to do a text animation from your code.

Your original code might be better like:

class TextAnimation {
    
    public static void main(String[] args) {
      System.out.print("\n\n\n\ncalculating.......");
      
      for (int i = 0; i < 3; ++i) {
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.print("\b ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b  ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b   ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b\b    ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b\b\b     ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b\b\b\b      ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b\b\b\b\b       ");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b.");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b..");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b...");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b\b....");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }        
        System.out.print("\b\b\b\b\b.....");
        
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.print("\b\b\b\b\b\b......");
        
        try {          
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.print("\b\b\b\b\b\b\b.......");
      }
    }

}

Back to your original question, and in order to make the code better, I will suggest the following code (I put a comment in code just to explain the usage in this context, but I don't recommend to do so in your production code):

class TextAnimation {

  public static void main(String[] args) {
    int maxDots = 7;
    int animationCycleCount = 3;

    System.out.print("\n".repeat(4) + "calculating" + ".".repeat(maxDots));

    for(int i = 0; i < animationCycleCount; ++i) {
      waiting();
      hideDots(maxDots);
      showDots(maxDots);
    }
  }

// Each method is declared directly below its caller.
        
  private static void waiting() {
    try {
      TimeUnit.MILLISECONDS.sleep(200);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();  // set interrupt flag
    }
  }

  private static void hideDots(int countDotsToHide) {
    animateWithString(" ", countDotsToHide);
  }

  private static void animateWithString(String value, int maxOccurrence) {
    IntStream.rangeClosed(1, maxOccurrence).forEach(times -> { // Use java 8+ stream
      System.out.print(getNewSuffix(value, times));
      waiting();
    });
  }

  static String getNewSuffix(String c, int times) {
    return "\b".repeat(times) + c.repeat(times);
  }

  private static void showDots(int countDotsToShow) {
    animateWithString(".", countDotsToShow);
  }

}

And a Test for getNewSuffix method, (you may add other tests as well):

import org.junit.Test;    
import static org.junit.Assert.assertEquals;

public class TextAnimationTest {

  @Test
  public void getNewSuffix_should_get_n_occurrences_with_n_back_spaces() {
  // When
    var suffix = TextAnimation.getNewSuffix(".", 3);

  // Then
    var expectedSuffix = "\b\b\b...";
    assertEquals(expectedSuffix, suffix);
  }

}
\$\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.