简体   繁体   English

编程新手 - ***更新***实践问题抛出 StringIndexOutOfBoundsException

[英]New to programming - ***Updated*** PracticeProblem throwing StringIndexOutOfBoundsException

I'm trying to teach myself Java and I've recently been doing online practice problems with a built in compiler.我正在尝试自学 Java,最近我一直在用内置编译器做在线练习题。 My code is working great for most of the conditions except for two in which the string length is less than two.除了字符串长度小于 2 的两个条件外,我的代码在大多数情况下都运行良好。

The URL to this specific practice problem is: http://codingbat.com/prob/p123384这个特定练习题的 URL 是: http : //codingbat.com/prob/p123384

Problem: Given a string, return a new string where the first and last chars have been exchanged.问题:给定一个字符串,返回一个新字符串,其中第一个和最后一个字符已交换。

Example例子

frontBack("code") should be→ "eodc"
frontBack("a") should be→ "a"
frontBack("ab") should be→ "ba"

Here's my code:这是我的代码:

    public String frontBack(String str) {

  char firstChar = str.charAt (0);

  char lastChar = str.charAt (str.length()-1);

  String middle = str.substring(1, str.length()-1);

    if (str.length()>=3){

  return lastChar + middle + firstChar;

  }

 else {

return new StringBuilder(str).reverse().toString();

}

}

These are the two conditions that error这是错误的两个条件

frontBack("a") should be→ "a"

"Exception:java.lang.StringIndexOutOfBoundsException: String index out of range: -1 (line number:4)"


frontBack("") should be→ ""

"Exception:java.lang.StringIndexOutOfBoundsException: String index out of range: 0           (line number:2)"

Here's the solution, the code that works这是解决方案,有效的代码

public String frontBack(String str) {
  if (str.length() <= 1) return str;

  String mid = str.substring(1, str.length()-1);

  // last + mid + first
  return str.charAt(str.length()-1) + mid + str.charAt(0);
}

What's the difference between my code and the solution?我的代码和解决方案有什么区别?

Any help would be great.任何帮助都会很棒。 I'm confused on this one since my else statement simply returns the original string.我对此感到困惑,因为我的 else 语句只是返回原始字符串。 Why would any of the variables (frontChar, middle, lastChar) affect the original string I'm returning?为什么任何变量(frontChar、middle、lastChar)会影响我返回的原始字符串? Thanks in advance!提前致谢!

First I want to say thank you to everyone that helped me!*首先我要感谢所有帮助过我的人!*

I've reworked my code and narrowed it down to one simple difference.我重新编写了我的代码并将其缩小到一个简单的区别。 That difference is the placement of an explicit statement to account for strings equal to or less than one.区别在于放置显式语句以说明等于或小于 1 的字符串。 This apparently can't be handled implicitly by a catch-all else statement.这显然不能通过 catch-all else 语句隐式处理。 Still not exactly sure why?仍然不确定为什么? Here is the same code with one minor difference;这是相同的代码,只有一个细微的区别; Explicit vs Implicit显式与隐式

This code works... Explicitly return str if string length is less than or equal to 1.此代码有效...如果字符串长度小于或等于 1,则显式返回 str。

public String frontBack(String str) {

  // This line below is the only difference 

  if (str.length() <= 1) {
   return str;
  }

  char firstChar = str.charAt (0);

  char lastChar = str.charAt (str.length()-1);

  String middle = str.substring(1, str.length()-1);


  if (str.length()>=2){

  return lastChar + middle + firstChar;

  }

  else {
  return str;
  }
}

This code doesn't work... Implicitly return str with an else statement if string length is less than or equal to 1.此代码不起作用...如果字符串长度小于或等于 1,则使用 else 语句隐式返回 str。

public String frontBack(String str) {

  char firstChar = str.charAt (0);

  char lastChar = str.charAt (str.length()-1);

  String middle = str.substring(1, str.length()-1);


  if (str.length()>=2){

  return lastChar + middle + firstChar;

  }

  else {
  return str;
  }
}

You need to program to defend你需要编程来防御


1. 1.

for one character String对于一个字符串

  String middle = str.substring(1, str.length()-1);

this would be这将是

str.substring(1, 0)

which is invalid这是无效的


2. 2.

for empty string ( length = 0 ) your code will attempt to look at index = -1 which is invalid, or even index = 0 is invalid对于空字符串( length = 0 ),您的代码将尝试查看index = -1无效,甚至 index = 0 无效


3. 3.

what if str is null如果strnull怎么办

You always have to think of boundary conditions:你总是要考虑边界条件:

str is null? str 为空? str is empty("") str is 1 char? str 为空("") str 是 1 个字符? also bear in mind that Java's substring is inclusive on start position but exclusive on the end.还请记住,Java 的子字符串在开始位置包含但在结尾不包含。

    public String frontBack(String str) {
      if (str == null || str.length()<2){
          //if str is null - return empty. else return the string itself
          return str == null ? "" : str;
      }else{
         //do the actual first last swap
         return  str.charAt(str.length()-1)+ str.substring(1,str.length()-1) + str.charAt(0);
      } 
    }

I've reworked my code and narrowed it down to one simple difference.我重新编写了我的代码并将其缩小到一个简单的区别。 That difference is the placement of an explicit statement to account for strings equal to or less than one.区别在于放置显式语句以说明等于或小于 1 的字符串。 This apparently can't be handled implicitly by a catch-all else statement.这显然不能通过 catch-all else 语句隐式处理。 Still not exactly sure why?仍然不确定为什么?

