Java 8 para Android código más limpio con expresiones Lambda

Las expresiones Lambda pueden ayudarlo a eliminar el código repetitivo de sus proyectos y procesar grandes cantidades de datos con facilidad. Vea cómo con este análisis en profundidad de las características de Java 8 que puede comenzar a usar hoy en sus proyectos Android. 

Java 8 para Android

Java 8, que debutó en marzo de 2014, fue un gran paso adelante para el lenguaje de programación, al presentar una lista de características que prometían hacer la codificación en Java más fácil y más concisa que nunca..

Desafortunadamente, los desarrolladores de Android no sentirán los beneficios de estas características por un tiempo, ya que Google experimentó con traer Java 8 a la plataforma de Android a través de Jack (Java Android Compiler Kit) antes de despreciar a Jack en favor de admitir Java 8 de forma nativa en Android Studio..

Ahora, con el lanzamiento de Android Studio 3.0, finalmente tenemos una versión de la cadena de herramientas de Android que tiene soporte incorporado para algunas de las características más importantes de Java 8.

En esta serie, le mostraré cómo eliminar una tonelada de código repetitivo de sus proyectos, procesar grandes cantidades de datos con facilidad e incluso adoptar un estilo más funcional en su programación Java con Java 8. Analice en profundidad las características de Java 8 que puede comenzar a usar hoy..

Cuando haya completado esta serie, estará listo para usar todas las siguientes funciones de Java 8 en sus proyectos de Android:

  • expresiones lambda
  • referencias de método
  • métodos por defecto
  • métodos de interfaz estática
  • escriba anotaciones
  • repitiendo anotaciones
  • interfaces funcionales
  • la API de Stream

En esta primera publicación, veremos la característica que generó más zumbidos cuando se lanzó Java 8 por primera vez, y que tiene el potencial de hacer la mayor diferencia para los desarrolladores de Android: expresiones lambda.

Preparación de su entorno de desarrollo

Antes de que puedas comenzar a usar alguna En las características de Java 8, debe asegurarse de que su entorno de desarrollo esté configurado para admitir esta versión de Java.

Si aún no tiene instalado Java 8, deberá descargar la última versión de JDK8 y actualizar la ruta JDK de Android Studio para que apunte al paquete JDK8:

  • Lanzar Android Studio.
  • Seleccionar Archivo> Estructura del proyecto ... de la barra de herramientas de Android Studio.
  • Actualizar el Ubicación de JDK campo para que apunte a su paquete JDK8 recién descargado.

Si no está seguro de qué versión de Java ha instalado, puede verificarlo abriendo una ventana de Terminal (si es un usuario de Mac) o un símbolo del sistema (si está en Windows) y luego ejecutando lo siguiente mando:

java -version

Si devuelve la versión 1.8 o superior, entonces estás listo para comenzar!

También deberá tener instalado Android Studio 3.0 Preview 1 o superior, aunque para reducir las posibilidades de encontrar errores y otros comportamientos extraños, se recomienda instalar la última versión de Android Studio 3.0, ya sea una versión beta o una vista previa o, idealmente, una versión estable de Android Studio 3.0 (que aún no estaba disponible en el momento de la escritura). 

A continuación, deberá realizar algunos cambios en los proyectos de su proyecto. construir.gradle archivos. Por lo general, solo deberá agregar algunas líneas de código que especifican que este proyecto debe generar el código de bytes de Java 8. Sin embargo, si previamente ha experimentado con las características de Java 8 utilizando el compilador Jack o el popular proyecto Retrolambda, deberá deshabilitar estas herramientas antes de que su proyecto pueda usar el nuevo y mejorado soporte de Java 8 provisto por la cadena de herramientas predeterminada de Android..

En las siguientes secciones, le mostraré cómo habilitar el soporte de Java 8 y cómo deshabilitar Retrolambda y Jack, si es necesario.

Adición de soporte de Java 8 a un nuevo proyecto

