Kotlin ( / ˈ k ɒ t l ɪ n / ) [2] es un lenguaje de programación multiplataforma de alto nivel , de tipo estático y de propósito general con inferencia de tipos . Kotlin está diseñado para interoperar completamente con Java , y la versión JVM de la biblioteca estándar de Kotlin depende de la biblioteca de clases de Java , pero la inferencia de tipos permite que su sintaxis sea más concisa. Kotlin se dirige principalmente a JVM, pero también compila en JavaScript (por ejemplo, para aplicaciones web frontend que usan React ) [3] o código nativo a través de LLVM (por ejemplo, para aplicaciones nativas de iOS que comparten lógica empresarial con aplicaciones de Android ). [4] Los costos de desarrollo del lenguaje corren a cargo de JetBrains , mientras que la Fundación Kotlin protege la marca Kotlin. [5]
El 7 de mayo de 2019, Google anunció que el lenguaje de programación Kotlin era ahora su lenguaje preferido para los desarrolladores de aplicaciones de Android . [6] Desde el lanzamiento de Android Studio 3.0 en octubre de 2017, Kotlin se ha incluido como una alternativa al compilador estándar de Java. El compilador Kotlin de Android produce código de bytes de Java 8 de forma predeterminada (que se ejecuta en cualquier JVM posterior), pero permite al programador elegir apuntar a Java 9 hasta 20, para optimización, [7] o permite más funciones; tiene soporte de interoperabilidad de clases de registro bidireccional para JVM, introducido en Java 16, considerado estable a partir de Kotlin 1.5.
Kotlin tiene soporte para la web con Kotlin/JS, ya sea a través de un backend clásico basado en intérprete que ha sido declarado estable desde la versión 1.3, o un backend basado en representación intermedia que ha sido declarado estable desde la versión 1.8. Kotlin/Native (por ejemplo, compatibilidad con Apple Silicon ) se considera beta desde la versión 1.3. [8] [9]
El nombre se deriva de la isla Kotlin , una isla rusa en el golfo de Finlandia , cerca de San Petersburgo . Andrey Breslav, ex diseñador principal de Kotlin, mencionó que el equipo decidió ponerle el nombre de una isla, al igual que el lenguaje de programación Java recibió su nombre de la isla indonesia de Java [10] (aunque se dice que el nombre del lenguaje se inspiró en " java" el término del argot americano para el café, [11] que a su vez se deriva del nombre de la isla). [12]
En julio de 2011, JetBrains presentó el Proyecto Kotlin, un nuevo lenguaje para JVM, que había estado en desarrollo durante un año. [13] El líder de JetBrains, Dmitry Jemerov, dijo que la mayoría de los lenguajes no tenían las características que buscaban, con la excepción de Scala . Sin embargo, citó el lento tiempo de compilación de Scala como una deficiencia. [13] Uno de los objetivos declarados de Kotlin es compilar tan rápido como Java. En febrero de 2012, JetBrains abrió el proyecto bajo la licencia Apache 2 . [14]
JetBrains esperaba que el nuevo lenguaje impulsara las ventas de IntelliJ IDEA . [15]
El primer compromiso con el repositorio Kotlin Git fue el 8 de noviembre de 2010. [16]
Kotlin 1.0 se lanzó el 15 de febrero de 2016. [17] Esta se considera la primera versión oficialmente estable y JetBrains se ha comprometido a ofrecer compatibilidad con versiones anteriores a largo plazo a partir de esta versión.
En Google I/O 2017, Google anunció soporte de primera clase para Kotlin en Android . [18]
Kotlin 1.2 se lanzó el 28 de noviembre de 2017. [19] La función para compartir código entre plataformas JVM y JavaScript se agregó recientemente a esta versión (la programación multiplataforma es ahora una función beta [20] actualizada desde "experimental"). Se ha realizado una demostración completa con el nuevo complemento Kotlin/JS Gradle. [21] [22]
Kotlin 1.3 se lanzó el 29 de octubre de 2018 y agregó soporte para corrutinas para usar con programación asincrónica. [23]
El 7 de mayo de 2019, Google anunció que el lenguaje de programación Kotlin es ahora su lenguaje preferido para los desarrolladores de aplicaciones de Android. [6]
Kotlin 1.4 se lanzó en agosto de 2020, con, por ejemplo, algunos ligeros cambios en la compatibilidad con las plataformas de Apple, es decir, en la interoperabilidad Objective-C / Swift . [24]
Kotlin 1.5 se lanzó en mayo de 2021.
Kotlin 1.6 se lanzó en noviembre de 2021.
Kotlin 1.7 se lanzó en junio de 2022, incluida la versión alfa del nuevo compilador Kotlin K2 . [25]
Kotlin 1.8 se lanzó en diciembre de 2022, 1.8.0 se lanzó el 11 de enero de 2023. [26]
Kotlin 1.9 se lanzó en julio de 2023, 1.9.0 se lanzó el 6 de julio de 2023. [27]
Kotlin 2.0 se lanzó en mayo de 2024, 2.0.0 se lanzó el 21 de mayo de 2024. [28]
El líder de desarrollo, Andrey Breslav, ha dicho que Kotlin está diseñado para ser un lenguaje industrial orientado a objetos y un "mejor lenguaje" que Java , pero aún así ser totalmente interoperable con el código Java, lo que permitirá a las empresas realizar una migración gradual de Java a Kotlin. . [29]
Tomando prestado de Scala , el punto y coma es opcional como terminador de declaración ; en la mayoría de los casos, una nueva línea es suficiente para que el compilador deduzca que la declaración ha finalizado. [30]
Tomando prestado de Scala , las declaraciones de variables y listas de parámetros de Kotlin tienen el tipo de datos después del nombre de la variable (y con un separador de dos puntos ), similar a Ada , BASIC , Pascal , TypeScript y Rust . Esto, según un artículo de Roman Elizarov, líder actual del proyecto, da como resultado la alineación de los nombres de las variables y es más agradable a la vista, especialmente cuando hay algunas declaraciones de variables seguidas y uno o más de los tipos es demasiado complejo para el tipo. inferencia, o debe declararse explícitamente para que los lectores humanos lo entiendan. [31] [32]
Tomando prestado de Scala , las variables en Kotlin pueden ser de solo lectura, declaradas con la palabra clave val , o mutables , declaradas con la palabra clave var . [33]
Tomando prestado de Scala , los miembros de la clase son públicos de forma predeterminada y las clases mismas son finales de forma predeterminada, lo que significa que la creación de una clase derivada está deshabilitada a menos que la clase base se declare con la palabra clave open .
Además de las clases y funciones miembro (que son equivalentes a métodos) de la programación orientada a objetos, Kotlin también admite la programación procedimental con el uso de funciones . [34] Las funciones y constructores de Kotlin admiten argumentos predeterminados , listas de argumentos de longitud variable , argumentos con nombre y sobrecarga mediante firma única. Las funciones de los miembros de la clase son virtuales, es decir, se distribuyen según el tipo de tiempo de ejecución del objeto al que se invocan.
Kotlin 1.3 agregó soporte para contratos, [35] que son estables para las declaraciones de biblioteca estándar, pero aún experimentales para declaraciones definidas por el usuario. Los contratos están inspirados en el paradigma de programación de diseño por contrato [36] de Eiffel .
Siguiendo a ScalaJS, el código Kotlin se puede transpilar a JavaScript , lo que permite la interoperabilidad entre el código escrito en los dos lenguajes. Esto se puede utilizar para escribir aplicaciones web completas en Kotlin o para compartir código entre un backend de Kotlin y un frontend de JavaScript. [37]
Kotlin relaja la restricción de Java de permitir que existan métodos y variables estáticos solo dentro del cuerpo de una clase. Los objetos y funciones estáticos se pueden definir en el nivel superior del paquete sin necesidad de un nivel de clase redundante. Para compatibilidad con Java, Kotlin proporciona una JvmName
anotación que especifica un nombre de clase utilizado cuando el paquete se ve desde un proyecto Java. Por ejemplo, @file:JvmName("JavaClassName")
.
Como en C , C++ , C# , Java y Go , el punto de entrada a un programa Kotlin es una función denominada "principal", a la que se le puede pasar una matriz que contiene cualquier argumento de línea de comandos . Esto es opcional desde Kotlin 1.3. [38] Se admite la interpolación de cadenas estilo shell Perl , PHP y Unix . También se admite la inferencia de tipos .
// ¡Hola Mundo! ejemplodiversión principal () { alcance val = "Mundo" println ( "Hola, $ alcance !" )}diversión principal ( argumentos : Matriz <Cadena> ) { para ( arg en argumentos ) imprimirln ( arg )}
Al igual que C#, Kotlin permite agregar una función de extensión a cualquier clase sin las formalidades de crear una clase derivada con nuevas funciones. Una función de extensión tiene acceso a todas las interfaces públicas de una clase, que puede usar para crear una nueva interfaz de función para una clase de destino. Una función de extensión aparecerá exactamente como una función de la clase y se mostrará en la inspección de finalización del código de las funciones de clase. Por ejemplo:
paquete MyStringExtensions cadena divertida . lastChar (): Char = obtener ( longitud - 1 ) >>> println ( "Kotlin" . últimocarácter ())
Al colocar el código anterior en el nivel superior de un paquete, la clase String se extiende para incluir una lastChar
función que no estaba incluida en la definición original de la clase String.
// Sobrecarga del operador '+' usando una función de extensiónpunto de diversión del operador . más ( otro : Punto ): Punto { Punto de retorno ( x + otro . x , y + otro . y ) }>>> valor p1 = Punto ( 10 , 20 ) >>> val p2 = Punto ( 30 , 40 ) >>> imprimirln ( p1 + p2 ) Punto ( x = 40 , y = 60 )
De manera similar a Python, el operador de extensión asterisco (*) descomprime el contenido de una matriz como argumentos individuales para una función, por ejemplo:
diversión principal ( argumentos : Matriz <Cadena> ) { val lista = listaDe ( "argumentos: " , * argumentos ) println ( lista )}
Las declaraciones de desestructuración descomponen un objeto en múltiples variables a la vez; por ejemplo, un objeto de coordenadas 2D podría desestructurarse en dos números enteros, x e y .
Por ejemplo, el Map.Entry
objeto admite la desestructuración para simplificar el acceso a sus campos clave y valor:
para (( clave , valor ) en el mapa ) println ( " $ clave : $ valor " )
Kotlin permite declarar funciones locales dentro de otras funciones o métodos.
usuario de clase ( id val : Int , nombre val : cadena , dirección val : cadena ) divertido saveUserToDb ( usuario : Usuario ) { validación divertida ( usuario : usuario , valor : cadena , nombre de campo : cadena ) { require ( value . isNotEmpty ()) { "No se puede guardar el usuario ${ user . id } : vacío $ fieldName " } } validar ( usuario , usuario . nombre , "Nombre" ) validar ( usuario , usuario . dirección , "Dirección" ) //Guardar usuario en la base de datos ...}
En Kotlin, para derivar una nueva clase a partir de un tipo de clase base, la clase base debe marcarse explícitamente como "abierta". Esto contrasta con la mayoría de los lenguajes orientados a objetos, como Java, donde las clases están abiertas de forma predeterminada.
Ejemplo de una clase base que está abierta a derivar una nueva subclase a partir de ella:
// abrir en la clase significa que esta clase permitirá clases derivadasclase abierta MegaButton { // no abrir una función significa que // comportamiento polimórfico deshabilitado si la función se anula en la clase derivada diversión desactivar () { ... } // abrir en una función significa que // se permite el comportamiento polimórfico si la función se anula en la clase derivada abrir diversión animar () { ... } }clase GigaButton : MegaButton () { // Se requiere uso explícito de la palabra clave override para anular una función en una clase derivada anular diversión animate () { println ( "¡Giga Click!" ) } }
Las clases abstractas definen funciones de marcador de posición abstractas o "virtuales puras" que se definirán en una clase derivada. Las clases abstractas están abiertas de forma predeterminada.
// No es necesaria la palabra clave open aquí, ya está abierta de forma predeterminadaclase abstracta animada { // Esta función virtual también está abierta por defecto abstracto divertido animado () abrir divertido stopAnimating () { } diversión animateTwice () { } }
Kotlin proporciona las siguientes palabras clave para restringir la visibilidad de las declaraciones de nivel superior, como las clases, y de los miembros de la clase: public
, internal
, protected
y private
.
Cuando se aplica a un miembro de la clase:
Cuando se aplica a una declaración de nivel superior:
Ejemplo:
// La clase es visible sólo para el módulo actualTalkativeButton de clase abierta interna { // el método sólo es visible para la clase actual grito de diversión privada () = println ( "¡Oye!" ) // el método es visible para la clase actual y las clases derivadas susurro divertido protegido () = println ( "¡Hablemos!" ) }clase interna MyTalkativeButton : TalkativeButton () { divertido absoluto () = súper . susurro () }Mi botón hablador (). absoluto ()
Kotlin admite la especificación de un "constructor primario" como parte de la definición de la clase misma, que consta de una lista de argumentos después del nombre de la clase. Esta lista de argumentos admite una sintaxis ampliada en las listas de argumentos de funciones estándar de Kotlin que permite la declaración de propiedades de clase en el constructor principal, incluidos los atributos de visibilidad, extensibilidad y mutabilidad. Además, al definir una subclase, las propiedades de las superinterfaces y superclases se pueden anular en el constructor principal.
// Ejemplo de clase que utiliza la sintaxis del constructor primario// (Sólo se requiere un constructor para esta clase)clase abierta BaseUser ( open var isSubscribed : booleano ) clase abierta PowerUser ( apodo de val protegido : Cadena , anulación final var isSubscribed : Boolean = true ): BaseUser ( isSubscribed ) { }
Sin embargo, en los casos en los que se necesita más de un constructor para una clase, se puede definir un constructor más general utilizando la sintaxis del constructor secundario , que se parece mucho a la sintaxis del constructor utilizada en la mayoría de los lenguajes orientados a objetos como C++, C# y Java.
// Ejemplo de clase que utiliza la sintaxis del constructor secundario// (se requiere más de un constructor para esta clase)contexto de clase conjunto de atributos de clase Vista de clase abierta ( ctx : Contexto ) { constructor ( ctx : Contexto , attr : AttributeSet ): esto ( ctx ) }clase MiBotón : Ver { // Constructor #1 constructor ( ctx : contexto ) : super ( ctx ) { } // Constructor #2 constructor ( ctx : contexto , atributo : conjunto de atributos ) : super ( ctx , atributo ) { //... }}
Las clases e interfaces selladas restringen las jerarquías de subclases, lo que significa más control sobre la jerarquía de herencia.
Declaración de interfaz y clase sellada:
interfaz sellada Expr trabajo de clase sellada
Todas las subclases de la clase sellada se definen en el momento de la compilación. No se le pueden agregar nuevas subclases después de la compilación del módulo que tiene la clase sellada. Por ejemplo, una clase sellada en un archivo jar compilado no se puede subclasificar.
Vehículo clase sellada clase de datos Coche ( val brandName : Cadena , val propietario : Cadena , val color : Cadena ): Vehículo () clase Bicicleta ( val marcaNombre : Cadena , val propietario : Cadena , val color : Cadena ): Vehículo () clase Tractor ( val marcaNombre : Cadena , val propietario : Cadena , val color : Cadena ): Vehículo () val kiaCar = Coche ( "KIA" , "John" , "Azul" ) val hyundaiCar = Coche ( "Hyundai" , "Britto" , "Verde" )
La construcción de Kotlin data class
define clases cuyo propósito principal es almacenar datos, similares a los tipos de Java record
. Al igual que los tipos de Java record
, la construcción es similar a las clases normales equals
, excepto que los métodos clave hashCode
se toString
generan automáticamente a partir de las propiedades de la clase; a diferencia de los registros, las clases de datos están abiertas a la herencia.
En Java, se espera que las clases proporcionen implementaciones para ciertos métodos estándar, de modo que funcionen correctamente con los métodos y clases proporcionados por la biblioteca estándar. La implementación predeterminada de Java, que cada clase hereda de la base de la jerarquía de clases, Object
implementa estos métodos sólo con respecto a la identidad de la instancia del objeto (normalmente su dirección en la memoria virtual ). [39] [40] Esto es un problema, ya que es extremadamente importante
(a) tener información sobre el estado del objeto en su representación String ( toString
) y
(b) detectar si dos objetos son similares ( equals
y hashCode
). Las implementaciones de los dos últimos también deben coincidir entre sí y, por lo tanto, implementarse juntas; es decir, cuando se cambia una, la otra también debe cambiarse para que coincida. La implementación de esta funcionalidad también aumenta la eficiencia de los algoritmos estándar que dependen de su comportamiento correcto. [41] Por el contrario, las implementaciones incorrectas pueden incluso provocar errores. [39]
Dado que la implementación de estos métodos manualmente o con herramientas externas es engorrosa y a menudo genera código repetido o repetitivo , su generación automática como característica del lenguaje acelera el desarrollo y reduce la posibilidad de errores.
$ tipo kotlinc-jvm : ayuda para obtener ayuda; :quit para salir >>> 2 + 2 4 >>> println ( "¡Hola mundo!" ) ¡Hola mundo!
Kotlin también se puede utilizar como lenguaje de programación. Un script es un archivo fuente de Kotlin que utiliza la extensión de nombre de archivo .kts , con código fuente ejecutable en el nivel superior:
// lista_carpetas.ktsimportar archivo java.io. carpetas val = Archivo ( args [ 0 ] ). listFiles { archivo -> archivo . esDirectorio () } carpetas ?. para cada uno ( :: println )
Los scripts se pueden ejecutar pasando la -script
opción y el archivo de script correspondiente al compilador.
$ kotlinc -script list_folders.kts "ruta_a_carpeta_a_inspeccionar"
Kotlin hace una distinción entre tipos de datos que aceptan valores NULL y que no admiten NULL. Todos los objetos que aceptan valores NULL deben declararse con un "?" postfix después del nombre del tipo. Las operaciones con objetos que aceptan valores NULL necesitan un cuidado especial por parte de los desarrolladores: se debe realizar una verificación de nulos antes de usar el valor, ya sea explícitamente o con la ayuda de los operadores seguros para NULL de Kotlin:
// devuelve nulo si...// - foo() devuelve nulo,// - o si foo() no es nulo, pero bar() devuelve nulo,// - o si foo() y bar() no son nulos, pero baz() devuelve nulo.// viceversa, el valor de retorno no es nulo si y sólo si foo(), bar() y baz() no son nulosfoo () ?. bar () ?. baz ()
divertido decir Hola ( tal vez : Cadena?, nunca Nulo : Int ) { // uso del operador Elvis nombre val : Cadena = ¿quizás ?: "extraño" println ( "Hola $ nombre " )}
Kotlin brinda soporte para funciones de orden superior y funciones anónimas o lambdas . [42]
// la siguiente función toma una lambda, f, y ejecuta f pasándole la cadena "lambda"// tenga en cuenta que (Cadena) -> Unidad indica una lambda con un parámetro Cadena y tipo de retorno Unidaddivertido ejecutarLambda ( f : ( Cadena ) -> Unidad ) { f ( "lambda" )}
Las lambdas se declaran usando llaves, { } . Si una lambda toma parámetros, se declaran entre llaves y seguidos del operador -> .
// la siguiente declaración define una lambda que toma un único parámetro y lo pasa a la función printlnval l = { c : ¿Alguno? -> imprimirln ( c ) } // las lambdas sin parámetros pueden definirse simplemente usando { }val l2 = { print ( "sin parámetros" ) }
(Tomado y explicado en https://kotlinlang.org/docs/kotlin-tour-hello-world.html).
diversión principal () { println ( "¡Hola mundo!" ) // ¡Hola Mundo!}
Cuando Kotlin se anunció como lenguaje de desarrollo oficial de Android en Google I/O en mayo de 2017, se convirtió en el tercer lenguaje totalmente compatible con Android, después de Java y C++. [52] A partir de 2020 [actualizar], Kotlin es el lenguaje más utilizado en Android, y Google estima que el 70% de las 1000 aplicaciones principales en Play Store están escritas en Kotlin. El propio Google tiene 60 aplicaciones escritas en Kotlin, incluidas Maps y Drive. Muchas aplicaciones de Android, como Google Home, están en proceso de migrar a Kotlin y, por lo tanto, utilizan tanto Kotlin como Java. Kotlin en Android se considera beneficioso por su seguridad de puntero nulo , así como por sus características que hacen que el código sea más corto y legible. [53]
Además de su uso destacado en Android, Kotlin está ganando terreno en el desarrollo del lado del servidor. Spring Framework agregó oficialmente soporte para Kotlin con la versión 5, el 4 de enero de 2017. [54] Para brindar mayor soporte a Kotlin, Spring ha traducido toda su documentación a Kotlin y agregó soporte integrado para muchas características específicas de Kotlin, como las corrutinas. [55] Además de Spring, JetBrains ha producido un marco de trabajo pionero en Kotlin llamado Ktor para crear aplicaciones web. [56]
En 2020, JetBrains descubrió en una encuesta de desarrolladores que usan Kotlin que el 56% usaba Kotlin para aplicaciones móviles, mientras que el 47% lo usaba para un back-end web. Poco más de un tercio de todos los desarrolladores de Kotlin dijeron que estaban migrando a Kotlin desde otro idioma. La mayoría de los usuarios de Kotlin apuntaban a Android (o de otro modo a la JVM), y solo el 6% usaba Kotlin Native. [57]
En 2018, Kotlin fue el lenguaje de más rápido crecimiento en GitHub, con 2,6 veces más desarrolladores en comparación con 2017. [58] Es el cuarto lenguaje de programación más querido según la Encuesta de desarrolladores de Stack Overflow de 2020. [59]
Kotlin también recibió el premio O'Reilly Open Source Software Conference Breakout Award de 2019. [60]
Muchas empresas/organizaciones han utilizado Kotlin para el desarrollo backend:
Algunas empresas/organizaciones han utilizado Kotlin para el desarrollo web:
Varias empresas han declarado públicamente que estaban utilizando Kotlin:
Kotlin te permite elegir la versión de JVM para su ejecución. De forma predeterminada, el compilador Kotlin/JVM produce un código de bytes compatible con Java 8. Si desea utilizar las optimizaciones disponibles en versiones más recientes de Java, puede especificar explícitamente la versión de Java de destino de 9 a 19. Tenga en cuenta que, en este caso, es posible que el código de bytes resultante no se ejecute en versiones inferiores.
Esperamos que Kotlin impulse las ventas de IntelliJ IDEA
Hoy, en la conferencia magistral de Google I/O, el equipo de Android anunció soporte de primera clase para Kotlin.
Trabajar en todas las plataformas es un objetivo explícito para Kotlin, pero lo vemos como una premisa para un objetivo mucho más importante: compartir código entre plataformas. Con soporte para JVM, Android, JavaScript, iOS, Linux, Windows, Mac e incluso sistemas integrados como STM32, Kotlin puede manejar todos y cada uno de los componentes de una aplicación moderna.
En 1.4.0, cambiamos ligeramente la API Swift generada desde Kotlin con respecto a la forma en que se traducen las excepciones.
Implemente la semántica completa de Eiffel DbC y mejórela.
De forma predeterminada, la clase Object define los métodos .equals() y .hashCode(). Como resultado, cada clase Java tiene implícitamente estos dos métodos. [...] La implementación predeterminada de equals() en la clase Objeto compara la identidad del objeto. [...] El segundo criterio del contrato .hashCode() tiene una consecuencia importante: si anulamos equals(), también debemos anular hashCode(). [...] Esperaríamos que myTeamLeader devolviera "Anne", pero con el código actual, no es así. Si queremos utilizar instancias de la clase Team como claves HashMap, tenemos que anular el método hashCode() para que se adhiera al contrato; los objetos iguales devuelven el mismo código hash.
Por mucho que sea razonablemente práctico, el método hashCode definido por la clase Object devuelve enteros distintos para objetos distintos. (Esto normalmente se implementa convirtiendo la dirección interna del objeto en un número entero, pero el lenguaje de programación Java™ no requiere esta técnica de implementación).
Esta implementación proporciona un rendimiento en tiempo constante para las operaciones básicas (obtener y colocar), suponiendo que la función hash disperse los elementos adecuadamente entre los depósitos.