Características del lenguaje Java 7 con Android

¿Me pregunto si alguien ha intentado utilizar las nuevas características del lenguaje Java 7 con Android? Sé que Android lee el bytecode que Java escupe y lo convierte en dex. Entonces, ¿mi pregunta es si puede entender el bytecode de Java 7?

Si está utilizando Android Studio , el lenguaje Java 7 debe habilitarse automáticamente sin ningún parche. Try-with-resource requiere API Level 19+, y faltan cosas de NIO 2.0.

Si no puede usar las características de Java 7, vea la respuesta de @Nuno sobre cómo editar su build.gradle .

Lo siguiente es solo para interés histórico.


Una pequeña parte de Java 7 ciertamente se puede usar con Android (nota: solo he probado en 4.1).

En primer lugar, no se puede usar el ADT de Eclipse porque está codificado de forma rígida que solo el comstackdor de Java 1.5 y 1.6 son compatibles. Podrías recomstackr ADT pero descubro que no hay una manera simple de hacerlo aparte de recomstackr todo el Android.

Pero no necesita usar Eclipse. Por ejemplo, Android Studio 0.3.2 , IntelliJ IDEA CE y otros IDE basados ​​en javac permiten comstackr en Android y usted puede establecer el cumplimiento incluso hasta Java 8 con:

  • Archivo → Estructura del proyecto → Módulos → (elija el módulo en el segundo panel) → Nivel de idioma → (elija “7.0 – Diamantes, BRAZO, captura múltiple, etc.”)

Habilitación de Java 7 en IntelliJ

Esto solo permite las características del lenguaje Java 7, y no puede beneficiarse de nada, ya que una mitad de mejora también proviene de la biblioteca. Las características que puede usar son aquellas que no dependen de la biblioteca:

  • Operador Diamante ( <> )
  • Interruptor de cadena
  • Múltiples capturas ( catch (Exc1 | Exc2 e) )
  • 1_234_567 en literales 1_234_567 ( 1_234_567 )
  • 0b1110111 binarios ( 0b1110111 )

Y estas características no se pueden usar aún :

  • La statement try -with-resources – porque requiere la interfaz no existente “java.lang.AutoCloseable” (esto se puede usar públicamente en 4.4+)
  • La anotación @SafeVarargs – porque “java.lang.SafeVarargs” no existe

… “todavía” 🙂 Resulta que, aunque la biblioteca de Android apunta a 1.6, la fuente de Android contiene interfaces como AutoCloseable y las interfaces tradicionales como Closeable heredan de AutoCloseable (sin embargo, SafeVarargs en realidad está ausente). Podríamos confirmar su existencia a través de la reflexión. Están ocultos simplemente porque Javadoc tiene la etiqueta @hide , lo que provocó que “android.jar” no los incluyera.

Ya existe una pregunta como ¿Cómo creo el SDK de Android con API internas y ocultas disponibles? sobre cómo recuperar esos métodos. Solo necesita reemplazar la referencia existente de “android.jar” de la Plataforma actual con nuestra personalizada, luego muchas de las API de Java 7 estarán disponibles (el procedimiento es similar al de Eclipse. Compruebe la estructura del proyecto → SDK).

