Java: 错误 无法找到符号 – 为什么这是一个错误而不是异常?

huangapple go评论72阅读模式
英文:

Java: error cannot find symbol - why is this an error and not an exception?

问题

以下是翻译好的内容:

我对Java相对较新,正在试图理解将此问题视为错误而不是异常背后的原因。

我在几个地方读到过错误:

>“表示严重问题,合理的应用程序不应该尝试捕捉”

在我的情况下,我创建了一个名为getAttribute的方法,其中包含一个switch语句,根据所请求的属性返回不同的字段值。在这种情况下,这似乎比为每个属性都有一个getter方法更优雅。以下是代码示例:

public class JPXmlWord implements Serializable {
	 
	    private static final long serialVersionUID = 1L;
	    
	    @XmlAttribute(name = "Kanji")
	    private String kanji;
	    @XmlAttribute(name = "Kana")
	    private String kana;
	    @XmlAttribute(name = "English")
	    private String english;
	    @XmlAttribute(name = "Romaji")
	    private String romaji;
	    @XmlAttribute(name = "Katakana")
	    private String katakana;
	    public String getAttribute( String attribute ) throws Exception {
	    	switch ( attribute ) {
		    	case ("kanji"):
		    		return this.kanji;
		    	case ("kana"):
		    		return this.kana;
		    	case ("english"):
		    		return this.english;
		    	case ("romaji"):
		    		return this.romaji;
		    	case ("katakana"):
		    		return this.katakana;
		    	default:
		    		throw new Exception();
	    	} 
	    }
}

如请求所示,您可以复现缺失符号错误(与从任何类请求任何缺失的符号时会出现的相同错误):

JPXmlWord word = new JPXmlWord();
word.getAttribute("nonExistentAttribute");

为了在请求不存在的字段时引发特定异常,我尝试在jshell中请求一个不存在的字段,以查看会引发哪个特定异常,但是得到了错误而不是异常。

为什么请求不存在的字段被认为是一个“合理的应用程序不应该尝试捕捉的问题”?

我担心我对Java的哲学有一些误解,因为我对此感到很惊讶。非常感谢任何帮助!谢谢!

英文:

I'm relatively new to Java, and trying to understand the rationale behind making this an error, rather than an exception.

I've read in several places that an error:

>"indicates serious problems that a reasonable application should not try to catch"

In my case, I've made a method called getAttribute, containing a switch to return various field values depending on the attribute requested. In this instance it seemed more elegant than to have getter methods for each of these attributes. Here's a sample of the code:

public class JPXmlWord implements Serializable {
	 
	    private static final long serialVersionUID = 1L;
	    