It has nothing to do with implicit or explicit.它与隐式或显式无关。 The problem is simply the sequence in which the lines are executed within the method, which is top to bottom.问题只是在方法中执行行的顺序,即从上到下。

By the time it gets to your if/else in the "implicit" case, the three lines above, such as char firstChar = str.charAt(0);当它在“隐式”情况下到达您的 if/else 时,上面的三行,例如char firstChar = str.charAt(0); have already happened (or already failed).已经发生(或已经失败)。 For an empty string it will blow up with a StringIndexOutOfBounds exception immediately on that line (look at the line number of the exception), and the method will stop executing then as it throws the exception out of the method.对于空字符串,它将立即在该行上出现 StringIndexOutOfBounds 异常(查看异常的行号),然后该方法将停止执行,因为它将异常抛出该方法。 (The technical term for this is abrupt completion .) If that exception is thrown, the below if/else won't happen, so it cannot retroactively prevent the exception afterwards. (对此的技术术语是abrupt completion 。)如果抛出该异常,则下面的 if/else 将不会发生,因此它无法在事后追溯防止异常。 That code will work fine if you move the three string-using statements from the top of the method to inside the 'if' branch of the if/else, so that they are not executed when not wanted.如果您将三个使用字符串的语句从方法顶部移动到 if/else 的“if”分支内部,则该代码将正常工作,以便在不需要时不会执行它们。

In the "explicit" case, you added if (str.length() <= 1) return str;在“显式”情况下,您添加了if (str.length() <= 1) return str; at the top of the method, where it can prevent the lines below from executing, because the return statement will exit the method before the attempts to use the non-existent characters of the string.在方法的顶部,它可以阻止下面的行执行,因为return语句将在尝试使用字符串中不存在的字符之前退出方法。 That statement wouldn't help if it was lower down in the method.如果它在方法中较低,那么该声明将无济于事。


I just want to add something about 'null', since other answerers on this page have complained that your code doesn't defend against a null argument.我只想添加一些关于“null”的内容,因为此页面上的其他回答者抱怨您的代码无法抵御 null 参数。 It's good to think about how your method will cope with peculiar input, but here, your code already does correctly defend against a null argument, because when you try to call charAt or length or substring on null, it will throw a NullPointerException out of the method, as it should.考虑一下您的方法将如何处理特殊输入是很好的,但是在这里,您的代码已经正确地防御了 null 参数,因为当您尝试在 null 上调用charAtlengthsubstring时,它将抛出NullPointerException方法,因为它应该。

Sometimes null should be checked for and allowed, but here it should not.有时应该检查并允许空值,但在这里不应该。 If called without a valid string, what might frontBack be expected to return?如果在没有有效字符串的情况下调用, frontBack可能返回什么? Some might say it should return null, some might say it should return the empty string, and some might say it should coerce it to a string and thus return "luln" .有些人可能会说它应该返回 null,有些人可能会说它应该返回空字符串,有些人可能会说它应该将它强制转换为一个字符串,从而返回"luln" There is no fully sensible or unambiguously correct way to handle it that will work for all callers.没有完全合理或明确正确的方法来处理它,适用于所有调用者。 So, frontBack should take the stance that null is not an acceptable input.因此, frontBack应该采取 null 不是可接受的输入的立场。 Then it is the caller's fault if they pass in null, and if the caller passes in garbage, it's correct that they should get the garbage thrown back at them (metaphorically, of course; you will actually throw an exception object, not the original input) so they are forced to deal with it properly.那么如果他们传入null,那是调用者的错,如果调用者传入垃圾,那么他们应该把垃圾扔回他们是正确的(当然,这是比喻;你实际上会抛出一个异常对象,而不是原始输入) 所以他们被迫妥善处理。 Tolerating and making excuses for bad callers by explicitly coercing garbage to valid input is the wrong thing to do because it hides errors and it makes the program's behavior more subtle.通过显式将垃圾强制为有效输入来容忍和为坏调用者找借口是错误的做法,因为它隐藏了错误并使程序的行为更加微妙。

If the method had side effects , such as modifying a data structure, writing to a file, or calling other methods with side effects, then null input could be dangerous, because the method might complete some of the side effects without using str .如果该方法有副作用,例如修改数据结构、写入文件或调用具有副作用的其他方法,则 null 输入可能是危险的,因为该方法可能会在不使用str情况下完成一些副作用。 Then, trying to use str would at some point throw the exception, leaving things half-finished and in an invalid state.然后,尝试使用str会在某个时候抛出异常,使事情未完成并处于无效状态。 Ideally, the side effects should be observed to happen either entirely or not at all.理想情况下,应该观察到副作用完全发生或根本不发生。 In that case, it would be good to check for null and throw the exception yourself at the top of the method:在这种情况下,最好检查 null 并在方法顶部自己抛出异常:

if (str == null) throw new NullPointerException();

That won't make a difference in this simple method because it has no side effects (it is purely functional ) and because it already unconditionally calls methods on str , which will cause the same exception to be thrown anyway.这不会对这个简单的方法产生影响,因为它没有副作用(它纯粹是函数式的)并且因为它已经无条件地调用了str方法,这将导致无论如何抛出相同的异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM