Eclipse中关于可变Java变量的警告

Eclipse中关于可变Java变量的警告,java,eclipse,functional-programming,Java,Eclipse,Functional Programming,我对Java中更多的函数结构感兴趣,并且想知道Eclipse中是否有一种方法可以让它在我有可变的局部变量、参数、类成员等时发出警告。这样,我可以在重构时轻轻地迁移代码,并在编写新代码时朝着这个方向前进 我意识到这不是FP的全部,但至少是一个开始 谢谢。以我的经验,无论您的IDE如何,您都可以使用最终声明 public class ImmutableThing { private final int someInt; private final String aString; } 这里的

我对Java中更多的函数结构感兴趣,并且想知道Eclipse中是否有一种方法可以让它在我有可变的局部变量、参数、类成员等时发出警告。这样,我可以在重构时轻轻地迁移代码,并在编写新代码时朝着这个方向前进

我意识到这不是FP的全部,但至少是一个开始


谢谢。

以我的经验,无论您的IDE如何,您都可以使用
最终声明

public class ImmutableThing {
  private final int someInt;
  private final String aString;
}
这里的想法是,在构造函数中设置一次,然后再也不要碰它们。(您可以提供更清晰的setter方法,但传达了不必要的概念,即该对象是可变的。)Eclipse、IntelliJ等应该注意
final
声明,并自然地告诉您当代码试图处理这些事情时,它不应该这样做。(我忘了他们是否会告诉您是否已经声明了最终实例变量,并且没有提供设置它的方法。)

当然,要注意的一个曲线球是对象,其字段可以在不更改
ImmutableThing
中字段值的情况下更改:

    private final List<String> strs; // Hmm.
或者使用第三方版本,如Guava:

    strs = ImmutableList<String>.of ("x", "y", "z");
strs=ImmutableList.of(“x”、“y”、“z”);

其他对象可能提供不变性特性;他们可能不会。这一特性的可用性很可能会影响您在这一范例中取得的进展。一般来说,使用不可变的数据对象可以走得很远,而使用流和连接池等固有的有状态的东西则走得不远。

在圣诞节假期中大发雷霆,决定使用解析器,以便能够获得可以从
final
中获益的位置列表。找到javaparser.org,并运行以下代码作为一个简单的开始,我希望在此基础上继续:

import java.io.File;
import java.io.FileNotFoundException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.body.FieldDeclaration;

public class JavaFPMain {

    public static void main(String[] args) throws Exception {
        JavaFPMain fpApp = new JavaFPMain();
        fpApp.run();
    }

    private void run() throws Exception {
        File projectDir = new File(...);
        FileUtils.listFiles(projectDir, new RegexFileFilter(".*.java"), DirectoryFileFilter.DIRECTORY)
            .stream()
            .forEach(this::parseFile);

        System.out.println("done");
    }

    private void parseFile(final File fi) {
        try {
            CompilationUnit compilationUnit = JavaParser.parse(fi);

            String AUTOWIRED = "Autowired";
            compilationUnit.getNodesByType(FieldDeclaration.class).stream()
                .filter(f -> !f.getModifiers().contains(Modifier.FINAL) &&
                             !containsAnnotation(f, AUTOWIRED))
                .forEach(f -> System.out.println("missing final: " + fi.getAbsolutePath() + "(" + f.getBegin().get().line + ") " + f.getVariable(0).getNameAsString()));
        } catch (FileNotFoundException ex) {
            throw new RuntimeException(ex);
        }
    }

    private boolean containsAnnotation(FieldDeclaration f, String name) {
        return f.getAnnotations()
                .stream()
                .anyMatch(a -> a.getNameAsString().equals(name));
    }

}

是的,我从中得到了6000行的输出,这意味着我有我的工作要做,如果我选择追求这个。这还不包括应该设置为final的参数、仍然可以修改的对象等等。但同样,这是一个开始。

谢谢,是的,但我想知道我还需要在哪里添加final,unmodifiableList,等等。我上面给出的代码片段是作为示例使用的。所以,如果你想让某些东西是不可变的,你应该让它看起来像上面的
ImmutableThing
。将其所有字段声明为
final
。假设这没有帮助——你能提供更多关于你正在尝试做的事情的信息吗?好吧,我最初的问题是,在这种情况下,Eclipse是否可以发出警告。指出事物在哪里是可变的。当然,我可以手工检查我的代码,但我有30年的强制性习惯,这些习惯肯定会让我一路受挫。你的例子正是我想做的;我只是想得到一些帮助来确定它的发展方向。好吧,我想我更了解你的来历。要回答您的第一个问题,在Java中,所有非final的内容都是可变的,这意味着您运行的大多数Java代码都将包含几乎所有可变的成员字段。但是,访问规则也有影响(即公共、私有、受保护、默认)。这意味着许多字段实际上是不可变的,我想这会使您在现有代码中一眼就能看出哪些是可变的目标变得复杂。正如我在回答中所暗示的,Eclipse不会真正告诉您哪些是可变的,因为在实践中,几乎所有内容都是可变的,您会被信号淹没。从我的角度来看,如果您认为对象字段应该是不可变的,您可以使用
final
private
将它们锁定下来。然后用
private
锁定mutator方法(即
setSomething()
)。如果代码对更改字段不感兴趣,Eclipse将开始警告您它试图更改您声明的
final
private
字段。也许这对你有帮助?
import java.io.File;
import java.io.FileNotFoundException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.body.FieldDeclaration;

public class JavaFPMain {

    public static void main(String[] args) throws Exception {
        JavaFPMain fpApp = new JavaFPMain();
        fpApp.run();
    }

    private void run() throws Exception {
        File projectDir = new File(...);
        FileUtils.listFiles(projectDir, new RegexFileFilter(".*.java"), DirectoryFileFilter.DIRECTORY)
            .stream()
            .forEach(this::parseFile);

        System.out.println("done");
    }

    private void parseFile(final File fi) {
        try {
            CompilationUnit compilationUnit = JavaParser.parse(fi);

            String AUTOWIRED = "Autowired";
            compilationUnit.getNodesByType(FieldDeclaration.class).stream()
                .filter(f -> !f.getModifiers().contains(Modifier.FINAL) &&
                             !containsAnnotation(f, AUTOWIRED))
                .forEach(f -> System.out.println("missing final: " + fi.getAbsolutePath() + "(" + f.getBegin().get().line + ") " + f.getVariable(0).getNameAsString()));
        } catch (FileNotFoundException ex) {
            throw new RuntimeException(ex);
        }
    }

    private boolean containsAnnotation(FieldDeclaration f, String name) {
        return f.getAnnotations()
                .stream()
                .anyMatch(a -> a.getNameAsString().equals(name));
    }

}