2015-05-29 21 views
2

我在Java 8中有一個方法create(Environment env),它有多個語句。現在我需要重寫方法來添加支持新的migration功能。Java 8中的條件lambda執行

要添加支持的migration只是表示:

如果Environment env對象有場migration設置爲true不 在create函數執行一些代碼。

這就是爲什麼我包裝這些代碼塊:

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... 
} 

這些代碼塊我廣泛分佈create功能。因此,我必須爲多個代碼塊添加條件執行。

在使用lambda表達式的情況下,我可以獲得一些優勢嗎? Java 8中是否有任何模式?

我的本意是寫的是這樣的:

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()); 
}); 

因此我希望得到lambda表達式,而我可以傳遞的任何代碼塊。只有當它不是migration時,lambda表達式纔會執行這些語句。

  1. 我該怎麼寫這個forMigrate lambda函數?
  2. 在這個例子中,使用lambda表達式與舊的if (...) {}語句有什麼優勢?

注:

  1. 我不控制Environment類,它是自動生成的XML文件。
  2. 我想最大限制範圍forMigration - 只在create(不要讓它在任何地方可見) - 這就是爲什麼我要分配lambda表達式到變量:final ... forMigrate = (...) -> { ... }
  3. 我想爲Environment使用詞法作用域,不要直接將它傳遞給lambda。從lambda定義的地方使用它。

原有功能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; 
    } 

我怎麼會改寫舊的Java 7的風格:

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; 
    } 
+3

你的問題根本不清楚 - 你可以用編譯的實際代碼(有或沒有lambda表達式)顯示一個例子嗎? – assylias

+0

我添加了更多細節,原始函數代碼和修改後的代碼(它在Java 7中的外觀)。 – likern

回答

2

你可以寫類似:

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

而且在你的代碼:

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

這是基於你的代碼

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; 
    } 
} 

樣本使用消費者可以參考一下您使用的拉姆達檢查(如果需要環境)相同的環境。

+0

謝謝!這與我的意圖非常相似。但我如何寫forMigration不是作爲Environment的方法,而是作爲lambda表達式在創建函數(甚至是捕獲Environment env時關閉)?我添加了Notes來解釋我的困難。 – likern

+0

@likern用我的lambda知識我不嘲笑它是可能的,或者如果可能的話,我的懷疑是java7解決方案會更復雜 – Giovanni

0

我不知道這是一個選擇,但在create你可以寫:

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

,然後調用它像這樣:

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

你不會輕易得到儘管如此,擺脫了函數式接口方​​法調用,因爲您只能對函數使用函數調用語法(帶圓括號),這些語法無法捕獲調用站點的環境。