Suponiendo que no haya habilitado previamente a Jack o agregado Retrolambda como una dependencia de proyecto, el primer paso es abrir su nivel de proyecto construir.gradle y asegúrese de utilizar la versión 3.0.0-alpha1 (o superior) del complemento Gradle para Android:

buildscript repositorios google () jcenter () dependencias classpath 'com.android.tools.build:gradle:3.0.0-alpha6'

A continuación, abra cada nivel de módulo construir.gradle archivo en el que desea utilizar las funciones de Java 8 y configure el nivel de idioma del código fuente y la versión del bytecode Java generado JavaVersion.VERSION_1_8:

android compileSunkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26aspaciosvaccionesvacientesestadecamientaspayaspelicidadcapacidad1placascidad1placas 1 versionName "1.0" testInstrumentationRunner "android.support.provacciones.aspiración. compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Si estás migrando de Jack

El compilador Jack puede estar en desuso, pero mientras esté habilitado, su proyecto usará el soporte Java 8 proporcionado por Jack, en lugar del soporte proporcionado por la cadena de herramientas predeterminada de Android.

Usar una herramienta obsoleta nunca es una buena idea, pero hay algunas razones adicionales por las que debería migrar desde el compilador Jack, si aún no lo ha hecho..

En primer lugar, Jack puede admitir un subconjunto de características de Java 8, pero a diferencia de la cadena de herramientas predeterminada, no admite bibliotecas de terceros que usan estas características, por lo que al usar Jack, usted limita sus opciones de inmediato cuando se trata de bibliotecas de terceros..

En segundo lugar, el compilador Jack toma el código Java y lo convierte directamente en dex, sin producir ningún bytecode intermedio. Mientras Jack esté habilitado, no podrá utilizar ninguna de las herramientas que dependen de esta salida intermedia, como los procesadores de anotación y los analizadores de bytecode..

Para deshabilitar el compilador Jack, abra su nivel de módulo construir.gradle archiva y elimina el jackOptions sección, pero asegúrese de dejar la compileOptions bloque intacto

android compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 recíproco. test.runner.AndroidJUnitRunner "// No elimine la sección compileOptions // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Si estás migrando desde Retrolambda

Al igual que Jack, Retrolambda no admite bibliotecas de terceros que utilizan las características del lenguaje Java 8. Si su proyecto está configurado para usar el complemento Retrolambda, debe eliminar este complemento para que su proyecto pueda volver a la cadena de herramientas predeterminada..

Abre tu nivel de proyecto construir.gradle archivo y eliminar Retrolambda como una dependencia de proyecto:

 dependencias classpath 'com.android.tools.build:gradle:3.0.0-beta2' // Eliminar la siguiente línea // classpath 'me.tatarka: gradle-retrolambda: 3.7.0'

Luego, elimine el complemento Retrolambda de cada uno de sus módulos construir.gradle archivos:  

apply plugin: 'com.android.application' // Elimine la siguiente línea // apply plugin: 'me.tatarka.retrolambda' android … // ¡No elimine el bloque compileOptions! // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Prueba tu soporte de Java 8

La forma más sencilla de verificar que su proyecto ahora puede ser compatible con Java 8 es escribir una expresión lambda rápida y ver si su proyecto aún se compila.

Agregue un botón a su interfaz de usuario (o use un botón que ya exista) y luego implemente un onClickListener para este botón, usando una expresión lambda. No se preocupe si el siguiente código no tiene mucho sentido ahora; lo hará al final de este artículo.!

importar android.support.v7.app.AppCompatActivity; importar android.os.Bundle; importar android.widget.Button; importar android.view.View; importar android.widget.Toast; la clase pública MainActivity extiende AppCompatActivity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Implementar el onClickListener usando una expresión lambda // Botón Button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((vista de vista) -> Toast.makeText (esto, "¡Estaba escrito en Java 8!", Toast.LENGTH_LONG) .show ()); 

Comprueba que tu proyecto aún se compile, ya sea seleccionando Sincronizar desde el banner que aparece, o seleccionando Herramientas> Android> Proyecto de sincronización con archivos Gradle de la barra de herramientas de Android Studio.

