Balaji Vignesh
Balaji Vignesh

Reputation: 456

How to make a condition block in java execute only once?

Consider a file reading scenario, where the first line is a header. When looping the file line by line, an 'if condition' would be used to check whether the current line is the first line.

for(Line line : Lines)
{
     if(firstLine)
     {
         //parse the headers
     }else
     {
         //parse the body
     }
}

Now since the control has come inside the 'if block', in all the other occurrences, it is waste to check the 'if condition'.

Is there any concept in java so that, once after executing, the particular line of code just vanishes away?

I think this would be a great feature if introduced or does it already exist?

Edit: Thank you for your answers. As I see, there were many approaches based on 'divide the data set'. So instead of 'first line', consider there is a 'special line'..

for(Line line : Lines) //1 million lines
{
     if(specialLine)
     {
         //handle the special line
     }else
     {
         //handle the rest
     }
}

In the above code block, suppose the special line comes only after half way to 1 million iterations, how would you handle this scenario efficiently?

Upvotes: 1

Views: 2999

Answers (7)

matt
matt

Reputation: 12347

Since everybody else is posting some weird answers. You could have an interface.

interface StringConsumer{
    void consume(String s);
}

Then just change interfaces after the first attempt.

StringConsumer firstLine = s->{System.out.printf("first line: %s\n", s);};
StringConsumer rest = s->{System.out.printf("more: %s\n", s);};

StringConsumer consumer = firstLine;

for(String line: lines){
    consumer.consume(line);
    consumer = rest;        
}

If you didn't like the assignment, you can make consumer a field and change it's value in the firstConsumer consume method.

class StringProvider{
    StringConsumer consumer;
    List<String> lines;
    //assume this is initialized and populated somewhere.

    void process(){
        StringConsumer rest = s->{System.out.printf("more: %s\n", s);};
        consumer = s->{
            System.out.printf("firstline: %s\n", s);
            consumer = rest;
        };
        for(String line: lines){
            consumer.consume(line);
        }
    }

}

Now the first consume call will switch the consumer that is being used. and subsequent calls will to the 'rest' consumer.

Upvotes: 1

Fred
Fred

Reputation: 1492

As no one said that, I'll just go ahead and say that this extra if statement is actually pretty cheap, performance wise.

At the lowest level of your machine, there is a thing called branch prediction. if statements tend to be pretty expensive when the hardware can't predict its result. But when it does get it right, testing a boolean with an if comes out pretty much for free. And since your if will 99.99% of the times evaluate to false, any hardware will do just fine

So don't worry about that too much. You're not wasting cycles there.

And answering your question... It kind of exists already. It doesn't vanish, but if you code it right it should be pretty close to vanished

Upvotes: 0

Niranjan
Niranjan

Reputation: 11

The simplest answer is to use some kind of flags to ensure that you parse the first line as header only once.

boolean isHeaderParsed = false

for(Line line: Lines)
{
 if(!isHeaderParsed && firstLine)
 {
     //parse the headers
     isHeaderParsed = true
 }else
 {
     //parse the body
 }
}

This will achieve what you are looking for. But if you are looking for something more fancier, Interfaces is what you need.

Parser parser = new HeaderParser()
for(Line line: Lines)
{
  parser = parser.parse();
}

// Implementations for Parser
public class HeaderParser implements Parser{
    public Parser parse() {
         // your business logic
         return new BodyParser();
    }
}

public class BodyParser implements Parser{
    public Parser parse() {
         // your logic
         return this;
    }
}

These are commonly referred to as Thunks

Upvotes: 1

GhostCat
GhostCat

Reputation: 140427

You could (pseudo code) simply reverse things:

// parse headers
for(Line line: remainingLines)
{

But then: you would be using a simple boolean flag for that check. That if check is almost for free, and even more: when this loop sees so many repetitions that it is worth optimizing, the JIT will kick in and create optimized code for it.

And if the JIT doesn't kick in, it isn't worth optimizing this. And of course, there is also branch prediction on the hardware level - in other words: you can expect that modern hardware/software makes sure that the optimal thing happens. Without you doing much else besides writing clear, simple code.

In that sense, your question is a typical example of premature optimization. You worry on the wrong aspects. Focus on writing clean, simple code that gets the job done. Because that is what enables the JIT to do its runtime magic. And most optimisations that you apply at jave source code level do not matter at runtime.

Upvotes: 2

ssaa
ssaa

Reputation: 1112

Have a boolean flag out side of if-else and change the status of flag when it entered in method. also evaluate this flag along with condition

boolean flag=true;

for(Line line: Lines)
{
     if(firstLine && flag)
     {
 flag=false;
         //parse the headers
     }else
     {
         //parse the body
     }
}

Upvotes: 0

Youcef LAIDANI
Youcef LAIDANI

Reputation: 59960

What about changing the logic a little!

So because the header is the first line you can get the firstLine and parse it alone, then start to parse the body starting from the second line :

List firstLine = Lines.get(0);
//parse the headers        ^------------------Get the first line
for (int i = 1; i < Lines.size(); i++) {
    //       ^--------------------------------Parse the body starting from the 2nd line
    //parse the body
}

In this case you don't need any verification.

Upvotes: 5

Milan Baran
Milan Baran

Reputation: 4222

Try to divde the dataset.

public List head(List list) {
    return list.subList(0, 1);
}

public List tail(List list) {
    return list.subList(1, list.size());
}

head(lines).foreach( lambda: //parse the header)
tail(lines).foreach( lambda: //parse the body)

Upvotes: 2

Related Questions