8

HI I have a class below which has functions to pull data from DataServices. I want to always call a method which prints a time at which the method was called and a method which prints time after the method was executed . Basically after every method is executed i want to know how much time it took to execute each method. Is there a generic way to do it instead of adding time at start and end of every function?

class ABC {


    void getAllProducts(){
        // some logic
    }

    void getAllClients(){
        // some logic
    }

    void getAllSymbols(){
        // some logic
    }

 }
Pedro Coelho
  • 1,411
  • 3
  • 18
  • 31
coder
  • 231
  • 3
  • 11
  • 1
    template pattern or aspects. – Eugene Feb 25 '20 at 03:29
  • 7
    Aspect Oriented Programming is designed to do this, but I don't know its current status. I think its popularity might have fallen and it's not really supported much any more. – markspace Feb 25 '20 at 03:31
  • Use object proxies. Example 5 in the following link is exactly what you're looking for https://www.baeldung.com/java-dynamic-proxies – Ruan Mendes Feb 25 '20 at 03:57
  • @markspace , please elaborate. – Vishwa Ratna Feb 25 '20 at 07:24
  • 1
    Rather than changing your code, if you want to know how long each method takes to run then you should use a profiler. That will give you much more useful information about your program's efficiency. – kaya3 Feb 25 '20 at 09:10
  • If you are using spring, look at https://tomgregory.com/spring-boot-default-metrics/. But if you really need to write your own code, looking at jUint's @BeforeMethod would be a good place to start. – developer747 Mar 13 '21 at 22:24

1 Answers1

16

You can use an “Execute Around” idiom similar to this by Jon Skeet, with the timing surrounding your method call:

public class StackOverflowTest {
  public static void main(String[] args){
    StackOverflowTest test = new StackOverflowTest(); 
    test.timeMethod(test::getAllProducts);
    test.timeMethod(test::getAllClients);
    test.timeMethod(test::getAllSymbols);
  }

  void getAllProducts(){
    System.out.println("getting all Products");
  }

  void getAllClients(){
    System.out.println("getting all Clients");
  }

  void getAllSymbols(){
    System.out.println("getting all Symbols");
  }

  // The "Execute Around" method
  void timeMethod(JustDoIt justDoIt){
    long start = System.nanoTime();
    try {
      justDoIt.doIt();
    } finally {
      long end = System.nanoTime();
      System.out.println("  Time: " + (end - start) / 1000 + " microseconds"");
    }
  }  
}

@FunctionalInterface
interface JustDoIt {
  void doIt();
}

Prints:

getting all Products
  Time: 1817 microseconds
getting all Clients
  Time: 421 microseconds
getting all Symbols
  Time: 418 microseconds

If you don't want your own Interface, you can replace it with a Runnable. This example also uses System.currentTimeMillis() instead of System.nanoTime():

void timeMethod(Runnable toRun){
  long start = System.currentTimeMillis();
  try{
    toRun.run();
  } finally {
    long end = System.currentTimeMillis();
    System.out.println("  Time: " + (end - start) + " miliseconds");
  }
}  
Scratte
  • 3,056
  • 6
  • 19
  • 26
  • 4
    `System.nanoTime()` is better for this. – kaya3 Feb 25 '20 at 09:08
  • 1
    @kaya3 Thank you :) For completeness I modified it. I rarely use it, due to the statement "no guarantees are made except that the resolution is at least as good as that of currentTimeMillis()" in [nanoTime](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/System.html#nanoTime()). I also sort of assumed that the use would be for calls that takes a lot more time. – Scratte Feb 25 '20 at 09:19
  • 9
    `currentTimeMillis()` is not monotonic, meaning that the value of consecutive calls is not guaranteed to increase, e.g. if the clock is moved back (change of timezone, DST, fixing time skew, or for any other reason). `nanoTime()` is monotonic, and as such is better to use for time duration computations like this, as long as both the start and end value come from the same JVM. – vlumi Feb 25 '20 at 10:38