Características del lenguaje Java 7 con Android


188

¿Me pregunto si alguien ha intentado usar las nuevas funciones de lenguaje Java 7 con Android? Sé que Android lee el código de bytes que Java escupe y lo convierte en dex. Así que supongo que mi pregunta es ¿puede entender el código de bytes de Java 7?


10
Alternativamente, ¿tal vez pueda usar las características del lenguaje Java 7 pero compilar en código de bytes Java 6?
MatrixFrog

2
Android Studio ahora le enviará una notificación cuando cree un nuevo proyecto: "Con minSdkVersion menor que 19, no puede usar try-with-resources, pero otras características del lenguaje Java 7 están bien"
IgorGanapolsky

1
Sí, lo sé :) Finalmente estamos usando Java 7 en nuestro proyecto.
Daniel Ryan

Respuestas:


165

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

Si no puede usar las características de Java 7, consulte 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 podría usar el ADT de Eclipse porque está codificado que solo el compilador Java 1.5 y 1.6 son compatibles. Podrías recompilar ADT, pero creo que no hay una manera simple de hacerlo, aparte de recompilar todo el Android juntos.

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

  • Archivo → Estructura del proyecto → Módulos → (seleccione el módulo en el segundo panel) → Nivel de idioma → (elija "7.0 - Diamantes, ARM, captura múltiple, etc.")

Habilitar Java 7 en IntelliJ

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

  • Operador de diamantes ( <>)
  • Interruptor de cuerda
  • Captura múltiple ( catch (Exc1 | Exc2 e))
  • Subrayado en literales numéricos ( 1_234_567)
  • Literales binarios ( 0b1110111)

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

  • La trydeclaración -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 está dirigida a 1.6, la fuente de Android contiene interfaces como AutoCloseable e interfaces tradicionales como Closeable hereda de AutoCloseable (sin embargo, SafeVarargs realmente falta). Podríamos confirmar su existencia a través de la reflexión. Están ocultos simplemente porque el Javadoc tiene la @hideetiqueta, lo que provocó que "android.jar" no los incluyera.

Ya existe una pregunta existente ¿ Cómo construyo el SDK de Android con API ocultas e internas disponibles? sobre cómo recuperar esos métodos. Solo necesita reemplazar la referencia "android.jar" existente 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. Verifique la Estructura del Proyecto → SDK).

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

  • Constructores de encadenamiento de excepciones en ConcurrentModificationException, LinkageError y AssertionError
  • Los métodos estáticos .compare () para primitivas: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Moneda : .getAvailableCur Currency (), .getDisplayName () (pero sin .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Colecciones : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • AutoCloseable
  • Throwable : .addSuppressed (), .getSuppressed (), y el constructor de 4-argumento
  • Carácter : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (pero sin .isAlphabetic () y .isIdeographic ())
  • Sistema: .lineSeparator () (¿no documentado?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Registrador : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .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 todavía no es @SafeVarargs.


2
Gran respuesta. Espero que el soporte completo de nivel jvm suceda pronto en el futuro, nio2y otros beneficios definitivamente serán una buena noticia.
SD

44
Vale la pena mencionar que la AutoCloseableinterfaz no existe en el tiempo de ejecución de Android hasta ICS (o tal vez hasta HoneyComb). Entonces, incluso si usa android.jar parcheado, recibirá NoClassDefFoundErroren el sistema 2.x.
Idolon

2
@deviant: eso requiere modificar la máquina virtual Dalvik, ya que Java 8 utiliza lambda invokedynamicque no es compatible con la JVM dirigida a Java 6.
kennytm

2
Es posible que desee agregar una actualización que a partir de Android Studio 3.2, Language level 7 es totalmente compatible, al igual que probar con recursos si está compilando contra KitKat
JRaymond

44
probar con recursos ahora se puede usar en SDK 19 (Android Kitkat). ver tools.android.com/recent/androidstudio032 publicado
Mohamed El-Nakib el

70

EDITAR: en el momento en que esto se escribió, la última versión era Android 9 y Eclipse Indigo. Las cosas han 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 una forma simple) de usar realmente Java 7:

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

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

  • Luego instalé un nuevo Eclipse Indigo y verifiqué 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 utilizado por este Eclipse

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

  • Pero tuve una sorpresa al intentar compilar y ejecutar una aplicación de Android Hello Word. La compatibilidad se estableció en Java 6 sin forma de forzarlo a Java 7:

La compatibilidad está limitada a Java 6

  • Intenté con un proyecto que no es Android, uno normal de Java, 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 al nivel 6 de compatibilidad

Así que tuve Hello World trabajo, y también otras aplicaciones, más complicado y el uso de SQLite, Listview, Sensory Camera, pero esto sólo demuestra que el manejo de la compatibilidad de Java 7 parece estar bien hecho y el trabajo con Android.

Entonces, ¿alguien intentó con la vieja hormiga para evitar la limitación de Eclipse que se ve arriba?

  • Respuesta teórica

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

Es posible que tengamos algo que funcione con Java 7, pero estaría funcionando "por accidente". La construcción del DEX puede funcionar correctamente o no, y una vez que se construye el DEX, puede funcionar o no. Esto se debe a que el uso de un JDK no calificado proporciona resultados impredecibles por definición.

Incluso si alguien ha creado con éxito una aplicación de Android en Java 7, esto no califica el 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 aplicaciones web, esto es exactamente lo mismo que implementar una aplicación web desarrollada en Java 5 o 6 en un servidor de aplicaciones calificado para Java 4 solamente (digamos Weblogic 8, por ejemplo). Esto puede funcionar, pero esto no es algo que pueda recomendarse para otros fines que no sean intentarlo.


1
Gracias por esa revisión detallada. Parece que no puede usar las características del lenguaje Java 7 pero aún usa Java 7 como Java 6. Espero que esto cambie pronto :)
Daniel Ryan

