Recursos da linguagem Java 7 com Android

188

Imaginando se alguém tentou usar os novos recursos da linguagem Java 7 com o Android? Eu sei que o Android lê o bytecode que o Java cospe e o transforma em dex. Então, acho que minha pergunta é: ele pode entender o bytecode do Java 7?

Daniel Ryan
fonte
10
Como alternativa, talvez você possa usar os recursos da linguagem Java 7, mas compilar com o bytecode do Java 6?
precisa saber é o seguinte
2
O Android Studio agora fornecerá uma notificação ao criar um novo projeto: "Com minSdkVersion menor que 19, você não pode usar try-with-resources, mas outros recursos da linguagem Java 7 são bons"
IgorGanapolsky
1
Sim, eu sei :) Estamos finalmente usando o Java 7 em nosso projeto.
Daniel Ryan

Respostas:

165

Se você estiver usando Android estúdio , o Java 7 linguagem deve ser ativado automaticamente, sem quaisquer patches. A tentativa com recurso requer o nível 19+ da API e o material NIO 2.0 está ausente.

Se você não pode usar os recursos do Java 7, consulte a resposta do @Nuno sobre como editar o seu build.gradle.

O seguinte é apenas para interesse histórico.


Uma pequena parte do Java 7 certamente pode ser usada com o Android (nota: testei apenas no 4.1).

Primeiro, você não pode usar o ADT do Eclipse porque é codificado permanentemente que apenas os compiladores Java 1.5 e 1.6 são compatíveis. Você pode recompilar o ADT, mas acho que não há uma maneira simples de fazer isso, além de recompilar todo o Android.

Mas você não precisa usar o Eclipse. Por exemplo, o Android Studio 0.3.2 , o IntelliJ IDEA CE e outros IDEs baseados em javac suportam a compilação no Android e você pode definir a conformidade até o Java 8 com:

  • Arquivo → Estrutura do projeto → Módulos → (selecione o módulo no 2º painel) → Nível do idioma → (escolha "7.0 - Diamantes, ARM, capturas múltiplas, etc.")

Ativando o Java 7 no IntelliJ

Isso permite apenas os recursos da linguagem Java 7 e você dificilmente pode se beneficiar de algo, já que metade da melhoria também vem da biblioteca. Os recursos que você pode usar são aqueles que não dependem da biblioteca:

  • Operador de diamante ( <>)
  • Interruptor de cadeia
  • Captura múltipla ( catch (Exc1 | Exc2 e))
  • Sublinhado em números literais ( 1_234_567)
  • Literais binários ( 0b1110111)

E esses recursos ainda não podem ser usados :

  • A tryinstrução -with-resources - porque requer a interface não existente "java.lang.AutoCloseable" (pode ser usada publicamente no 4.4+)
  • A anotação @SafeVarargs - porque "java.lang.SafeVarargs" não existe

... "yet" :) Acontece que, embora a biblioteca do Android esteja direcionada para a versão 1.6, a fonte do Android contém interfaces como AutoCloseable e interfaces tradicionais como Closeable herdam do AutoCloseable (embora SafeVarargs esteja realmente ausente). Nós poderíamos confirmar sua existência através da reflexão. Eles estão ocultos simplesmente porque o Javadoc possui a @hidetag, o que fez com que o "android.jar" não os incluísse.

Já existe uma pergunta existente. Como faço para criar o SDK do Android com APIs ocultas e internas disponíveis? sobre como recuperar esses métodos. Você só precisa substituir a referência "android.jar" existente da plataforma atual pela nossa plataforma personalizada e, em seguida, muitas das APIs do Java 7 ficarão disponíveis (o procedimento é semelhante ao do Eclipse. Verifique Estrutura do projeto → SDKs).

