下面的代码来自我的教科书中的一个分配,用于获取用户输入的名称并将名字和姓氏的第一个字母大写的简单程序。代码工作正常,但我不明白为什么name.substring()
正常工作。具体来说,我对第24 - 29行的块如何工作感兴趣。如果用户输入名称“Johnny Johnson”,那么i
应包含值为7的第29行。如果i
确实包含7,则name = name.substring(0, i)
不应包含“Johnny J “这应该让第29行实际存储”Johnny JJohnson“String name
?但实际上,它实际上存储了“约翰尼约翰逊”。
我的第二个问题来自于搞乱这段代码以查看不同的结果。如果我将第29行的第一部分更改为name = name.substring(0, i-1)
,我会收到错误(使用Eclipse):
线程“main”中的异常 java.lang.StringIndexOutOfBoundsException: 字符串索引超出范围:15 at java.lang.String.charAt(String.java:558) 在 RepairName.main(RepairName.java:17)
为什么错误出现在第17行而不是第29行?实际上,为什么我会收到错误,因为i-1
实际上并没有改变i
的值是正确的?我认为它与循环有关,但由于i
的值没有改变,我不知道为什么会这样。
对不起,如果这是一个冗长的问题。我是Java新手,对编程很新(很明显),但我很欣赏你们所能给予的任何见解。谢谢!
1 import javax.swing.*;
2
3 public class RepairName
4 {
5 public static void main(String[] args)
6 {
7 String name, saveOriginalName;
8 int stringLength;
9 int i;
10 char c;
11 name = JOptionPane.showInputDialog(null, "Please enter your first and last name");
12
13 saveOriginalName = name;
14 stringLength = name.length();
15 for (i = 0; i < stringLength; i++)
16 {
17 c = name.charAt(i);
18 if (i == 0)
19 {
20 c = Character.toUpperCase(c);
21 name = c + name.substring(1, stringLength);
22 }
23 else
24 if(name.charAt(i) == ' ')
25 {
26 i++;
27 c = name.charAt(i);
28 c = Character.toUpperCase(c);
29 name = name.substring(0, i) + c + name.substring(i+1, stringLength);
30 }
31 }
32 JOptionPane.showMessageDialog(null, "Original name was " + saveOriginalName + "\nRepaired name is " + name);
33 }
34
35 }
答案 0 :(得分:3)
来自String.subString(int, int)
javadoc:
public String substring(int beginIndex, int endIndex)
返回一个新的字符串 这个字符串的子串。该 substring从指定的开始 beginIndex并扩展到 索引endIndex处的字符 - 1.因此 子串的长度是 endIndex的-的beginIndex。
继承人:http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#substring(int,int)
如果有疑问,请查看javadoc:D
关于你的第二个问题,charAt(int)
的javadocs(http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#charAt(int))再次帮助你:
抛出:IndexOutOfBoundsException - 如果 index参数是否定的 小于这个字符串的长度。
如果在子字符串中使用i-1
,则每次找到' '
时,名称的大小都会减1。这意味着它将迭代15次,但name
在找到' '
后只有14个字符。
答案 1 :(得分:1)
引用substring
Javadoc,
子字符串从指定的beginIndex开始,并扩展到索引endIndex - 1处的字符。
换句话说,结果中不包含endIndex
。
关于你的第二个问题,它与减少循环内name
的长度有关。您的循环条件(i < stringLength
)以及您查看name.charAt(i)
的事实假设name
的长度保持不变(或至少不减少)。当你开始缩短字符串时,这会被侵犯。
答案 2 :(得分:1)
正确的子串以这种方式工作:
public String substring(int beginIndex, int endIndex)
返回一个新的字符串 这个字符串的子串。该 substring从指定的开始 beginIndex并扩展到 索引endIndex处的字符 - 1.因此 子串的长度是 endIndex的-的beginIndex。
因此对于子串(0,7),它需要来自字符串
的0..6个字符请注意,在for-loop中修改iterate的值是非常糟糕的做法(i ++在for-loop-body中)。如果在太空之后你没有任何其他字符,你将遇到异常
答案 3 :(得分:1)
嗨,你得到了异常,因为你对字符串进行了迭代,但在for循环中你实际上是在改变字符串长度name = name.substring(0,i)+ c + name.substring(i + 1,stringLength); 因此,当您仍处于循环中时,名称的大小不再等于旧的stringLength。
博罗
答案 4 :(得分:1)
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 15 at java.lang.String.charAt(String.java:558) at RepairName.main(RepairName.java:17)
因为您在第21行和第29行更改name
并在name
stringLength
的长度相同而发生
答案 5 :(得分:1)
ad 1)javadocs是一个非常好的引用,这里是java.lang.String.substring(...):
子
public String substring(int beginIndex, int endIndex)
返回一个新字符串,该字符串是此字符串的子字符串。该 substring从指定的开始 beginIndex并扩展到 索引endIndex处的字符 - 1.因此 子串的长度是 endIndex的-的beginIndex。
排除结束索引的好处是,您可以随后迭代值:
a [0] = x.substring (0, 5);
a [1] = x.substring (5, 10);
a [2] = x.substring (10, 15);
// or
a [i] = x.substring (i*5, (i+1)*5);
答案 6 :(得分:1)
ad 2)
您不会自行更改,但name
会在此处被截断:
name = name.substring(0,i-1)+ c + name.substring(i + 1,stringLength);
但是外部循环没有被告知新的长度。
ad 3)(代码审查):
您应该尽可能晚地声明和初始化变量,并尽可能标记最终。这告诉你,在初始化之后你不必担心它们。
鉴于此代码:
import javax.swing.*;
public class RepairName
{
public static void main(String[] args)
{
final String name = JOptionPane.showInputDialog(null, "Please enter your first and last name");
final String saveOriginalName = name;
final int stringLength = name.length ();
System.out.println (name);
for (int i = 0; i < stringLength; i++)
{
final char c = name.charAt (i);
if (i == 0)
{
char upper = Character.toUpperCase (c);
name = upper + name.substring (1, stringLength);
}
else
if (c == ' ')
{
i++;
final char c2 = name.charAt (i);
final char upper = Character.toUpperCase (c2);
name = name.substring (0, i-1) + upper + name.substring (i+1, stringLength);
}
}
JOptionPane.showMessageDialog (null, "Original name was " + saveOriginalName + "\nRepaired name is " + name);
}
}
你会得到一条错误信息,因为名字是最终的。也许这会阻止你意外地与长度不同步。
已修改,具有可变的upName,但迭代名称:
String upName = null;
for (int i = 0; i < stringLength; i++)
{
final char c = name.charAt (i);
if (i == 0)
{
char upper = Character.toUpperCase (c);
upName = upper + name.substring (1, stringLength);
}
else
if (c == ' ')
{
i++;
final char c2 = name.charAt (i);
final char upper = Character.toUpperCase (c2);
upName = upName.substring (0, i-1) + upper + name.substring (i+1, stringLength);
}
}
JOptionPane.showMessageDialog (null, "Original name was " + saveOriginalName + "\nRepaired name is " + upName);
给你输入“honky tonky”输出“HonkyTonky”,它可以引导你前进,子串(从,到)工作,也许。 :)