Directrices de precedencia del operador de Java

La mala interpretación de la precedencia del operador Java es una fuente de preguntas frecuentes y errores sutiles. Me intrigaba saber que incluso la Especificación del lenguaje Java dice: “Se recomienda que el código no dependa de manera crucial de esta especificación”. JLS §15.7 Preferir claro a inteligente , ¿hay alguna guía útil en esta área?

Aquí hay una cantidad de recursos sobre el tema:

  • Operadores JLS
  • Precedencia JLS
  • Glosario de Java
  • Princeton
  • Tutorial de Oracle
  • Conversiones y Promociones
  • Precedencia del operador de Java
  • Orden de evaluación y precedencia
  • Discusión de Usenet

Adiciones o correcciones bienvenidas.

    En lo que respecta al “mundo real”, es probable que sea justo decir:

    • suficientes progtwigdores saben que la multiplicación / división tiene prioridad sobre la sum / resta, ya que matemáticamente es la convención
    • casi ningún progtwigdor puede recordar ninguna de las otras reglas de precedencia

    Entonces, aparte del caso específico de */ vs +- , realmente solo usaría corchetes para definir explícitamente la precedencia deseada.

    Otra fuente relacionada de errores es cómo se acumulan los errores de redondeo. No es un problema de orden de precedencia del operador per se, sino una fuente de sorpresa cuando se obtiene un resultado diferente después de reorganizar los operandos de una manera aritméticamente equivalente. Aquí hay una versión de sun.com de Lo que todo científico informático de David Goldberg debería saber sobre la aritmética de coma flotante .

    La cita (de la Especificación del lenguaje Java §15.7 ) debe leerse en el contexto de la Orden de evaluación . Como se discutió aquí , esa sección se refiere al orden de evaluación , que no está relacionado con la precedencia del operador (o asociatividad ).

    La precedencia y la asociatividad influyen en la estructura del árbol de expresiones (es decir, qué operadores actúan sobre qué operandos), mientras que el “orden de evaluación” simplemente influye en el orden en que se atraviesa el árbol de expresiones cuando se evalúa la expresión. El orden de evaluación (o “orden transversal”) no tiene ningún efecto a menos que algunas sub expresiones tengan efectos colaterales que afecten al resultado (o efectos secundarios) de otras subexpresiones.

    Por ejemplo, si x == 1 inicialmente, la expresión ++x/++x se evaluaría como 2/3 (que se evalúa como 0) ya que Java tiene un orden de evaluación de izquierda a derecha. Si el orden de evaluación en Java hubiera sido de derecha a izquierda, x se habría incrementado dos veces antes de que se evalúe el numerador, y la expresión se habría evaluado como 3/2 (que se evalúa como 1). Si el orden de evaluación no se hubiera definido, la expresión podría haber evaluado cualquiera de estos resultados.

    La cita en cuestión, junto con su contexto, …

    El lenguaje de progtwigción Java garantiza que los operandos de los operadores parecen evaluarse en un orden de evaluación específico, es decir, de izquierda a derecha.

    Se recomienda que el código no dependa de forma crucial de esta especificación. El código suele ser más claro cuando cada expresión contiene como máximo un efecto lateral, ya que su operación más externa

    … disuade al lector de depender de la orientación de izquierda a derecha del orden de evaluación de Java (como en el ejemplo anterior). No fomenta paréntesis innecesarios.

    Editar: Recurso: tabla de precedencia del operador Java que también sirve como un índice en secciones del JLS que contiene la gramática sintáctica de la que se deduce cada nivel de precedencia.

    Además, no te olvides de los logicos && y || son operadores de acceso directo, evite algo como:

     sideeffect1() || sideeffect2() 

    Si sideeffect1 () está evaluando en verdadero, sideeffect2 () no se va a ejecutar. Lo mismo ocurre con && y falso. Esto no está completamente relacionado con la precendencia, pero en estos casos extremos la asimilación también puede ser un aspecto importante que normalmente es realmente irrelevante (al menos en lo que a respecta)

    El JLS no proporciona una tabla de precedencia de operador explícita; está implícito cuando el JLS describe varios operadores. Por ejemplo, la gramática para ShiftExpression es esta:

     ShiftExpression: AdditiveExpression ShiftExpression < < AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression 

    Esto significa que los operadores aditivos ( + y - ) tienen una precedencia mayor que los operadores de desplazamiento asociativos a la izquierda ( < < , >> y >>> ).

    Me parece que la verdad de esto es que “la mayoría de los progtwigdores” piensan que “la mayoría de los otros progtwigdores” no saben o no pueden recordar la precedencia del operador, por lo que se entregan a lo que se llama indulgentemente “progtwigción defensiva” al “insertar el desaparecido” paréntesis ‘, solo para’ aclarar ‘eso. Si recordar estas cosas de tercer grado es un problema real es otra cuestión. Es igualmente discutible que todo esto sea una completa pérdida de tiempo y, en todo caso, empeora las cosas. Mi propia opinión es que la syntax redundante debe evitarse siempre que sea posible, y que los progtwigdores de computadoras deben conocer el lenguaje en el que están progtwigndo, y también quizás elevar las expectativas de sus colegas.