1

I want to create a class which has only static functions. I also need to initialize certain variables before the class functions get called. Since I am using only static functions, I cannot use a constructor to do it.

So now when I try to set the SSLContext in the following manner I get an error: Unhandled exception type NoSuchAlgorithmException. How should I approach this? I can put a try catch in the setContext function and set the value to null, incase of an error. And if I notice somewhere that the context variable is null, I throw an error from one of my functions.

public class HTTPRequest {
    private static SSLContext context = setContext();
    private static SSLContext setContext() throws NoSuchAlgorithmException    {
        return SSLContext.getInstance("TLSv1.2");
    }
}

Specifically how would this effect while writing JUnit test cases: Say hypothetically, while testing I want to pass my mocking algorithm? Usually I would set these values through the constructor. In the following way: HTTPRequest(String algo) { context =SSLContext.getInstance(algo); } But now I won't be able to do that right?

user1692342
  • 5,007
  • 11
  • 69
  • 128

5 Answers5

1

Catch the exception and throw an unchecked exception (such as RuntimeException) instead.

private static SSLContext setContext() {
    try {
        return SSLContext.getInstance("TLSv1.2");
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}
Kayaman
  • 72,141
  • 5
  • 83
  • 121
1

You can create a static init() method that the other static methods will call before they run.

private static void init() { .. }

public static void doSomething() {
  init();
  // do the thing
}

You can also make the class non-static and access it via a singleton instance:

public class HTTPRequest {
  public static HTTPRequest getInstance() { ... }
}

You can then use the constructor normally.

orip
  • 73,323
  • 21
  • 116
  • 148
1

@Kayaman's answer is perfectly correct, but I can also advice you to use static block to initialize static variables - it reduces amount of code:

public class HTTPRequest {
    private static SSLContext context;

    static {
        try {
            context = SSLContext.getInstance("TLSv1.2")
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}
bsiamionau
  • 8,099
  • 4
  • 46
  • 73
1

I want to create a class which has only static functions.

Java has no functions, only methods.

I also need to initialize certain variables before the class functions get called. Since I am using only static functions, I cannot use a constructor to do it.

How about not? That is, use ordinary methods and instances variables in your class. The fact that you're running into trouble doing otherwise could be interpreted as a sign that you should go a different direction.

Nevertheless, you can do this if you insist. The main tool you need is a static initializer block. Such a block can contain more or less arbitrary code to initialize the static members of your class. For example:

public class HTTPRequest {
    private static SSLContext context;

    static {
        try {
            context = setContext();
        } catch (NoSuchAlgorithmException nsae) {
            throw new RuntimeException(nsae);
            // or maybe just eat it, but that would leave context null
        }
    }

    private static SSLContext setContext() throws NoSuchAlgorithmException    {
        return SSLContext.getInstance("TLSv1.2");
    }
}

Note in particular that you can catch exceptions inside an initializer block, and that you can throw unchecked exceptions. If such an initializer does throw an unchecked exception, then loading the class (or initializing it, really) will cause an ExceptionInInitializerError to be thrown.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

I can put a try catch in the setContext function and set the value to null, incase of an error. And if I notice somewhere that the context variable is null, I throw an error from one of my functions.

You should handle the problem as soon as the exception is encountered. This avoid side effect if you forget to handle it everywhere.

So now when I try to set the SSLContext in the following manner I get an error: Unhandled exception type NoSuchAlgorithmException. How should I approach this?

You have three ways of handling the problem :

  • If the exception should stop the handling and that you should display or perform a particular processing when NoSuchAlgorithmException is thrown, you should catch the exception and throw a custom RuntimeException, for example NoSuchAlgorithmRunTimeException :

    try { return SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException e) { throw new NoSuchAlgorithmRunTimeException(e); }

In this way you know how to handle it from the caller side. You only need to catch NoSuchAlgorithmRunTimeException.

  • If the exception should stop the handling and that you should not perform a particular processing when NoSuchAlgorithmException is thrown, throwing a genericRuntimeException as Kayaman suggests is enough:

    try { return SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); }

  • If the exception should be ignored because the exception should not prevent the application to go on working, just catch it and log with the log level that you deem right.

    try { return SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException e) { LOGGER.error("error during initialization",e); }

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Thanks for the detailed info. Does this effect while writing testcases using JUnit? Say hypothetically, while testing I want to pass my mocking algorithm? Usually I would set these values through the constructor. In the following way: HTTPRequest(String algo) { context =SSLContext.getInstance(algo); } But now I won't be able to do that right? – user1692342 Jan 12 '17 at 21:28
  • You are welcome :) You are right. Anyway not with classic unit testing tools as junit or rmockito. After you can use Powermock to bypass this limitation but i think that it is a tool that should be used only when you have no choice. In your case if you want to mock naturally the algorithm, you should have a testable code. – davidxxx Jan 12 '17 at 21:37
  • 1
    Personally I would change the design to avoid using static initialization. If you want ensure that the algorithm be loaded when a HTTPRequest is instantiated, you could use a factory to create HTTPRequest instances. Then when the factory method to create a HTTPRequest instance is invoked you could check if the algorithm was loaded. If it is not case you load it. Using a factory seems more clean that with a constructor as it integrates some logic that you may be surprised to see in a constructor. – davidxxx Jan 12 '17 at 21:38