	    @XmlAttribute(name = "Kanji")
	    private String kanji;
	    @XmlAttribute(name = "Kana")
	    private String kana;
	    @XmlAttribute(name = "English")
	    private String english;
	    @XmlAttribute(name = "Romaji")
	    private String romaji;
	    @XmlAttribute(name = "Katakana")
	    private String katakana;
	    public String getAttribute( String attribute ) throws Exception {
	    	switch ( attribute ) {
		    	case ("kanji"):
		    		return this.kanji;
		    	case ("kana"):
		    		return this.kana;
		    	case ("english"):
		    		return this.english;
		    	case ("romaji"):
		    		return this.romaji;
		    	case ("katakana"):
		    		return this.katakana;
		    	default:
		    		throw new Exception();
	    	} 
	    }


By request, so you can reproduce the missing symbol error (same error you'd get requesting any missing symbol from any class):

JPXmlWord word = new JPXmlWord();
word.getAttribute("nonExistentAttribute");

Wanting to throw an exception specific to when an inexistent field is requested, I tried requesting an inexistent field in jshell to see what specific exception gets thrown, but got an error rather than exception.

Why is the request for an inexistent field considered a problem "that a reasonable application should not try to catch"?

I'm worried there is something I don't grasp about Java philosophy, because I am surprised by this. Any help would be greatly appreciated! Thank you!

答案1

得分: 2

如果我理解你的问题正确的话,你的代码大致如下所示:

public class Main {
    private String field1;
    private String field2;

    public String getAttribute(String name) {
        switch (name) {
            case "field1":
                return this.field1;
            case "field2":
                return this.field2;
            case "notDeclaredField":
                return this.notDeclaredField; // <- 这是编译器报错提示的问题
            default:
                throw new IllegalArgumentException("无效的名称");
        }
    }
}

你面临的问题是你的代码无法编译,因为你引用了一个未声明的字段。这是因为Java是一种在使用之前(在编译时)要求字段、类型、方法等被定义的语言。
你似乎来自像Python这样的语言,在Python中,你通过使用字段来_定义_实例字段。

class Class:
    def __init__(self):
        pass

    def setAtt(self, value):
        self.field = value # 这在Python中是可以的

另一方面,下面的代码可以完美编译,并且会执行你似乎期望的操作:

public class Main {
    private String field1;
    private String field2;

    public String getAttribute(String name) {
        switch (name) {
            case "field1":
                return this.field1;
            case "field2":
                return this.field2;
            default:
                throw new IllegalArgumentException("无效的名称");
        }
    }
}

注意,在这里没有访问未声明的字段。但是,如果你希望能够访问一组固定的属性,你应该为每个属性编写一个getter方法。这样,你在编译时就可以获得字段/属性存在的安全性,而不是在运行时。

但是,如果你想在运行时为类实例添加属性,你应该使用 Map<String, String> 来跟踪它们的值:

import java.util.HashMap;

public class Main {
    private HashMap<String, String> atts = new HashMap<>();

    public String getAttribute(String name) {
        if (atts.containsKey(name)) {
            return atts.get(name);
        } else {
            throw new IllegalArgumentException("不存在名称为:" + name + "的属性");
        }
    }

    public static void main(String[] args) {}
}
英文:

If I understood you correctly your code is something like this

public class Main {
    private String field1;
    private String field2;

    public String getAttribute(String name) {
        switch (name) {
            case &quot;field1&quot;:
                return this.field1;
            case &quot;field2&quot;:
                return this.field2;
            case &quot;notDeclaredField&quot;:
                return this.notDeclaredField; // &lt;- this is simply an error that the javac is telling you about
            default:
                throw new IllegalArgumentException(&quot;Invalid name&quot;);
        }
    }
}

and the problem you are facing is that your code can't be compiled because you reference a field that is not declared. This is because Java is a language that enforces that field, type, methods, etc. need to be defined (at compile time) before they are used.
You seam to come from lanugages like python where you define an instance field by using it.

class Class:
    def __init__(self):
        pass

    def setAtt(self, value):
        self.field = value # this is okay in python

On the otherhand the below code would perfectly compile and do what you seam to expect

public class Main {
    private String field1;
    private String field2;

    public String getAttribute(String name) {
        switch (name) {
            case &quot;field1&quot;:
                return this.field1;
            case &quot;field2&quot;:
                return this.field2;
            default:
                throw new IllegalArgumentException(&quot;Invalid name&quot;);
        }
    }
}

notice that there is no access to a field that is not declared.
But if you have a fixed set of attributes you want to be able to access you should simply write a getter for each one. This way you get the safty that the field/attribute is present at compile time rather than at runtime.

But if you want to be able to add attributes to your class instance at runtime, you should use a Map&lt;,&gt; to keep track of theri values

import java.util.HashMap;

public class Main {
    private HashMap&lt;String, String&gt; atts = new HashMap&lt;&gt;();

    public String getAttribute(String name) {
        if (atts.containsKey(name)) {
            return atts.get(name);
        } else {
            throw new IllegalArgumentException(&quot;There is not attribute with the name: &quot; + name);
        }
    }

    public static void main(String[] args) {}
}

huangapple
  • 本文由 发表于 2020年4月6日 20:41:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/61060120.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定