Sobes.tech
Middle

Where have you used generics in your development experience?

sobes.tech AI

Answer from AI

Used generics:

  • For implementing type-safe collections. For example, ArrayList<MyObject> instead of raw ArrayList, which prevents runtime errors related to type casting.
    // Non-type-safe approach (raw type)
    List list = new ArrayList();
    list.add("String");
    list.add(123); // Adding int
    
    // Type-safe approach with generics
    List<String> stringList = new ArrayList<>();
    stringList.add("String");
    // stringList.add(123); // Compiler will give an error
    
  • For creating universal RecyclerView adapters. Allows reusing adapter logic for different data types.
    // Example of a universal ViewHolder
    class GenericViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: T) {
            // Data binding logic depending on type T
        }
    }
    
    // Example of a universal adapter
    class GenericAdapter<T>(private val items: List<T>) : RecyclerView.Adapter<GenericViewHolder<T>>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenericViewHolder<T> {
            // Create ViewHolder
        }
    
        override fun onBindViewHolder(holder: GenericViewHolder<T>, position: Int) {
            holder.bind(items[position])
        }
    
        override fun getItemCount() = items.size
    }
    
  • When creating object factories. To obtain a specific object type without explicit casting.
    interface Factory<T> {
        T create();
    }
    
    class StringFactory implements Factory<String> {
        @Override
        public String create() {
            return "New String";
        }
    }
    
    class IntegerFactory implements Factory<Integer> {
        @Override
        public Integer create() {
            return 100;
        }
    }
    
    Factory<String> stringFactory = new StringFactory();
    String myString = stringFactory.create(); // Get String without casting
    
  • To constrain types in methods and classes. Using bounded generics (<T extends MyInterface> or <T super MyClass>) to ensure the generic type implements a certain interface or inherits from a specific class.
    // Method that accepts a list of elements implementing Serializable
    public <T extends Serializable> void saveObjectList(List<T> list) {
        // Saving logic
    }
    
  • In architectural components. For example, when working with LiveData or ViewModel, generics are often used to define the data type they manage.
    // LiveData for a list of objects of a specific type
    val myData: LiveData<List<MyItem>> = // initialization
    
    // ViewModel with data of a specific type
    class MyViewModel : ViewModel() {
        val data: MutableLiveData<MyStateType> by lazy {
            MutableLiveData<MyStateType>()
        }
    }
    
  • When developing network clients. For automatic deserialization of server responses into specific object types.
    // Example of a Retrofit service with generics in response
    interface ApiService {
        @GET("users")
        Call<List<User>> getUsers();
    
        @GET("products/{id}")
        Call<Product> getProduct(@Path("id") String productId);
    }
    

Generics significantly increased type safety, readability, and code reusability.