Além do AutoCloseable, (apenas) os seguintes recursos da biblioteca Java 7 também são revelados:

  • Construtores de encadeamento de exceção em ConcurrentModificationException, LinkageError e AssertionError
  • Os métodos estáticos .compare () para primitivos: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Moeda : .getAvailableCurrencies (), .getDisplayName () (mas sem .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Coleções : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • AutoCloseable
  • Throwable : .addSuppressed (), .getSuppressed () e o construtor de 4 argumentos
  • Caractere : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (mas sem .isAlphabetic () e .isIdeographic ())
  • Sistema: .lineSeparator () (não documentado?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Registrador : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : os 3 construtores com "syncFlush".
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () com 4 argumentos

Isso é basicamente tudo. Em particular, o NIO 2.0 não existe e o Arrays.asList ainda não é @SafeVarargs.

kennytm
fonte
2
Ótima resposta. Espero que o suporte completo ao nível de jvm aconteça em breve no futuro, nio2e outros brindes serão definitivamente uma boa notícia.
SD
4
Vale ressaltar que a AutoCloseableinterface não existe no tempo de execução do Android até o ICS (ou talvez até o HoneyComb). Portanto, mesmo se você usar o android.jar corrigido, receberá NoClassDefFoundErrorno sistema 2.x.
Idolon
2
@deviant: que requer modificar o Dalvik VM, já que Java 8 usa lambda invokedynamicque não é suportado pela JVM alvo Java 6.
kennytm
2
Você pode querer adicionar uma atualização que a partir de estúdio Android 3.2, o nível de Língua 7 é totalmente suportado, como é recursos try-com-se você está compilando contra KitKat
JRaymond
4
a tentativa com recursos agora pode ser usada no SDK 19 (Android Kitkat). ver tools.android.com/recent/androidstudio032released
Mohamed El-Nakib
70

EDIT: No momento em que isso foi escrito, a versão mais recente era o Android 9 e o Eclipse Indigo. As coisas mudaram desde então.

  • Resposta prática

Sim, eu tentei. Mas este não é um ótimo teste, pois a compatibilidade foi limitada ao nível 6 sem nenhuma maneira (pelo menos de maneira simples) de realmente usar o java 7:

  • Primeiro, instalei um JDK7 em uma máquina que não tinha outro JDK instalado - o Eclipse e o Android também não estão instalados:

O 7 é o único instalado nesta máquina

  • Então instalei um Eclipse Indigo novinho em folha e verifiquei que ele estava realmente usando o JDK 7 (bem, como esse é o único e como esse que eu selecionei, ficaria surpreso)

O 7 é o único usado por este Eclipse

  • Em seguida, instalei a versão mais recente do Android SDK (EDIT: Honeycomb, API13, no momento em que esta postagem foi escrita). Ele encontrou o meu JDK 7 e foi instalado corretamente. O mesmo para o ADT.

  • Mas tive uma surpresa ao tentar compilar e executar um aplicativo Hello Word para Android. A compatibilidade foi configurada para Java 6 sem nenhuma maneira de forçá-la para Java 7:

A compatibilidade é limitada ao Java 6

  • Eu tentei com um projeto não Android, um Java regular, e eu tive a explicação. O nível de compatibilidade parece ser limitado pelo Eclipse (consulte a mensagem na parte inferior da imagem a seguir):

Eclipse se limita à compatibilidade de nível 6

Então eu tive Olá mundo de trabalho, e também outros aplicativos, mais complicado e usando SQLite, Listview, SensoreCamera , mas isso só prova que a compatibilidade manipulação de Java 7 parece ser bem feito e trabalhar com Android.

Então, alguém tentou com o bom e velho Ant, ignorar a limitação do Eclipse vista acima?

  • Resposta termoética

De qualquer forma, o SDK foi projetado para ser usado com Java 5 ou 6, conforme explicado aqui .

Podemos ter algo trabalhando com o Java 7, mas estaria funcionando "por acidente". A construção do DEX pode funcionar corretamente ou não e, uma vez que o DEX foi construído, ele pode funcionar ou não. Isso porque o uso de um JDK não qualificado fornece resultados imprevisíveis por definição.

Mesmo que alguém tenha criado com êxito um aplicativo Android no Java 7 comum, isso não qualifica o JDK. O mesmo processo aplicado a outro aplicativo pode falhar ou o aplicativo resultante pode ter erros vinculados ao uso desse JDK. Não recomendado.

Para aqueles que estão envolvidos no desenvolvimento de aplicativos da Web, isso é exatamente o mesmo que implantar um aplicativo da Web construído em Java 5 ou 6 em um servidor de aplicativos qualificado apenas para Java 4 (digamos, Weblogic 8, por exemplo). Isso pode funcionar, mas isso não é algo que pode ser recomendado para outros propósitos além de tentar.

Shlublu
fonte
1
Obrigado por essa revisão detalhada. Então parece que você não pode usar Java 7 recursos de linguagem, mas ainda usam Java 7 como Java 6. Esperamos que isso muda em breve :)
Daniel Ryan
Isso é com o Eclipse. Com o Ant, isso provavelmente é possível. Espero que alguém vai fazer o teste e eu me culpo por ser muito preguiçoso para fazê-lo :)
Shlublu
Sim, Varga, mas não acho que a limitação da versão do compilador venha do Ant, mas do Eclipse.
Shlublu 13/11/11
2
Observe também que, se você está brincando com várias versões do Java, as ferramentas fornecidas não são compatíveis. O que quero dizer é que, se você assinou seu aplicativo pela primeira vez com o jarsigner a partir das ferramentas java 6 e depois instalou o java 7 e assinou uma nova versão do nosso aplicativo com o jarsigner que acompanha o java 7 e o mesmo keystore que anteriormente as assinaturas não corresponderiam !
Timo
38

Citação de dalvikvm.com:

O dx, incluído no Android SDK, transforma os arquivos de classe Java das classes Java compiladas por um compilador Java comum em outro formato de arquivo de classe (o formato .dex)

Isso significa que o arquivo de origem .java não importa, é apenas o bytecode .class.

