2

I have a method create(Environment env) in Java 8, which have multiple statements. Now I need to rewrite method to add support of new migration functionality.

To add support of migration just means:

If Environment env object has field migration set to true don't execute some code in create function.

That's why I wrap these code blocks:

protected Environment create(Environment env) 
{
    statements;
    if (!env.isForMigrate()) {
         // executed only if it's NOT a migration
        statements;
        // for example: imh.create(ve)
        // or: newEnv.setAps(env.getAps());
    }
    ...
    statements;
    if (!env.isForMigrate()) {
         // executed only if it's NOT a migration
        statements;
    }
    ...
    and so on...
}

These code blocks I widespread all over create function. Thus I have to add conditional execution for multiple code blocks.

Can I get some advantages in case of using lambda expressions for this? Is there any pattern in Java 8?

My intention is to write something like this:

final Predicate<T> forMigrate = (func) -> {
    // closure for Environment env
    if (env.isForMigrate()) {
        func(); // execute passed statements
    }
}

... 
forMigrate({
    Environment newEnv = apsh().envh().im2aps(ve);
    newEnv.setAps(env.getAps());
    newEnv.setOsId(env.getOsId());
});

Thus I want to get lambda expression, to which I could pass any block of code. And lambda expression will execute these statements only if it's not a migration.

  1. How can I write this forMigrate lambda function?
  2. Is there any advantages of using lambda expressions vs old if (...) {} statements in this example?