Además de AutoCloseable, (solo) las siguientes características de la biblioteca Java 7 también se revelan:

  • Excepción encadenando constructores en ConcurrentModificationException, LinkageError y AssertionError
  • Los métodos static .compare () para primitivos: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Moneda : .getAvailableCurrencies (), .getDisplayName () (pero sin .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Colecciones : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • Autocloseable
  • Lanzable: .addSuppressed (), .getSuppressed () y el constructor de 4 argumentos
  • Carácter : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (pero sin .isAlphabetic () y .isIdeographic ())
  • Sistema: .lineSeparator () (¿indocumentado?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Logger : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSincronizador : .hasQueuedPredecessors ()
  • DeflaterOutputStream : los 3 constructores con “SyncFlush”.
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () con 4 argumentos

Eso es básicamente todo. En particular, NIO 2.0 no existe, y Arrays.asList aún no es @SafeVarargs.

EDITAR: En el momento en que esto fue escrito, el último lanzamiento fue Android 9 y Eclipse Indigo. La cosa ha cambiado desde entonces.

  • Respuesta práctica

Sí, lo he intentado. Pero esta no es una gran prueba, ya que la compatibilidad se limitó al nivel 6 sin ninguna forma (al menos no de manera simple) de usar realmente Java 7:

  • Primero instalé un JDK7 en una máquina que no tenía otro JDK instalado: Eclipse y Android no están instalados:

El 7 es el único instalado en esta máquina

  • Luego instalé un nuevo Eclipse Indigo y comprobé que en realidad estaba usando el JDK 7 (bueno, ya que este es el único y como este es el que he seleccionado, me habría sorprendido)

El 7 es el único usado por este Eclipse

  • Luego instalé la última versión del SDK de Android (EDIT: Honeycomb, API13, en el momento en que se escribió esta publicación). Encontró mi JDK 7 y se instaló correctamente. Lo mismo para ADT.

  • Pero me sorprendí al tratar de comstackr y ejecutar una aplicación de Hello Word para Android. La compatibilidad se estableció en Java 6 sin posibilidad de forzarlo a Java 7:

La compatibilidad está limitada a Java 6

  • Intenté con un proyecto que no es de Android, uno de Java normal, y tuve la explicación. El nivel de compatibilidad parece estar limitado por Eclipse (vea el mensaje en la parte inferior de la siguiente imagen):

Eclipse se limita a la compatibilidad de nivel 6

Así que tenía Hello World funcionando, y también otras aplicaciones, más complicadas y que usaban SQLite , Listview , Sensor y Camera , pero esto solo prueba que el manejo de compatibilidad de Java 7 parece estar bien hecho y funciona con Android.

Entonces, ¿alguien intentó con la buena ant, evitar la limitación de Eclipse vista arriba?

  • Respuesta teórica

De todos modos, el SDK está diseñado para ser utilizado con Java 5 o 6, como se explica aquí .

Es posible que tengamos algo que funcione con Java 7, pero funcionaría “por accidente”. La construcción del DEX puede funcionar correctamente o no, y una vez que se construya el DEX, puede funcionar o no. Esto porque usar un JDK no calificado da resultados impredecibles por definición.

Incluso si alguien ha construido con éxito una aplicación de Android en Java 7, esto no califica al JDK. El mismo proceso aplicado a otra aplicación puede fallar, o la aplicación resultante puede tener errores relacionados con el uso de ese JDK. No recomendado.

Para aquellos que están involucrados en el desarrollo de webapps, esto es exactamente lo mismo que implementar una aplicación web creada bajo Java 5 o 6 bajo un servidor de aplicaciones calificado solo para Java 4 (digamos Weblogic 8, por ejemplo). Esto puede funcionar, pero esto no es algo que pueda recomendarse para otros fines que no sea intentarlo.

Cita de dalvikvm.com:

dx, incluido en el SDK de Android, transforma los archivos de la clase Java de las clases de Java comstackdas por un comstackdor común de Java en otro formato de archivo de clase (el formato .dex)

Eso significa que el archivo fuente .java no importa, es solo el bytecode .class.

Por lo que sé, solo se agregó invookedynamic al bytecode de JVM en Java 7, el rest es compatible con Java 6. El lenguaje de Java en sí no usa invokedynamic . Otras características nuevas, como la instrucción switch que utiliza String o multicaptura, son solo azúcares sintéticos y no requieren cambios en el código de byte. Por ejemplo, la captura múltiple solo copia el locking de captura para cada posible excepción.

El único problema debería ser que las nuevas clases introducidas en Java 7 faltan en Android, como AutoCloseable , así que no estoy seguro de si puedes usar la función try -with-resources (¿alguien lo intentó?).

¿Algún comentario sobre eso? ¿Me estoy perdiendo de algo?

A partir de Android SDK v15, junto con Eclipse 3.7.1, Java 7 no es compatible con el desarrollo de Android. Estableciendo la compatibilidad de la fuente en 1.7 mandatos configurando la compatibilidad del archivo .class generado a 1.7, lo que lleva al siguiente error del comstackdor de Android:

Android requiere el nivel de cumplimiento del comstackdor 5.0 o 6.0. Encontrado ‘1.7’ en su lugar. Utilice Android Tools> Fix Project Properties.

Para ampliar la respuesta anterior con @KennyTM, si tiene como objective 4.0.3 y superior ( minSdkVersion = 15 ), puede usar las API ocultas agregando algunas clases al SDK de su objective android.jar.

Una vez hecho esto, puede usar try-with-resources en cualquier cierre, así como implementar AutoCloseable en sus propias clases.

Creé un archivo comprimido con fonts y binarios de todas las clases que necesitaban modificarse en android.jar para que estas API estuvieran disponibles. Solo tiene que descomprimirlo y agregar los binarios a su
android-sdk / platforms / android-NN / android.jar

Puede descargarlo desde aquí: http://db.tt/kLxAYWbr

También es de destacar que, en los últimos meses, Elliott Hughes ha realizado algunos commits para el árbol de Android: completó AutoCloseable , agregó SafeVarargs , mostró varias API , arregló el constructor protegido de Throwable y agregó soporte para archivos de clase de la versión 51 en dx . Por lo tanto, finalmente está progresando algo.

Editar (abril de 2014):

Con el lanzamiento de SDK 19 ya no es necesario parchar android.jar con las API adicionales.

El mejor método para usar try-with-resources en Android Studio para una aplicación dirigida a 4.0.3 y superior ( minSdkVersion = 15 ) es agregar las siguientes compileOptions a su build.gradle :

 android { compileSdkVersion 19 buildToolsVersion '19.0.3' defaultConfig { minSdkVersion 15 targetSdkVersion 19 } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } } 

Android Studio se quejará de que try-with-resources no se puede usar con este nivel de API, pero mi experiencia es que sí. El proyecto se comstackrá y ejecutará sin problemas en dispositivos con 4.0.3 y superior. No he tenido problemas con esto, con una aplicación que se ha instalado en más de 500k dispositivos.

Error de Android Studio

Para ignorar esta advertencia, agregue lo siguiente a su lint.xml :

    

Parece que hacer que esto funcione con la ant pura es un poco complicado.

Pero funcionó para mí: http://www.informit.com/articles/article.aspx?p=1966024

Para usar las características de Java 7 en la creación de código por el sistema de comstackción basado en ant de Android, simplemente coloque lo siguiente en su custom_rules.xml en su directorio raíz de proyectos:

custom_rules.xml:

     

Algunas personas pueden estar interesadas en este proyecto git que he encontrado, que parece permitir ejecutar Java 7 en Android. https://github.com/yareally/Java7-on-Android

Sin embargo, es demasiado arriesgado si agrego esto en el proyecto actual en el que trabajo. Así que esperaré hasta que Google soporte oficialmente Java 7.