Até onde eu sei, apenas invokedynamic foi incluído no bytecode da JVM no Java 7, o restante é compatível com o Java 6. A linguagem Java em si não usa invokedynamic . Outros novos recursos, como a instrução switch usando String s ou a captura múltipla, são apenas açúcar sintático e não exigiram alterações no código de bytes. Por exemplo, a captura múltipla apenas copia a captura bloco de para cada exceção possível.

O único problema deve ser que as novas classes introduzidas no Java 7 estão ausentes no Android, como o AutoCloseable , por isso não tenho certeza se você pode usar a tentativa recurso -with-resources (alguém tentou?).

Algum comentário sobre isso? Estou esquecendo de algo?

E eu
fonte
2
Agora, o problema é como configuramos esses códigos de origem do Java 7 para compilar os arquivos de classe do Java 6, especialmente no eclipse?
Randy Sugianto 'Yuku'
A única questão que resta é por que você se incomodaria?
Warpzit
@ Warpzit, a grande questão deveria ser: por que um desenvolvedor não se preocupa com toda essa confusão?
Amit
@ Aceite porque ele percebeu que o Android é diferente de Java e, para trabalhar com o Android, ele precisa usar as ferramentas oferecidas.
Warpzit 30/10/12
2
@Warpzit Sua única questão é " Can Android entender java 7? " A ignorância nunca é uma solução / resposta ...
Amit
12

No SDK do Android v15, juntamente com o Eclipse 3.7.1, o Java 7 não é suportado no desenvolvimento do Android. Definir a compatibilidade de origem como 1.7 determina a compatibilidade do arquivo .class gerado como 1.7, o que leva ao seguinte erro do compilador Android:

O Android requer o nível de conformidade do compilador 5.0 ou 6.0. Encontrado '1.7'. Use Ferramentas Android> Corrigir propriedades do projeto.

Hosam Aly
fonte
5

Para expandir a resposta acima por @KennyTM, se você estiver direcionando para a versão 4.0.3 e superior ( minSdkVersion = 15 ), use as APIs ocultas adicionando algumas classes ao android.jar do SDK do seu destino.

Depois de fazer isso, você pode usar try-with-resources em qualquer Closeable, além de implementar o AutoCloseable em suas próprias classes.

Fiz um zip contendo fontes e binários de todas as classes que precisavam ser modificadas no android.jar para disponibilizar essas APIs. Você só precisa descompactá-lo e adicionar os binários ao seu
android-sdk / platform / android-NN / android.jar

Você pode baixá-lo aqui: http://db.tt/kLxAYWbr

Também é importante notar que, nos últimos meses, Elliott Hughes fez alguns comprometimentos com a árvore do Android: finalizou o AutoCloseable , adicionou o SafeVarargs , exibiu várias APIs , corrigiu o construtor protegido da Throwable e adicionou suporte para os arquivos de classe da versão 51 no dx . Então, finalmente há algum progresso.

Editar (abril de 2014):

Com o lançamento do SDK 19, não é mais necessário corrigir o android.jar com as APIs adicionais.

O melhor método para usar a tentativa com recursos no Android Studio para um aplicativo direcionado para 4.0.3 e superior ( minSdkVersion = 15 ) é adicionar o seguinte compileOptionsao seu 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
    }
}

O Android Studio reclamará que a tentativa com recursos não pode ser usada com este nível da API, mas minha experiência é que sim. O projeto será desenvolvido e executado sem problemas em dispositivos com 4.0.3 e superior. Não tive problemas com isso, com um aplicativo que foi instalado em dispositivos com mais de 500k.

Erro no Android Studio

Para ignorar esse aviso, adicione o seguinte ao seu lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>
Nuno Cruces
fonte
1
Acho interessante que o aviso de código do Android Studio diga que o try-with-resources é novo na API 13 e que eu deveria usá-lo. Embora não tenha tempo para realmente testar se está funcionando corretamente.
Daniel Ryan
1

Parece que fazer isso funcionar com formiga pura é meio que um desdém.

Mas funcionou para mim: http://www.informit.com/articles/article.aspx?p=1966024

mako
fonte
1
Eu procurei por isso por um longo tempo. Para reduzir o problema das pessoas através da filtragem no artigo, você precisará alterar a linha `<nome da propriedade =" java.source "value =" 1.5 "/>` no build.xml fornecido pelo android (não aquele em seu projecto!). Para mim foi em /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk
Não, você não. Você pode sobrescrever essas propriedades custom_rules.xml, veja minha resposta aqui: stackoverflow.com/a/24608415/194894
Fluxo
1

Para usar os recursos do Java 7 na criação de código pelo sistema de compilação baseado em formigas do Android, basta colocar o seguinte em seu custom_rules.xml diretório raiz do seu projeto:

custom_rules.xml:

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

Algumas pessoas podem estar interessadas neste projeto git que encontrei, que parece permitir a execução do Java 7 no Android. https://github.com/yareally/Java7-on-Android

No entanto, é muito arriscado se eu adicionar isso no projeto atual em que trabalho. Então, esperarei até o Google oferecer suporte oficial ao Java 7.

Daniel Ryan
fonte