Note:

  1. I don't control Environment class, it's auto-generated from XML file.
  2. I want to maximum restrict scope of forMigration - only inside create (don't make it visible anywhere) - that's why I want to assign lambda expression to variable: final ... forMigrate = (...) -> { ... }.
  3. I want to use lexical scoping for Environment, dont' pass it directly to lambda. Use it from where lambda is defined.

Original function create:

protected Environment create(Environment env)
    {
        if(env.getHostname()!=null && env.getHostname().endsWith(".")){
            String normalizedHostname = env.getHostname().substring(0, env.getHostname().length() - 1);
            env.setHostname(normalizedHostname);
        }
        Ve ve = apsh().envh().aps2im(env);
        if (ve.getHostname() == null) {
            ve.setHostname(ve.getName());
        }
        List<String> apps = env.getApps();
        Boolean passwordSet = false;
        imh.create(ve);
        ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
        if(env.getPassword()!= null && !env.getPassword().isEmpty()){
            try{
                imh.setVePassword(ve.getCustomerId(), ve.getName(), env.getPassword());
                passwordSet = true;
            } catch(Exception ex){
                logger.error("Failed to set password for VE: " +  env.getName(), ex);
            }
        }
        if (!apps.isEmpty()) {
            try {
                imh.setVeApps(ve.getCustomerId().intValue(), ve.getName(), apps);
            } catch (Exception ex) {
                logger.error("Failed to install applications VE: {}", ex);
            }
        }
        VeFacade vef = vehFactory.create(ve.getCustomerId(), ve.getName());
        vef.operation("start");

        ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
        Environment newEnv = apsh().envh().im2aps(ve);
        newEnv.setAps(env.getAps());
        newEnv.setOsId(env.getOsId());
        newEnv.setSample(env.getSample());
        newEnv.setHosting(env.getHosting());
        newEnv.setDomain(env.getDomain());
        newEnv.getStatus().setUptime(Long.valueOf(new Date().getTime()));
        newEnv.setPassword(null);  //prevent password from being saved in DB    
        newEnv.setPasswordSet(passwordSet);
        apsh().envh().fillOsData(newEnv, apsh().teh().getOs(newEnv.getOsId()));
        apsh().envh().synchPublicAddresses(newEnv, ve);
        apsh().dnsh().synchDomainRecords(newEnv);
        logger.info("Environment '{}' successfully created", newEnv.getName());
        return newEnv;
    }

How I would rewrite it in old Java 7 style:

protected Environment create(Environment env)
    {
        if(env.getHostname()!=null && env.getHostname().endsWith(".")){
            String normalizedHostname = env.getHostname().substring(0, env.getHostname().length() - 1);
            env.setHostname(normalizedHostname);
        }
        Ve ve = apsh().envh().aps2im(env);
        if (ve.getHostname() == null) {
            ve.setHostname(ve.getName());
        }
        List<String> apps = env.getApps();
        Boolean passwordSet = false;

        // NOTE: Wrap block of code
        if (env.isForMigrate() == false) {
            imh.create(ve);
        }
        ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
        if(env.getPassword()!= null && !env.getPassword().isEmpty()){
            try{
                imh.setVePassword(ve.getCustomerId(), ve.getName(), env.getPassword());
                passwordSet = true;
            } catch(Exception ex){
                logger.error("Failed to set password for VE: " +  env.getName(), ex);
            }
        }
        if (!apps.isEmpty()) {
            try {
                imh.setVeApps(ve.getCustomerId().intValue(), ve.getName(), apps);
            } catch (Exception ex) {
                logger.error("Failed to install applications VE: {}", ex);
            }
        }

       // NOTE: Wrap block of code
       if (env.isForMigrate() == false) {
           VeFacade vef = vehFactory.create(ve.getCustomerId(), ve.getName());
           vef.operation("start");
       }

        ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
        Environment newEnv = apsh().envh().im2aps(ve);
        // NOTE: Wrap block of code
        if (env.isForMigrate() == false) {
            newEnv.setAps(env.getAps());
            newEnv.setOsId(env.getOsId());
            newEnv.setSample(env.getSample());
        }
        newEnv.setHosting(env.getHosting());
        newEnv.setDomain(env.getDomain());
        newEnv.getStatus().setUptime(Long.valueOf(new Date().getTime()));
        newEnv.setPassword(null);  //prevent password from being saved in DB    
        newEnv.setPasswordSet(passwordSet);
        apsh().envh().fillOsData(newEnv, apsh().teh().getOs(newEnv.getOsId()));
        apsh().envh().synchPublicAddresses(newEnv, ve);
        apsh().dnsh().synchDomainRecords(newEnv);
        logger.info("Environment '{}' successfully created", newEnv.getName());
        return newEnv;
    }
2
  • 3
    Your question is not clear at all - can you show an example with actual code that compiles (with or without lambdas)? Commented May 29, 2015 at 14:37
  • I added more details, original function code and modified code (how it would looks in Java 7). Commented May 29, 2015 at 14:54

3 Answers 3

3

this is a sample based on your code

private static class Environment {
    private String aps;
    private String osId;
    private String sample;
    private boolean forMigrate;

    public String getAps() {
        return aps;
    }
    public void setAps(String aps) {
        this.aps = aps;
    }
    public String getOsId() {
        return osId;
    }
    public void setOsId(String osId) {
        this.osId = osId;
    }
    public String getSample() {
        return sample;
    }
    public void setSample(String sample) {
        this.sample = sample;
    }

    private void forMigration(Environment e, Consumer<Environment> con) {
        if (!e.isForMigrate()) {
            con.accept(e);
        }
    }

    public boolean isForMigrate() {
        return forMigrate;
    }
    public void setForMigrate(boolean isForMigrate) {
        this.forMigrate = isForMigrate;
    }

    protected Environment create(Environment env) {
        Environment newEnv= new Environment();
        List<String> imh=new ArrayList<>();
        forMigration(env, e -> {newEnv.setAps(e.getAps());newEnv.setOsId(e.getOsId()); });
        forMigration(env, e -> {imh.add("test for generic call"); });
        return newEnv;
    }
}

Using a Consumer you can reference the same Enviroment you use for the check in the lambda (if a Enviroment is needed).

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! That's very similar to my intention. But how I can write forMigration not as method of Environment, but as lambda expression inside create function (or even closure with capturing Environment env)? I added Notes to explain my difficulties.
@likern with my knowledge of lambda I do not tink it's possibile, or if it's possible my suspect is that it would be more complicated that the java7 solution
2

You could write something like:

private static void forMigrate(Environnement env, Runnable r) {
  if (!env.isForMigrate()) r.run();
}

And in your code:

forMigrate(env, () -> {
    newEnv.setAps(env.getAps());
    newEnv.setOsId(env.getOsId());
    newEnv.setSample(env.getSample());
  }
);

Comments

0

I don't know if this is an option for you, but in create you could write:

Consumer<Runnable> forMigration = runnable -> {
    if (environment.isForMigrate()) runnable.run();
};

and then call it like this:

forMigration.accept(() -> System.out.println("migrating"));

You will not easily get rid of that functional interface method call, though, because you can only use function call syntax (with parentheses) on functions, which cannot capture the call site's environment.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.