Java 字符串常量上的NullPointerException

Java 字符串常量上的NullPointerException,java,Java,查看其中一个生产webapp的日志(在tomcat6和oracle java 1.6中运行),我发现了以下异常: java.lang.NullPointerException at sso.manager.SimpleRegistrationManager.getCiviliteFromRCUValue(SimpleRegistrationManager.java:536) 以下是getCiviliteFromRCUValue方法: private int getCiviliteFromRCU

查看其中一个生产webapp的日志(在tomcat6和oracle java 1.6中运行),我发现了以下异常:

java.lang.NullPointerException
at sso.manager.SimpleRegistrationManager.getCiviliteFromRCUValue(SimpleRegistrationManager.java:536)
以下是
getCiviliteFromRCUValue
方法:

private int getCiviliteFromRCUValue(final RechercheClient clientInfo)
{
  if (clientInfo == null || clientInfo.getCivilite() == null)
  {
    return 1;
  }
  String civilite = clientInfo.getCivilite().trim();
  if ("mme".equalsIgnoreCase(civilite))
  {
    return 2;
  }
  else if ("mlle".equalsIgnoreCase(civilite))
  {
    return 3;
  }
  else
  {
    return 1;
  }
}
第536行是
if(“mme”.equalsIgnoreCase(civilite))

这个例外怎么可能呢

下面是该方法的字节码(我没有用javap找到该方法,我不知道为什么):

//方法描述符#366(Lpass/sso/rcu/rechercheClient/rechercheClient;)I
//堆栈:2,本地:3
private int getCivilite fromRCUvalue(pass.sso.rcu.rechercheClient.rechercheClient-clientInfo);
0 aload_1[clientInfo]
1如果空11
4 aload_1[客户信息]
5 invokevirtual pass.sso.rcu.rechercheClient.rechercheClient.getCivilite():java.lang.String[142]
8如果非空13
11 iconst_1
12我轮到你了
13 aload_1[客户信息]
14 invokevirtual pass.sso.rcu.rechercheClient.rechercheClient.getCivilite():java.lang.String[142]
17 invokevirtual java.lang.String.trim():java.lang.String[108]
20 astore_2[文明]
21最不发达国家[184]
23 aload_2[文明]
24 invokevirtual java.lang.String.equalsIgnoreCase(java.lang.String):布尔[128]
27 ifeq 32
30 iconst_2
31我返回
32最不发达国家[185]
34 aload_2[文明]
35 invokevirtual java.lang.String.equalsIgnoreCase(java.lang.String):布尔[128]
38 ifeq 43
41 iconst_3
42我返回
43 iconst_1
44我返回
行号:
[个人计算机:0,第531行]
[个人计算机:11,第533行]
[个人计算机:13,第535行]
[个人计算机:21,第536行]
[个人计算机:30,第538行]
[个人计算机:32,第540行]
[个人电脑:41,第542行]
[个人计算机:43,第546行]
局部变量表:
[pc:0,pc:45]本地:此索引:0类型:sso.manager.SimpleRegistrationManager
[pc:0,pc:45]本地:客户端信息索引:1类型:pass.sso.rcu.rechercheClient.rechercheClient
[pc:21,pc:45]本地:civilite索引:2类型:java.lang.String
堆栈映射表:帧数4
[个人资料:11,同上]
[个人资料:13,同上]
[pc:32,追加:{java.lang.String}]
[个人资料:43,同上]

问题可能不是你在问题中说的那一行,而是前一行:

String civilite = clientInfo.getCivilite().trim();
此代码假定
getCivilite()
始终返回非空字符串。只是为了好玩,尝试将其重构为:

String civilite = clientInfo.getCivilite();
if (civilite != null) civilite = civilite.trim();
看看你是否仍然得到了例外


我注意到您正在执行空检查,但我不确定每次调用时是否返回相同的值

我将尝试更改为以下代码:

if (clientInfo == null)
{
    return 1;
}

String civilite = clientInfo.getCivilite();
if (civilite == null)
{
    return 1;
}
civilite = civilite.trim();

...
我们没有看到
getCivilite
方法的代码。我看到过这样的代码:在
get
方法中从数据库检索值,如果无法连接到数据库,该方法返回
null

我知道在你的代码中有类似的东西,可能是第一次调用成功,第二次调用没有成功


举个例子…

即使你说线程不是问题,我也宁愿这样做

private int getCiviliteFromRCUValue(final RechercheClient clientInfo)
{
  if (clientInfo == null) {
    return 1;
  }
  String civilite = clientInfo.getCivilite();
  if (civilite == null) {
    return 1;
  }
  String civiliteTrimmed = civilite.trim();
  if ("mme".equalsIgnoreCase(civiliteTrimmed))
  {
    return 2;
  }
  else if ("mlle".equalsIgnoreCase(civiliteTrimmed))
  {
    return 3;
  }
  else
  {
    return 1;
  }
}
这确保
null
检查和以下值匹配的使用不会使用多个值

如果您有几个
equalsIgnoreCase
检查,最好执行一次
.toLower()
并使用此字符串-如果您使用的是足够新的Java版本,您甚至可以转到
开关

  ...
  switch (civilite.trim().toLower()) {
      case "mme":
          return 2;
      case "mlle":
          return 3;
      default:
          return 1;
  }
}

您能断言该特定日志与该文件的状态匹配吗?(换句话说,文件从那以后有变化吗?)这确实不应该发生。另外,我们可以得到该特定函数的字节码反汇编吗?(filter from javap-cpath/to/class/file)我可以建议问题的作者学习如何使用调试tools@Andremoniy如果异常每六个月发生一次,就像生产应用程序中有时会发生的那样,您不能只使用调试器等待异常的发生。字节码是可以的,所以我想说,回溯肯定偏离了1行。您应该只调用一次getCivilite(),然后null检查结果,如前所述。。。。但是上面的clientInfo.getCivilite()上有一个空检查。
clientInfo.getCivilite()
在方法的第一行被测试为非空。有一个检查-方法的第一行。你确定
getCivilite
每次调用都返回相同的东西吗?@thorstenditmar一次只有一个线程操作
clientInfo
对象,所以我认为可以安全地说是。遗憾的是,它必须在Java1.6上运行,所以字符串上没有开关大小写
  ...
  switch (civilite.trim().toLower()) {
      case "mme":
          return 2;
      case "mlle":
          return 3;
      default:
          return 1;
  }
}