将Java final关键字添加到在循环内构建实例的工作方法中

时间:2018-12-10 17:59:20

标签: java for-loop final

采取以下POJO:

public class Widget {
    private String fizz;
    private Long buzz;
    private List<Fidget> collaborators;

   // Constructor, getters & setters
}

public class Fidget {
    private String fizz;
    private String foo;

    // Constructor, getters & setters
}

以及以下(有效)方法:

public void compriseWidgets(List<Fidget> fidgetList) {
    List<Widget> widgets = new ArrayList<Widget>();
    Widget currentWidget = null;

    for (Fidget fidget : fidgetList) {
        if (currentWidget == null || 
                !currentWidget.getFizz().equals(fidget.getFizz())) {

            currentWidget = new Widget();
            widgets.add(currentWidget);
            currentWidget.setFizz(fidget.getFizz());
            currentWidget.setBuzz(fidget.getFoo().length());
        }

        currentWidget.getCollaborators().add(fidget);
    }

    return widgets;
}

在这里,我们要返回一个List<Widget>并仅填充该列表:

  1. 从输入列表的第一个Fidget开始(因此currentWidget == null);和
  2. 如果FidgetcurrentWidget具有相同的fizz

此外,我们希望继续将collaborators附加到currentWidget上,无论嘶嘶声是否匹配。

我的问题

新的代码风格指南要求我们使用final声明 ALL 变量...这意味着我需要将上述代码重构为如下形式:

public void compriseWidgets(final List<Fidget> fidgetList) {
    final List<Widget> widgets = new ArrayList<Widget>();
    final Widget currentWidget = null;

    for (final Fidget fidget : fidgetList) {
        ...
    }

    return widgets;
}

因为它既需要在循环中创建一个新的Widget ,又需要一个对Widget的外部引用(在循环之外),我们可以添加{{ 1}},对于如何用collaborators重写它我一无所知。有任何想法吗?另外,请注意,这没什么我可以“推后”的,我只需要弄清楚并使其与新的编码标准一起使用即可。

2 个答案:

答案 0 :(得分:1)

要扩展我的评论,您可以或多或少地机械转换示例代码,如下所示:

$ ls -la ~/
total 72
drwxr-xr-x. 1 cirrus cirrus 4096 Jul  9 19:16 .
drwxr-xr-x. 1 root   root   4096 Mar  7  2018 ..
drwxr-xr-x. 1 cirrus cirrus 4096 Jul  9 19:17 .android
-rw-r--r--. 1 cirrus cirrus  220 May 15  2017 .bash_logout
-rw-r--r--. 1 cirrus cirrus 3526 May 15  2017 .bashrc
-rw-r--r--. 1 cirrus cirrus   24 Jul  9 19:16 .flutter
-rw-r--r--. 1 cirrus cirrus  675 May 15  2017 .profile
drwxr-xr-x. 1 cirrus cirrus 4096 Jul  9 19:16 .pub-cache
drwxr-xr-x. 1 cirrus cirrus 4096 Jul  9 19:16 sdks

可以使许多变量public List<Widget> compriseWidgets(final List<Fidget> fidgetList) { final List<Widget> widgets = new ArrayList<Widget>(); final Widget[] currentWidget = new Widget[] {null}; for (final Fidget fidget : fidgetList) { if (currentWidget[0] == null || !currentWidget[0].getFizz().equals(fidget.getFizz())) { currentWidget[0] = new Widget(); widgets.add(currentWidget); currentWidget.setFizz(fidget.getFizz()); currentWidget.setBuzz(fidget.getFoo().length()); } currentWidget.getCollaborators().add(fidget); } return widgets; } 不受任何特殊影响,包括Fidgets和Widget列表以及增强型final循环中的循环变量。原始方法中唯一的其他变量是for,实现会对其进行修改。可以将其替换为长度为1的(currentWidget)数组,然后将其第零个元素用作原始变量的直接替换。

同样,更麻烦的要求是您可能不使用赋值语句(变量声明中的初始化程序不被视为“赋值”)。这正在朝着一种更具功能性的编程风格发展,我想这可能是您的新指南的意图。然后,您可能会采用以下方法:

final

这几乎是相同的把戏,只是不太明显。可变状态隐藏在调用堆栈中(每次调用public List<Widget> compriseWidgets(final List<Fidget> fidgetList) { final List<Widget> widgets = new ArrayList<Widget>(); final ListIterator<Fidget> fidgets = fidgetList.listIterator(); while (addWidget(widgets, fidgets)) { /* empty */ } return widgets; } private boolean addWidget(final List<Widget> widgets, final ListIterator<Fidget> fidgets) { if (fidgets.hasNext()) { final Fidget firstFidget = fidgets.next(); final Widget currentWidget = new Widget(); widgets.add(currentWidget); currentWidget.setFizz(firstFidget.getFizz()); currentWidget.setBuzz(firstFidget.getFoo().length()); currentWidget.getCollaborators().add(firstFidget); while (fidgets.hasNext()) { final nextFidget = fidgets.next(); if (currentWidget.getFizz().equals(nextFidget.getFizz())) { currentWidget.getCollaborators().add(nextFidget); } else { fidgets.previous(); return true; } } } return false; } 代表原始方法addWidget()的变异)和容器对象(这次为currentWidget())。

可以在功能编程方向上走得更远。通常,例如,您可以考虑基于流的方法,尽管我认为在这种特殊情况下,这种方法不能完全解决问题。但是,更通用的函数式编程没有适用于Streams的约束。

答案 1 :(得分:0)

Builder设计模式是构建不可变对象的好方法。 资源: https://stackoverflow.com/a/15461337/4245294

我最喜欢这个设计模式的版本是它如何为您创建对象之前提供验证规则的理想场所。

适用于此问题的示例:

public class Widget {
    private final String fizz;
    private final Long buzz;
    private final List<Fidget> collaborators;

    private Widget(Builder builder) {
        this.fizz = builder.fizz;
        this.buzz = builder.buzz;
        this.collaborators = builder.collaborators;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private String fizz;
        private Long buzz;
        private List<Fidget> collaborators = new ArrayList<>();

        public Builder addFizz(String fizz) {
            this.fizz = fizz;
            return this;
        }

        public Builder addBuzz(Long buzz) {
            this.buzz = buzz;
            return this;
        }

        public Builder addCollaborators(List<Fidget> fidgets) {
            collaborators.addAll(fidgets);
            return this;
        }

        public Builder addCollaborator(Fidget fidget) {
            collaborators.add(fidget);
            return this;
        }

        private void validate() throws InvalidArgumentException{
            ArrayList<String> invalidArguments = new ArrayList<>();
            boolean failedValidation = false;
            if (collaborators.isEmpty()) {
                invalidArguments.add("collaborators");
                failedValidation = true;
            }
            if (this.fizz == null) {
                invalidArguments.add("fizz");
                failedValidation = true;
            }
            if (this.buzz == null) {
                invalidArguments.add("buzz");
                failedValidation = true;
            }
            if (failedValidation) {
                throw new InvalidArgumentException(invalidArguments.toArray(new String[0]));
            }
        }

        public Widget build() {
            validate();
            return new Widget(this);
        }
    }
}

您将创建一个有效的Widget对象,如下所示:

Widget widget = Widget.builder().addFizz("test").addBuzz(999).addCollaborators(fidgets).build();

您的compriseWidget方法存在我在“问题”的注释中提到的问题,否则我也将提供一个示例。