Jens Jansson
Jens Jansson

Reputation: 4686

Can you store a variable inside a if-clause?

I'm kinda waiting for a 'no' answer on this question.

I was interested if you can save a variable at the same time when you checking it in an if-clause.

Let's say I have this code.

if(foo!=null){
  if(foo.getBar()!=null){
    Bar bar = foo.getBar();
    System.out.println("Success: " + bar);
  } else {
    System.out.println("Failure.");
  }
} else {
  System.out.println("Failure.");
}

I handling now to "failure" -states independently, even if the outcome is the same. I could get them together like this:

if(foo!=null && foo.getBar()!=null){
  Bar bar = foo.getBar();
  System.out.println("Success: " + bar);
} else {
  System.out.println("Failure.");
} 

Much neater code already. if foo is null it will stop there and won't try foo.getBar (in the if) so I won't get a NPE. The last thing i would like to enhance, and the main question: Do I really gave to call on foo.getBar() twice? It would be nice to get away from the second identical call if getBar() would be a very heavy operation. So I am wondering if there is somehow possible to do something similiar to this:

if(foo!=null && (Bar bar = foo.getBar())!=null){
  Bar bar = foo.getBar();
  System.out.println("Success: " + bar);
} else {
  System.out.println("Failure.");
}

I would have to break it up to two different if's again if I would like to do

Bar bar = foo.getBar();
if (bar!=null) ...

Upvotes: 24

Views: 11665

Answers (9)

architect_711
architect_711

Reputation: 11

Duc Minh Vu said it, but I have found out this line of code inside the OncePerRequestFilter#doFilter in Spring Boot:

if (!((request instanceof HttpServletRequest httpRequest) && (response instanceof HttpServletResponse httpResponse))) {
    throw new ServletException("OncePerRequestFilter only supports HTTP requests");
}

Spring boot version: 3.4.1

I found next in a documentation (in a nutshell):

Starting from Java 16 the Pattern Matching for instanceof was introduced to avoid next lines of code

if (obj instanceof String) {
    String s = (String) obj;    // grr...
    ...
}

Upvotes: 0

TofuBeer
TofuBeer

Reputation: 61536

if you want to limit the scope of Bar bar I'd add { and } around the code that Michael posted.

void foo()
{
    // some code ...
    
    // this block limits the scope of "Bar bar" so that the rest of the method cannot see 
    // it.
    {
        Bar bar;
        if(foo!=null && (bar = foo.getBar())!=null){
            System.out.println("Success: " + bar);
        } else {
            System.out.println("Failiure.");
        }
    }
}

You might also want to check into the null object pattern if it makes sense. I personally try to avoid things being null if I can... really think about if you want null to be allowed or not.

Upvotes: 7

Duc Minh Vu
Duc Minh Vu

Reputation: 15

With pattern matching in Java 14, you can get even closer:

if(foo != null && foo.getBar() instanceof Bar bar) {
    // instanceof itself does null-check
    System.out.println("Success: " + bar);
} else {
    System.out.println("Failure.");
}

Upvotes: 0

Jan Nielsen
Jan Nielsen

Reputation: 11829

You cannot declare a variable in a Java conditional, but you can in a for loop:

for (Bar bar = (null != foo) ? foo.getBar() : null; bar != null;) {
    System.out.println("Success: " + bar);
    break;
}

But it is not pretty. I completely agree with Tom Hawtin's comments.

Upvotes: 0

Felipe Gomes
Felipe Gomes

Reputation: 1

Actually I think that is a way to do this using Java Optional, here's an example:

Optional.ofNullable("text").ifPresent( $0 -> {
  System.out.println($0.toUpperCase());
});

Or in your case:

  if(foo != null){
      Optional.ofNullable(foo.getBar()).ifPresent(bar -> {
          System.out.println("Success: " + bar);
      });
  }

Upvotes: 0

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147164

Three points that completely fail to answer the question:

null is evil. Don't write methods that return it. Your example problem would then disappear.

I think you might be missing out on encapsulation. Instead of foo.getBar() could the interface of foo be made such that you perform a "tell don't ask" operation?

Side-effects in expression tends to cause bad code. Prefer more, simpler lines to fewer, buggy lines. The usual exception if using ++ to increment an index when accessing a buffer, or similar iterator style algorithms.

Upvotes: 2

Aaron Digulla
Aaron Digulla

Reputation: 328724

From the department "My Programming Language is Better Than Your Programming Language": In Groovy, you can use the "?." operator:

Bar bar = foo?.bar
if (bar != null) {
}

In Java, this is good pattern(*):

Bar bar = foo == null ? null : foo.getBar();
if (bar != null) {
}

*: Something you can save in your fingertips.

Upvotes: 2

Staale
Staale

Reputation: 27998

I have used that technique when iterating over lines from a BufferedReader:

BufferedReader br = // create reader
String line
while ((line = br.readLine()) != null) {
    // process the line
}

So yes, you can do an assignment, and the result off that will be the left hand side variable, which you can then check. However, it's not legal to declare variables inside a test, as they would then only be scoped to that expression.

Upvotes: 14

Michael Borgwardt
Michael Borgwardt

Reputation: 346377

This is the closest you can get:

Bar bar;
if(foo!=null && (bar = foo.getBar())!=null){
  System.out.println("Success: " + bar);
} else {
  System.out.println("Failiure.");
}

Upvotes: 39

Related Questions