Si Android Studio no produce ningún error, entonces está listo para comenzar a usar todas las funciones que enumeramos al principio de este artículo, incluidas las expresiones lambda.!

¿Por qué son tan importantes las expresiones Lambda??

Las expresiones Lambda fueron fácilmente la nueva característica más grande de Java 8, y pueden tener un enorme influye en la cantidad de código repetitivo que necesitas escribir al crear prácticamente cualquier aplicación de Android.

Esencialmente, una expresión lambda representa una función que no pertenece a ninguna clase, y que se puede pasar con facilidad y luego ejecutar bajo demanda..

Esta característica elimina una larga frustración que muchos desarrolladores de Android han experimentado con Java: como lenguaje orientado a objetos, la transferencia de bloques de código siempre Se sintió más difícil de lo que debería ser. Por ejemplo, si desea crear un nuevo hilo y luego pasar algo de código a ese hilo, entonces normalmente tendrá que crear una instancia de un hilo con una implementación anónima de la interfaz de Runnable. ¡Es mucho trabajo solo para pasar algo de código! Al proporcionar una forma fácil de pasar una función a un método, las expresiones lambda tienen el potencial de simplificar algunas de las tareas más comunes que realizará como desarrollador de Android.

Las expresiones Lambda también serán una adición bienvenida para cualquier desarrollador de Java que desee adoptar un enfoque más funcional para su programación. Antes de Java 8, la codificación en un estilo funcional inevitablemente requeriría que escribieras muchos códigos repetitivos, pero ahora que puedes pasar funciones utilizando expresiones lambda, escribir tu código Java de una manera menos orientada a objetos no tiene que implicar escribiendo una tonelada de clases anónimas.

¿Cómo creo una expresión Lambda??

Usted crea una expresión lambda usando la siguiente sintaxis:

(argumento) -> expresión cuerpo

El operador de flecha es bastante autoexplicativo, pero las reglas sobre cómo debe estructurar el argumento y la expresión de la lambda pueden variar según lo que esté tratando de lograr, así que exploremos estos dos elementos con más detalle.

El argumento

El argumento es uno o más parámetros, que son casi Siempre entre paréntesis. Incluso si su expresión lambda no tiene ningún parámetro, deberá proporcionar paréntesis vacíos, por ejemplo:

() -> System.out.println ("Esta expresión lambda no tiene parámetros");

La excepción a esta regla es cuando su método tiene un solo parámetro con su tipo inferido, en cuyo caso puede omitir los paréntesis:

textView.setOnLongClickListener (event -> System.out.println ("Long Click"));

Puede usar múltiples parámetros en su argumento, separando cada parámetro con una coma:

(parámetro1, parámetro2) -> System.out.println ("Parámetros:" + parámetro1 + "," + parámetro2);

La inferencia de tipos es posible en las lambdas, por lo que generalmente puede omitir el tipo de datos de su argumento. Sin embargo, si el compilador no puede inferir el tipo de datos, entonces deberá agregar el tipo al frente de su (s) parámetro (s):

 Button button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((vista de vista) -> Log.d ("debug", "Button clicked")); 

El cuerpo de expresion

El cuerpo de la expresión es el código que desea ejecutar, que puede ser una sola expresión o varias líneas de código. Si desea ejecutar varias líneas, deberá crear un bloque de instrucciones rodeando esta sección de su código con llaves:

