Classes utilitárias em Kotlin: a perspectiva de um desenvolvedor Java

Mar 10 2023
Como linguagem de programação, o Kotlin oferece vários recursos e benefícios que o tornam uma opção atraente para os desenvolvedores. Um aspecto do Kotlin que o diferencia de outras linguagens, como Java, é sua abordagem de classes utilitárias.

Como linguagem de programação, o Kotlin oferece vários recursos e benefícios que o tornam uma opção atraente para os desenvolvedores.

Um aspecto do Kotlin que o diferencia de outras linguagens, como Java, é sua abordagem de classes utilitárias . Os utilitários podem ser uma ferramenta útil no desenvolvimento de software, embora nem sempre sejam a melhor escolha quando se trata de projetar sistemas orientados a objetos.

Neste artigo, exploraremos as diferentes maneiras de implementar classes utilitárias no Kotlin e o que o Kotlin realmente faz sob o capô do ponto de vista do desenvolvedor Java. Desde a redução do código clichê até a melhoria da legibilidade do código, o Kotlin oferece uma variedade de maneiras diferentes que podem tornar a transição do Java um pouco mais suave.

Seja você um desenvolvedor Java experiente procurando expandir seu conjunto de habilidades ou um novato no mundo da programação, entender as diferenças entre a implementação de classes utilitárias em Kotlin e Java é uma etapa importante para dominar essa linguagem poderosa.

Como todos sabemos, o processo de criação de uma classe util em Java é bastante direto e descrito abaixo:

  • Crie uma classe final (porque não deve ser uma subclasse)
  • Adicione um construtor privado para evitar instanciação desnecessária da classe
  • Adicione métodos utilitários estáticos (foo nesse caso)
  • public final class UtilClass {
        private UtilClass(){}
        
        public static String foo() {
            return "bar";
        }
    }
    

  1. Declarações de objeto: o padrão Singleton pode ser benéfico em vários cenários, e o Kotlin fornece uma maneira conveniente de implementar singletons.
  2. object UtilObject {
        fun foo(): String = "bar"
    }
    

Interoperabilidade Kotlin-Java

Quando você escreve o código Kotlin, sob o capô ele é compilado em um bytecode Java que pode ser executado na Java Virtual Machine (JVM) exatamente como o código Java. Isso significa que o Kotlin pode ser usado para desenvolver aplicativos executados em qualquer plataforma compatível com JVM, incluindo desktop, web e plataformas móveis.

Kotlin foi projetado para ser totalmente interoperável com Java, o que significa que o código Kotlin pode chamar o código Java e vice-versa. Isso torna mais fácil para os desenvolvedores migrar gradualmente suas bases de código Java para Kotlin ou usar Kotlin junto com seu código Java existente.

Observação: os equivalentes de código Java que veremos no artigo foram criados compilando kotlin para código de byte Java e, em seguida, descompilando-o em Java.

Vejamos o equivalente Java gerado do código pelo compilador Kotlin:

public final class UtilObject {
   @NotNull
   public static final UtilObject INSTANCE;

   @NotNull
   public final String foo() {
      return "bar";
   }

   private UtilObject() {
   }

   static {
      UtilObject var0 = new UtilObject();
      INSTANCE = var0;
   }
}

O uso ficará assim:

UtilObject.foo()

2. Objetos complementares: Objetos complementares também são objetos singleton que possuem variáveis ​​ou funções associadas a uma classe, mas não a instâncias específicas dessa classe.

Em vez disso, ele cria outra classe chamada Companion (ou um nome de sua escolha) e coloca todas as propriedades e funções nela.

class UtilClass {
    companion object{
        fun foo(): String = "bar"
    }
}

public final class UtilClass {
    @NotNull
    public static final Companion Companion = new Companion(null);

    public static final class Companion {
        @NotNull
        public final String foo() {
            return "bar";
        }

        private Companion() {
        }

        public Companion(DefaultConstructorMarker $constructor_marker) {
            this();
        }
    }
}

O segundo (“Companion”) é um objeto singleton (inicializado rapidamente), o que significa a instância única que pode ser acessada sem chamar o construtor. Isso permite que o objeto complementar fique visível e acessível de qualquer lugar.

Nesse caso, o uso ainda será assim:

UtilClass.foo()

Utils.kt

package com.yourdomain.utils

fun foo(): String = "bar"

public final class UtilPackageKt {
   @NotNull
   public static final String foo() {
      return "bar";
   }
}

De acordo com a documentação do Kotlin, as funções de nível de pacote são recomendadas como solução para a maioria dos casos em que funções estáticas são necessárias.

O uso ficará assim:

foo()

Conclusão

As preferências podem variar com base em necessidades específicas e nem sempre é fácil determinar qual método é a melhor escolha. Cada situação deve ser avaliada individualmente.

Neste artigo, fornecemos uma visão geral das várias opções disponíveis no Kotlin e como o Java as trata nos bastidores. Esperamos que esta discussão tenha ajudado você a entender melhor as semelhanças e diferenças entre diferentes implementações de funções utilitárias em Kotlin.

Para resumir o que abordamos:

  • Considere o uso de declarações de objeto se precisar criar objetos singleton inicializados com segurança de thread .
  • Considere o uso de objetos complementares se você precisar criar uma extensão única "Java static-like" inicializada rapidamente de sua classe .
  • Considere o uso de funções de nível de pacote , se você precisar criar funções “java-static reais” (sem instância) sem a necessidade de um namespace.

Sugestões e feedbacks são sempre apreciados.