Esto es con Eclipse. Con Ant, esto es probablemente posible. Espero que alguien haga la prueba y me culpo por ser demasiado vago para hacerlo :)
Shlublu

Sí Varga, pero no creo que la limitación de la versión del compilador provenga de Ant sino de Eclipse.
Shlublu

2
También tenga en cuenta que si juega con varias versiones de Java, las herramientas proporcionadas no son compatibles. Lo que quiero decir es que si primero firmó su aplicación con jarsigner de java 6 tools y luego instaló java 7 y firmó una nueva versión de nuestra aplicación con el jarsigner que vino con java 7 y el mismo almacén de claves que antes, las firmas no coincidirían !
Timo

38

Cita de dalvikvm.com:

dx, incluido en el SDK de Android, transforma los archivos Java Class de las clases Java compilados por un compilador Java normal en otro formato de archivo de clase (el formato .dex)

Eso significa que el archivo fuente .java no importa, es solo el código de bytes .class.

Hasta donde yo sé, solo se agregó invocacíno dinámico al código de bytes JVM en Java 7, el resto es compatible con Java 6. El lenguaje Java en sí no usa invocador dinámico . Otras características nuevas, como la instrucción switch que usa String s o la captura múltiple, son solo azúcar sintáctico y no requieren cambios de código de byte. Por ejemplo, la captura múltiple solo copia la captura bloque de para cada posible excepción.

El único problema debería ser que faltan las nuevas clases introducidas en Java 7 en Android, como AutoCloseable , por lo que no estoy seguro de si puede usar el try con recursos (¿alguien lo intentó?).

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


2
Ahora el problema es cómo configuramos de manera que los códigos fuente de Java 7 se compilen en archivos de clase Java 6, especialmente en eclipse.
Randy Sugianto 'Yuku'

La única pregunta que queda es ¿por qué te molestarías?
Warpzit

@Warpzit la pregunta más importante debería ser ¿Por qué un desarrollador no se molestará por toda esta confusión?
Amit

@Amit porque se ha dado cuenta de que Android es diferente de Java y para poder trabajar con Android tiene que usar las herramientas que se ofrecen.
Warpzit

2
@Warpzit Su única pregunta es " ¿Puede Android entender Java 7? " La ignorancia nunca es una solución / respuesta ...
Amit

12

A partir de Android SDK v15, junto con Eclipse 3.7.1, Java 7 no es compatible con el desarrollo de Android. Establecer la compatibilidad de origen en 1.7 exige establecer la compatibilidad del archivo .class generado en 1.7, lo que lleva al siguiente error del compilador de Android:

Android requiere un nivel de cumplimiento del compilador 5.0 o 6.0. Encontró '1.7' en su lugar. Utilice las herramientas de Android> Reparar propiedades del proyecto.


5

Para ampliar la respuesta anterior de @KennyTM, si está apuntando a 4.0.3 y superior ( minSdkVersion = 15 ), puede usar las API ocultas agregando algunas clases al SDK android.jar de su objetivo.

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

He creado un archivo zip que contiene las fuentes y los archivos binarios de todas las clases que deben modificarse en android.jar para que estas API estén disponibles. Solo necesita descomprimirlo y agregar los binarios a su
android-sdk / plataformas / 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 compromisos con el árbol de Android: finalizó AutoCloseable , agregó SafeVarargs , ocultó varias API , arregló el constructor protegido de Throwable y agregó soporte para archivos de clase versión 51 en dx . Entonces, finalmente hay algún progreso.

Editar (abril de 2014):

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

El mejor método para usar try-with-resources en Android Studio para una aplicación que se dirige a 4.0.3 y superior ( minSdkVersion = 15 ) es agregar lo siguiente compileOptionsa 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 probar con recursos no se puede usar con este nivel de API, pero mi experiencia es que sí. El proyecto se compilará 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:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>

1
Me parece interesante que la advertencia de código de Android Studio indique que probar con recursos es nuevo en API 13 y que debería usarlo. Sin embargo, no tengo tiempo para probar si funciona correctamente.
Daniel Ryan

1

Parece que hacer que esto funcione con una hormiga pura es un poco un error.

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


1
Lo busqué por mucho tiempo. Para evitar problemas a las personas al filtrar el artículo, deberá cambiar la línea `<property name =" java.source "value =" 1.5 "/>` en el build.xml que proporciona Android (no el que está en ¡tu proyecto!). Para mí fue en /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk

No, no lo haces. Puede sobrescribir esas propiedades con custom_rules.xml, vea mi respuesta aquí: stackoverflow.com/a/24608415/194894
Flujo

1

Para usar las características de Java 7 en la compilación de código mediante el sistema de compilación basado en hormigas de Android, simplemente ponga lo siguiente en su custom_rules.xmldirectorio raíz de proyectos:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>

0

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 admita oficialmente Java 7.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.