明星猜猜猜(Name that Celebrity)

陈 欣发布

明星猜猜猜是一个针对基本String操作的Java小项目。美国孩子可能会很喜欢,但中国孩子一般不大感冒。

要求是对于类似这样的明星名字:

Allan Alda
John Wayne
Gregory Peck

能够输出为这样的题目:

Allan Alda>>>lan A
John Wayne>>>hn Wa
Gregory Peck>>>egory P

然后根据半截名字猜出是哪个明星……


解题的话首先需要把规律分析出来,这个和那种小学奥数题目也有点类似,需要找一下共同的规律。第一行l,第二行h,第三行e,都是原来名字的第三个字母。那么结尾的话,正着数好像有点不一致,倒着数的话,就会发现是倒数第四个字母。确实不难。

对于Java的String,有一些特殊之处需要初学者注意。

可以看到String的index从0开始。所以第三个字母对应的index其实是2。同理执行length()的结果会是10,那么事实上根据substring()定义endIndex应为7,即length()-3。意思就是把index从7开始的部分切掉。

NameCelebrity.java

public class NameCelebrity {
  public static String name(String name) {
    return name.substring(2, name.length()-3);
  }

  public static void main(String[] args) {
    String s1 = "Allan Alda";
    String s2 = "John Wayne";
    String s3 = "Gregory Peck";
    System.out.println(s1 + ">>>" + name(s1));
    System.out.println(s2 + ">>>" + name(s2));
    System.out.println(s3 + ">>>" + name(s3));
  }
}

首先注意我们定义了一个name(),这样就不需要把这个String变换的过程重复三遍(或者在真实案例里重复n遍)。我们定义函数是static的,这样不需要instantiation也可以在main()里调用。

其次name.substring()其实本身是一个与name不同的新String,这样后面实际上可以同样继续无限制的加上一系列针对String的操作。比如继续substring()或者toUpperCase()等等,非常灵活。

还有一个小点就是println()里面的+并不是我们通常意义上的加号,在这里执行的是合并String的concatenation操作。请避免将其与算数+混合起来。比如实际执行

1 + "1"

的时候,输出的结果会是"11"而不是"2"或者2。事实上Java compiler内部执行的操作是先调用IntegertoString(),然后执行concatenation。而不是反过来把"1"这个StringparseInt()转成Integer


当然对于真正的软件工程师而言,以上的代码是完全错误的。考虑到以下这种情况:

NameCelebrity.java

public class NameCelebrity {
  public static String name(String name) {
    return name.substring(2, name.length()-3);
  }

  public static void main(String[] args) {
    String s1 = "";
    String s2 = "John Wayne";
    String s3 = "Gregory Peck";
    System.out.println(s1 + ">>>" + name(s1));
    System.out.println(s2 + ">>>" + name(s2));
    System.out.println(s3 + ">>>" + name(s3));
  }
}

就会发现当输入不合法时,整个程序会因为String index out of range而在未执行完工作前就强制退出了。勉强可以接受的做法是以下这样:

public class NameCelebrity {
  public static String name(String name) {
    try{
      return name.substring(2, name.length()-3);
    }
    catch(Exception e){
      return "";
    }
  }

  public static void main(String[] args) {
    String s1 = "";
    String s2 = "John Wayne";
    String s3 = "Gregory Peck";
    System.out.println(s1 + ">>>" + name(s1));
    System.out.println(s2 + ">>>" + name(s2));
    System.out.println(s3 + ">>>" + name(s3));
  }
}

对于Exception实际开发里有不同的处理方法。像我们这个例子里是可以无视然后继续工作的。如果是造成严重软件错误(比如内存泄漏)或者硬件错误(比如显卡像显示器发送硬件不支持的刷新频率),需要立即终止程序(见过Windows 10蓝屏(BSOD)没?)。如果是可能造成用户数据丢失(比如Word崩溃),需要尽最大可能保存用户数据。如果是在原子操作(比如银行转账,从我账户里扣了钱但是还没有把钱打到你账户里)过程中出现,需要把整个操作回滚到初始状态(不然我的钱就蒸发了……)。


陈 欣

AADPS创始人