Java 字符串#等于抛出ArrayIndexOutOfBoundException

Java 字符串#等于抛出ArrayIndexOutOfBoundException,java,Java,stacktrace相当长,但这里是相关部分 Caused by: java.lang.ArrayIndexOutOfBoundsException: 33 at java.lang.String.equals(String.java:1018) at java.util.HashMap.get(HashMap.java:305) 因此,当我从HashMap中检索元素时,将调用String#equals。然后,如果(v1[i++]!=v2[j++]) 这真的很糟糕 更新。异常是从日志

stacktrace相当长,但这里是相关部分

Caused by: java.lang.ArrayIndexOutOfBoundsException: 33
  at java.lang.String.equals(String.java:1018)
  at java.util.HashMap.get(HashMap.java:305)
因此,当我从
HashMap
中检索元素时,将调用String#equals。然后,如果(v1[i++]!=v2[j++])

这真的很糟糕


更新。异常是从日志分析程序获取的。我没有在那里使用反射。我还认为字符串对象被破坏了,但没有从代码中得到任何线索。重新启动后,此问题不会重现。如果我继续重试,我不知道它是否会重现

  • LogUtils

    public static Map<String, String> parseLine(String line) {
        if (StringUtils.isEmpty(line)) {
            return Collections.emptyMap();
        }
        String[] parts = StringUtils.split(line, '\t');
        Map<String, String> results = new HashMap<String, String>();
        for (String part : parts) {
            String[] keyVal = StringUtils.split(part, "=", 2);
            if (keyVal.length == 2) {
                String key = keyVal[0];
                String value = keyVal[1];
                results.put(key, value);
            }
        }
        return results;
    }
    
    public static void process(String fileName, Date date, Closure closure) throws IOException {
        InputStream is = null;
        Reader r = null;
        try {
            is = new FileInputStream(getFilename(fileName, date));
            is = new BufferedInputStream(is);
            is = new GZIPInputStream(is);
            r = new InputStreamReader(is, "utf8");
            LineIterator iter = IOUtils.lineIterator(r);
            while (iter.hasNext()) {
                String line = iter.nextLine();
                Map<String, String> map = LogUtils.parseLine(line);
                closure.execute(map);
            }
        } finally {
            IOUtils.closeQuietly(r);
            IOUtils.closeQuietly(is);
        }
    }
    
    公共静态映射解析行(字符串行){
    if(StringUtils.isEmpty(行)){
    return Collections.emptyMap();
    }
    String[]parts=StringUtils.split(第“\t”行);
    映射结果=新的HashMap();
    用于(字符串部分:部分){
    String[]keyVal=StringUtils.split(部分“=”,2);
    如果(keyVal.length==2){
    字符串key=keyVal[0];
    字符串值=keyVal[1];
    结果。输入(键、值);
    }
    }
    返回结果;
    }
    公共静态无效进程(字符串文件名、日期、闭包)引发IOException{
    InputStream=null;
    读取器r=null;
    试一试{
    is=新文件输入流(getFilename(文件名,日期));
    is=新的BufferedInputStream(is);
    is=新的GZIPInputStream(is);
    r=新的InputStreamReader(即“utf8”);
    LineIterator iter=IOUtils.LineIterator(r);
    while(iter.hasNext()){
    String line=iter.nextLine();
    Map Map=LogUtils.parseLine(line);
    closure.execute(map);
    }
    }最后{
    IOUtils.close(r);
    IOUtils.安静地关闭(is);
    }
    }
    
  • 关闭

    public void execute(Map<String, String> line) {
        if (dataMap == null) {
            dataMap = new HashMap<String, Map<Long, Integer>>();
        }
    
        String identifier = line.get(Constants.IDENTIFIER_KEY); // Exception thrown from there
        /* ...blahblah... */
    }
    
    public void execute(映射行){
    if(dataMap==null){
    dataMap=newhashmap();
    }
    String identifier=line.get(Constants.identifier_KEY);//从此处引发异常
    /*……布拉布拉*/
    }
    

  • 为了简单起见,我将创建一个closure对象并用它调用
    LogUtils.process
    。LogUtils将行(例如:
    key1=value1\tkey2=value2\t…kn=valuen
    )拆分为一个
    HashMap
    。然后
    LogUtils
    将映射传递给闭包。异常是从
    line.get(Constants.IDENTIFIER\u KEY)抛出的当Constants.IDENTIFIER_键是静态最终字段时。因此equals方法的lhs和rhs是一个静态的最终字符串,返回值为
    StringUtils.split(第“\t”行)
    。我检查了commons-lang的代码。它实际上是一个
    字符串#子字符串。所以它仍然是正确的。

    这基本上表明有什么东西正在破坏字符串对象。很容易复制:

    import java.lang.reflect.*;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            String x = "hello";
            String y = new String("xhell");
    
            Field field = String.class.getDeclaredField("offset");
            field.setAccessible(true);
            field.set(y, 1);
            System.out.println(x.equals(y));
        }
    }
    

    。。。但我们不知道在您的情况下,字符串是否真的是这样损坏的。

    这表明i或j超出了该数组的限制。@veer:我不这么认为。想象一下如果
    n
    以0开头。。。有了你的版本,它永远不会终止。@yegong你能给我们看更多的代码吗?e、 g.插入和访问
    映射的内容
    @JonSkeet等代码方法不是我的实现。它是Java1.6的源代码。@rhyon没问题。但它是java.lang.String#equals。此处不应出现ArrayIndexOutOfBoundException。我粘贴的代码没有反射。我同意损坏的字符串对象。但是,代码似乎非常简单,没有任何东西试图打开字符串并修改最终字段。
    import java.lang.reflect.*;
    
    public class Test {
        public static void main(String[] args) throws Exception {
            String x = "hello";
            String y = new String("xhell");
    
            Field field = String.class.getDeclaredField("offset");
            field.setAccessible(true);
            field.set(y, 1);
            System.out.println(x.equals(y));
        }
    }