Button button = (Button) findViewById (R.id.button); button.setOnClickListener (view -> Log.d ("debug", "Button clicked"); Toast.makeText (este, "¡Estaba escrito en Java 8!", Toast.LENGTH_LONG) .show ();

Si su expresión devuelve un valor, entonces debe devolverse con una declaración de retorno, por ejemplo:

(parámetro1) -> System.out.println ("Parámetro:" + parámetro1); devuelve "valor de retorno"; 

Usando expresiones Lambda en tus aplicaciones Android

Ahora tenemos una visión general de las diversas formas en que puede estructurar una expresión lambda, echemos un vistazo a algunos de los escenarios más comunes en los que puede usar expresiones lambda en su trabajo de desarrollo de Android.

Lambdas para manejo de eventos

Su aplicación típica de Android tiene que ser capaz de responder a una amplia gama de eventos de entrada de usuario, y las expresiones lambda pueden hacer que este evento sea mucho más sencillo.

En el siguiente código, estamos usando una clase anónima para crear una instancia de onClickListener con un anulado al hacer clic método. Lo más probable es que hayas escrito este tipo de código. incontable veces.

Button button = (Button) findViewById (R.id.button); button.setOnClickListener (new View.OnClickListener () @Override public void onClick (Vista de vista) doSomething (););

Al volver a escribir el código anterior con una expresión lambda, podemos eliminar todo lo siguiente:

  • la instanciación de clase: nuevo View.OnClickListener ()
  • El modificador de acceso, el nombre del método y el tipo: Vacío público onClick (Ver vista)
  • y los tipos de parámetros, para que no tenga que escribir Vista vista

Esto significa que podemos implementar exactamente la misma funcionalidad, utilizando una sola línea:

button.setOnClickListener (view -> doSomething ());

Lambdas para multiproceso

El multihilo es otro escenario común donde las expresiones lambda pueden ayudarlo a escribir un código más limpio. De forma predeterminada, Android tiene un único hilo de interfaz de usuario (UI) que se encarga de gestionar todas las interacciones de los usuarios, enviar eventos a los widgets de la interfaz de usuario apropiados y modificar la interfaz de usuario. Tan pronto como bloquee este subproceso de la interfaz de usuario con operaciones de larga duración o intensivas, su aplicación dejará de responder, e incluso puede activar el cuadro de diálogo ANR (aplicación que no responde) de Android. Por lo tanto, la creación de subprocesos adicionales y la asignación de código para ejecutarse en esos subprocesos suele ser una parte esencial del desarrollo de Android..

Antes de Java 8, la asignación de código para ejecutarse en un subproceso adicional requería que creara una clase anónima que implementa el Ejecutable interfaz:

Runnable r = new Runnable () @Override public void run () System.out.println ("My runnable"); ; Hilo de rosca = hilo nuevo (r); thread.start ();

Alternativamente, puede crear una instancia de un nuevo hilo con una implementación anónima de la Ejecutable interfaz:

Thread thread = new Thread (new Runnable () @Override public void run () System.out.println ("My Runnable");); thread.start ();

Reemplazar esta clase anónima con una expresión lambda puede hacer esta tarea frecuentemente realizada mucho más conciso:

Runnable r = () -> System.out.println ("My runnable"); ; // Iniciar el nuevo hilo // nuevo Tema (r) .start ();

Finalmente, si estás usando la biblioteca RxJava o RxAndroid, entonces puedes usar expresiones lambda para ayudarte a crear observables.

Aquí, estamos creando un simple Observable que emite la cadena hola mundoa todos sus Observadores:

Observable.just ("Hello, world!") .Subscribe (nueva Action1() @Override public void call (String s) Log.d (TAG, s); );

Usar una expresión lambda te permite reemplazar todo eso Acción1 código con una sola línea:

Observable.just ("Hello, world!") .Subscribe (s -> Log.d (TAG, s));

Usando expresiones Lambda en su Vida real Código

Después de leer toda la teoría detrás de una nueva característica, el siguiente desafío es adquirir el hábito de realmente utilizando esta nueva característica Esto puede ser particularmente difícil con algo como las lambdas, que están diseñadas para ser usadas en lugar de un código familiar, ya que siempre existe la tentación de simplemente recurrir a lo que sabes.

Android Studio tiene algunas características que pueden ayudarlo a darle ese impulso final para reemplazar el código familiar pero anticuado con nuevas expresiones lambda brillantes.

La primera característica es el menú de acciones de intento de Android Studio, que puede convertir automáticamente cualquier clase anónima compatible en la expresión lambda equivalente. Esto es perfecto si alguna vez no está seguro de cómo escribir un fragmento de código en particular en un formato lambda: simplemente escríbalo como de costumbre y luego use la función de conversión automática del menú de acciones de intención.

Para convertir automáticamente una clase anónima en una expresión lambda:

  • Desplace el cursor sobre la clase anónima, y ​​Android Studio debería mostrar una información sobre herramientas que le informe que puede convertir esta sección de código en una expresión lambda.
  • Presiona tu mac Alt / Opción-Enter teclas, o utilice el Alt-Enter atajo si eres un usuario de Windows o Linux.
  • Selecciona el Reemplazar con lambda Opción desde el menú contextual..


Alternativamente, puede usar la herramienta de inspección de Android Studio para marcar cada Clase anónima que potencialmente podría reemplazar con una expresión lambda en todo su proyecto. Luego puede volver a escribir cada clase anónima manualmente o dejar que la función de conversión automática de Android Studio le muestre cómo se hace..

Para resaltar cada clase anónima que Android Studio podría potencialmente reemplazar con una expresión lambda:

  • Seleccionar Analizar> Ejecutar inspección por nombre de la barra de herramientas de Android Studio.
  • En la ventana emergente que aparece, comienza a escribir Tipo anónimo puede ser reemplazado con lambda, y luego seleccione esta opción cuando aparezca en el menú desplegable.


  • En la ventana siguiente, seleccione Todo el proyecto para marcar cada clase anónima en tu proyecto. Alternativamente, puede especificar módulos o archivos individuales donde Android Studio debería ejecutar esta inspección.
  • Hacer clic DE ACUERDO.
  • Seleccionar Analizar> Inspeccionar Código de la barra de herramientas de Android Studio.

El panel Resultados de la inspección ahora debería aparecer y mostrar una lista de todas las clases anónimas que puede reemplazar con una expresión lambda. Para echar un vistazo más de cerca a una clase anónima, simplemente haga doble clic esa clase en el Resultados de la inspección y Android Studio abrirá el archivo y lo llevará a la línea exacta que contiene esta clase anónima en particular.

Para reemplazar la clase anónima seleccionada actualmente con una expresión lambda, indique la Reemplazar con lambda botón de un clic.


Si Android Studio no abre automáticamente la ventana Resultados de inspección, puede iniciarlo manualmente seleccionando Ver> Ventanas de herramientas> Resultados de inspección desde la barra de herramientas de Android Studio. Si los resultados de la inspección no hace aparecer en el Herramientas de Windows submenú, entonces puede que tenga que seleccionar Analizar> Inspeccionar Código ... de la barra de herramientas de Android Studio primero.

Pruebas de expresiones Lambda

A pesar de los muchos beneficios que ofrecen las expresiones lambda, hay un inconveniente importante que debe tener en cuenta antes de agregarlas a su código. Como las lambdas no tienen un nombre, no puede llamarlas directamente desde el código de prueba, por lo que agregar una gran cantidad de lambdas a su proyecto puede dificultar la prueba..

Lo ideal es que las expresiones lambda sean demasiado simples para romperlas, por lo que no poder realizar una prueba unitaria no debería ser un problema demasiado grande. Sin embargo, si necesita probar un lambda, entonces siempre puede tratarlo como un método privado y probar la unidad Salir, en lugar de la propia lambda. Alternativamente, puede refactorizar la expresión lambda en su propio método, de modo que puede hacer referencia a ella directamente y, por lo tanto, probarlo como normal.  

Conclusión

En esta primera publicación sobre las características del lenguaje Java 8, vimos cómo configurar los proyectos de Android para que sean compatibles con Java 8 y cómo reducir el código de referencia al reemplazar las clases anónimas con expresiones lambda.. 

En la próxima publicación, le mostraré cómo recortar aún más el código de sus proyectos de Android mediante la combinación de expresiones lambda con referencias de métodos, y cómo puede mejorar sus interfaces con los métodos de interfaz predeterminados y estáticos..

Mientras tanto, echa un vistazo a algunas de nuestras otras publicaciones sobre el desarrollo de aplicaciones para Android!