从C#转换后的java代码中的错误

时间:2014-01-03 02:57:10

标签: c# java

这是一个函数在数组中打印重复的int。 在c#:

int [] ReturnDups(int[] a)
{
   int repeats = 0;
   Dictionary<int, bool> hash = new Dictionary<int>();
   for(int i = 0; i < a.Length i++)
   {
       bool repeatSeen;
       if (hash.TryGetValue(a[i], out repeatSeen))
       {
           if (!repeatSeen)
           {
               hash[a[i]] = true;
               repeats ++;
           }
       }
       else
       {
           hash[a[i]] = false;
       }
   }

   int[] result = new int[repeats];
   int current = 0;
   if (repeats > 0)
   {
     foreach(KeyValuePair<int,bool> p in hash)
     {
         if(p.Value)
         {
             result[current++] = p.Key;
         }
     }
   }    
   return result;
} 

现在通过有形软件的工具转换为JAVA。 在java中:

private int[] ReturnDups(int[] a)
{
   int repeats = 0;
   java.util.HashMap<Integer, Boolean> hash = new java.util.HashMap<Integer>();
   for (int i = 0; i < a.length i++)
   {
       boolean repeatSeen = false;
       if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
       {
           if (!repeatSeen)
           {
               hash.put(a[i], true);
               repeats++;
           }
       }
       else
       {
           hash.put(a[i], false);
       }
   }

   int[] result = new int[repeats];
   int current = 0;
   if (repeats > 0)
   {
     for (java.util.Map.Entry<Integer,Boolean> p : hash.entrySet())
     {
         if (p.getValue())
         {
             result[current++] = p.getKey();
         }
     }
   }

   return result;
}

但是findbug发现这行代码是错误的。这对我来说也很奇怪。

if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)

有人可以向我解释一下这行是什么以及如何在java中正确编写它? 感谢

3 个答案:

答案 0 :(得分:1)

您的TryGetValue代码过于复杂 - 这个简单的翻译应该有效:

if ( hash.containsKey(a[i]) ) {
    if (!hash.get(a[i])) {
        hash.put(a[i], true);
    }
} else {
    hash.put(a[i], false);
}

C#有一种获取值的方法和一个标志,告诉你是否在一次调用中找到了值; Java没有类似的API,因为它缺乏通过引用传递变量的能力。

答案 1 :(得分:0)

不要直接转换C#实现。仅当id在那里时才分配repeatSeen值。

if (hash.containsKey(a[i]))
           {
               repeatSeen = hash.get(a[i]).equals(repeatSeen)
               if (!repeatSeen)
               {
                   hash.put(a[i], true);
                   repeats++;
               }
           }

答案 2 :(得分:0)

回答所提出的实际问题:

if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)

确实在语法上是错误的。我还没有查看其余的代码,但是在我的时间里编写了解析器/代码生成器,我猜它应该是

if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen) : false) 

它是无偿的丑陋 - 这通常发生在代码生成器中,尤其是没有优化传递的代码生成器 - 但它在语法上是正确的。让我们看看它是否确实具有明确的含义。

CAVEAT:我没有通过运行它来交叉检查 - 如果有人发现错误,请告诉我!

首先,x?y:z确实是一个三元运算符,Java通过C ++从C继承。它是if-then-else表达式 - 如果xtrue,则其值为y,而如果xfalse则为z值为boolean implied; if (hash.containsKey(a[i]) then implied = (repeatSeen = hash.get(a[i])) == repeatSeen); else implied = false; if(implied) 。所以这个单行代表的意思与:

相同
a=b=0;

......等等。

现在,丑陋的剩余部分是那个和表达的后半部分。我不知道你是否熟悉使用=(赋值)作为表达式运算符;它作为运算符的值与赋给变量的值相同。这主要是为了让你做==之类的事情,但它也可以用来设置变量&#34;传递&#34;在表达的中间。 Hardcore C黑客用它做了一些非常聪明,丑陋的事情(他说是一个)......而且这里用来从哈希表中获取值,将它分配给repeatSeen,然后 - 通过== - 测试与repeatSeen相同的值。

现在的问题是,==的两个参数的评估顺序是什么?如果首先评估左侧,则true必须始终为==,因为分配将在右侧检索值之前进行。如果首先评估右侧,我们会以非常明显的方式将新值与之前的值进行比较。

实际上,还有另一个StackOverflow条目可以解决这个问题:

What are the rules for evaluation order in Java?

根据这一点,Java的规则是运算符的左参数总是在右参数之前求值。因此,第一种情况适用,true始终返回boolean implied; if (hash.containsKey(a[i]) then { repeatSeen = hash.get(a[i])); implied = true; } else implied = false; if(implied)

再次重写我们的翻译以反映它,它变成了

if (hash.containsKey(a[i]) then 
{
  repeatSeen = hash.get(a[i]));
  // and go on to do whatever else was in the body of the original if statement

可以进一步改写为

if

&#34;如果这就是他们的意思,为什么他们不这样写呢?&#34; ......正如我所说,我已经编写了代码生成器,在许多情况下,最简单的方法就是确保你所写的所有片段都是正确的,因为他们正在尝试不要担心它们是否完全像人类所写的那样做同样的事情。特别是,根据模板生成代码很有吸引力,这些模板允许您可能实际不使用的情况,而不是尝试识别更简单的情况并以不同方式生成代码。

我猜测编译器正在绘制并翻译计算位,因为它意识到它需要它们,并且这会在启动if时创建奇怪的嵌套,然后意识到它需要一个条件分配给repeatSeen,并且无论出于何种原因试图在{{1}}的测试中而不是在其体内进行。相信我,我从代码生成器中看到了更糟糕的问题。