Most Relevant Android Interview Questions 2023
Most Relevant Android Interview questions to watch out
Q: Activity lifecycle in Android
A: An android application will undergo various states that are associatively called as Android Activity Life Cycle.
1. onCreate() - The function onCreate() is called when a user first opens an activity that acts the same as a constructor of a class. The callback function is required as the basic setup for the application is done in the created state like, associate the activity with the ViewModel or to bind data to the UI, etc.
2. onStart() - The function onStart() is called when an activity becomes visible to the user and is called after onCreate. The activity will not stay in the started state for too long. Once the callback completes executing its task, it will move to the resumed state.
3. onResume() - The function onResume() is called just before the user starts interacting with the application. The activity stays in the same state until some action is performed on it. For example, users switching to another application or user receiving a phone call.
4. onPause() - The function onPause() is called when the app is partially visible to the user on the mobile screen. Or in other words activity is partially obscured by another activity. Another activity that’s in the foreground is semi-transparent. The application will not reside in this state for too long, so heavy load tasks shouldn’t be performed in this state.
5. onStop() - The function onStop() is called when the activity is no longer on the activity stack and not visible to the user. In this state, the resources must be managed or released as the activity is no longer visible to the user. The activity either comes back to interact with the user after running the onRestart() or finishes by executing the onDestroy() callback.
6. onRestart() - The function onRestart() is called when the activity in the stopped state is about to start again. This method is only called when the user navigates back to the stopped activity. The callback is immediately followed by the onStart() and onResume() callbacks.
7. onDestroy() - The function onDestroy() is called when the activity is cleared from the application stack. The activity may enter this state because of two reasons,
- The activity is finishing due to the user dismissing the activity or called the finish() function.
- The system temporarily destroys the activity because of a configuration change.
If the onDestroy() is called due to user interaction or due to activity is finishing, onDestroy() is the final callback in the life cycle. If this callback is called due to a configuration change, then there is a chance that the activity will be created again by calling the onCreate() function. You can differentiate between the two by using the isFinishing() function. It returns a boolean, which indicates whether the activity is finishing or being dismissed temporarily. It returns true if the activity is finishing.
Now let’s see some of the situations where the life cycle methods and states will occur.
- When you open the app, it will go through below states:
onCreate() –> onStart() –> onResume()
When you press the back button and exit the app
onPause() — > onStop() –> onDestory()
When you press the home button
onPause() –> onStop()
After pressing the home button, again when you open the app from a recent task list
onRestart() –> onStart() –> onResume()
After dismissing the dialog or back button from the dialog
onResume()
When your phone screen is off
onPause() –> onStop()
When your phone screen is turned back on
onRestart() –> onStart() –> onResume()
So, these are some of the situations when your app goes through various states.
Q: What are the four states of an activity?
A: Basically, there are 4 stages of an activity i.e., active, paused, stopped and destroyed.
Stage 1 refers to when an activity is 'active' (onStart or Startactivity)). This means that the activity is currently in use and can be seen by the user on the screen in the foreground.
Stage 2 means that the activity is 'paused' (onPause). This means that the application is located in the background yet still visible to the user.
Stage 3 is when the activity is 'stopped' (onStop or stop Activity). This means that the application is obstructed, blocked, or hidden by another activity.
Lastly, stage 4 means that the application has been 'destroyed' (onDestroy) implying that it has been completely terminated and that one will have to start a new activity if they want to access it.
Q: Activity life cycle on phone rotate
A: On rotation of screen,
- 1. The Activity is destroyed.
- 2. The Activity is recreated fresh in requested orientation.
- 3. Views and Variables need to be handled accordingly.
onCreateonStartonResume
onPauseonStoponDestroyonCreateonStartonResume
Restoring the Activity state using onRestoreInstanceState and onSaveInstanceState
- Is generally preferred and recommended.
2.
Handling configurations change yourself using on Configuration Changed, d
eclare android:configChanges attribute in Manifest- Against the guidelines
- Not recommended
- Should be used ONLY when restoring Activity back is expensive and slow.
Q: Why do we override Android Lifecycle callback functions?
A: Understanding and implementing these functions can avoid the App crashing when the user receives a phone call or moves to another app. These steps are useful to overcome the loss of the user’s progress when the user switches to another app or the device screen turns off. Additionally, to perform specific actions when the activity is at some stage, for example, getting the state of the user when the app resumes from the paused state or setting the initial configuration in the creating state.
Q: In Activity life cycle which one is the guaranteed first callback method invoked by the system?
A: The first method on Activity life cycle which is guaranteed to be called is 'onCreate()', when the system first creates the activity, it always calls 'onCreate()'.
Q: In Activity life cycle which one is the guaranteed last callback method invoked by the system?
A: 'onPause()' is last method of Activity life cycle which is guaranteed to be called. There is a possibility that onStop(), & onDestroy() may be called or not as it depends totally on the system.
The system calls 'onPause()' as the first indication that the user is leaving your activity (though it does not always mean the activity is being destroyed).
Q: How to create a custom View
1.(a). By Extending an Existing Widget Class (eg. Button, TextView)
(b). By Extending the View Class (eg. View)
2. To use the view, we have to add in the XML
3. To draw something on the UI, we need to override the onDraw() method, which gives us a canvas object.
Q: Foreground service Vs Background service and their use
Background service: It runs in background till the time app is running or in background, as soon as the app is killed, background service is also destroyed. In simple words background service performs an operation that isn't directly noticed by the user.
To create a Background Service,
(1) Create a new Class and have it extend the Service class.
(2) Inside the class, override the onBind() and onStartCommand() methods.
(3) The onStartCommand() method is called every time we start the service either by calling startService() or startForegroundService(). This is where we want to define what the service will do.
(4) Add Service element in the AndroidManifest.xml file
<service android:name=".MY_BACKGROUND_SERVICE"/>
(5) Call startService() and pass in the intent.
Intent serviceIntent = new Intent(this,MyBackgroundService.class) startService(serviceIntent)
A Foreground Service is a service that stays alive even when the app is terminated. A foreground service performs some operation that is noticeable to the user. When we use a foreground service, we must display a notification so that users are actively aware that the service is running. This notification cannot be dismissed unless the service is either stopped or removed from the foreground.
To create a Foreground Service:
(1) Create a new Class and have it extend the Service class.
(2) Inside the class, override the onBind() and onStartCommand() methods.
(3) The onStartCommand() method is called every time we start the service either by calling startService() or startForegroundService(). This is where we want to define what the service will do. In this method only call
startForeground(ID, NOTIFICATION)
It expects two arguments i.e., an ID for the notification and the notification itself.
Example:
val CHANNELID = "FOREGROUND_SERVICE_ID"
val channel = NotificationChannel(
CHANNELID,
CHANNELID,
NotificationManager.IMPORTANCE_LOW
)
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
val notification: Notification.Builder = Builder(this, CHANNELID)
.setContentText("Service is running")
.setContentTitle("Service enabled")
.setSmallIcon(R.drawable.ic_launcher_background)
startForeground(1001, notification.build())
(4) Add Service element in the AndroidManifest.xml file
<service android:name=".MyForegroundService"/>
(5) In order for us to use Foreground Services, we need to add the FOREGROUND_SERVICE permission in the manifests file to enable it.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
(6) Call startForegroundService() and pass in the intent.
val serviceIntent = Intent(this, MyForegroundService::class.java) startForegroundService(serviceIntent)
Q: What are the bound services?
A bound service is an implementation of the Service class that allows other applications to bind to it and interact with it. To provide binding for a service, you must implement the onBind() callback method. This method returns an IBinder object that defines the programming interface that clients can use to interact with the service.
A service is bound when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, receive results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
Refer this link on how to create, and bind/unbind bound services
Q: How to update the UI from Background Service
A: There are a lot of ways to do that, but these are the 3 of the basic implementations and I personally feel that every android developer should be aware of it.
(1) Using LocalBroadcastReceivers -
LocalBroadcastReceivers are a helper to register for and send broadcasts of Intents to local objects within your process. This is efficient for a couple of reasons:
- You know that the data you are broadcasting won’t leave your app, so don’t need to worry about leaking private data.
- It is not possible for other applications to send these broadcasts to your app, so you don’t need to worry about having security holes they can exploit.
(2) Using ResultReceiver -
ResultReceiver are Generic interface for receiving a callback result from someone.
- Create a CustomResultReceiver class which extends ResultReceiver, and overrides method onReceiveResult(int resultCode, Bundle resultData).
- Create an interface AppReceiver with function as public void onReceiveResult(int resultCode, Bundle resultData);
- Implement AppReceiver interface in the activity, create the object of CustomResultReceiver and pass it via the intent to the intent service.
(3) Using Handlers -
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue.
- Create a custom Handler class which extends Handler.
- Create an interface AppReceiver with function as public void onReceiveResult(Message message);
- We pass the Handler from the activity to the intent service via intent.
- Once background service is processed, we can pass the status of the service back to the activity using the Message & handler.
- Register the intent service in the activity.
- Pass the handler via the intent to the intent service.
- Implement AppReceiver interface in the activity, and inside onReceiveResult handle the results from the intent service.
Q: Differences between Alarm manager and Work Manager
Alarm Manager:
- By the help of Android AlarmManager in android, you can schedule your application to run at a specific time in the future.
- It works whether your phone is running or not.
- The Android AlarmManager holds a CPU wake lock that provides guarantee not to sleep the phone until broadcast is handled.
Work Manager:
- Support for both asynchronous one-off and periodic tasks.
- Support for constraints such as network conditions, storage space, and charging-status.
- Chaining of complex work requests, including running work in parallel.
- Output from one work request used as input for the next.
- Handles API level compatibility back to API level 14.
- Works with or without Google Play services.
- Follows system health best practices.
- LiveData support to easily display work request state in UI.
Q: Arrays Vs ArrayLists Vs List
An Array is fixed in size once it is allocated. You can't add items to it or remove items from it. Also, all the elements must be the same type. As a result, it is type safe, and is also the most efficient of the three, both in terms of memory and performance. Also, Array supports multiple dimensions (i.e., it has a Rank property) while List and ArrayList do not (although you can create a List of Lists or an ArrayList of ArrayLists, if you want to).
An ArrayList is a flexible array which contains a list of objects. You can add and remove items from it, and it automatically deals with allocating space. If you store value types in it, they are boxed and unboxed, which can be a bit inefficient. Also, it is not type-safe.
A List<> leverages generics; it is essentially a type-safe version of ArrayList. This means there is no boxing or unboxing (which improves performance) and if you attempt to add an item of the wrong type it'll generate a compile-time error.
Q: HashTable Vs HashMap
A: HashMap and Hashtable both are used to store data in key and value form. Both are using hashing technique to store unique keys.
But there are many differences between HashMap and Hashtable classes that are presented below:
Q: HashSet Vs TreeSet
- HashSet is faster than TreeSet and should be preferred choice if sorting of element is not required.
- HashSet allows null object, but TreeSet doesn't allow null Object and throw NullPointerException, why, because TreeSet uses compareTo() method to compare keys and compareTo() will throw java.lang.NullPointerException.
- HashSet is backed by HashMap while TreeSet is backed by NavigableMap in Java.
- HashSet uses equals() method to compare two objects in Set and for detecting duplicates while TreeSet uses compareTo() method for same purpose. if equals() and compareTo() are not consistent, i.e., for two equal object equals should return true while compareTo() should return zero, then it will break contract of Set interface and will allow duplicates in Set implementations like TreeSet.
- HashSet doesn't guaranteed any order while TreeSet maintains objects in Sorted order defined by either Comparable or Comparator method in Java.
- TreeSet does not allow to insert Heterogeneous objects. It will throw classCastException at Runtime if trying to add heterogeneous objects, whereas HashSet allows hetrogeneous objects.
Q: Internal working of HashMap. What will happen if hash code will be same for 2 different keys?
A: HashMap class is a part of the Java Collections Framework which is used for storing elements in key-value pairs. All the keys in a hashmap are unique. And it allows retrieving value by key. A hashmap uses a hashtable, however, it is internally implemented using two data structures namely an array and a linked list.
Whenever you declare a hashmap, internally, it will create an array of buckets. The buckets are referred to as nodes or you can say a linked list. A node can represent:
int Hash
K Key
V Value
Node next (Address of the next node)
Now, when you insert values in a key using put() method of the HashMap class, the hashcode will be generated by the put() method. Hashcode makes the process of receiving values faster and easier. And this hashcode is further computed and it will generate the index for storing the value.
The value of our key will be stored at the index given by the hashcode in the form of a Linked list. Now, let’s see how the index is calculated for storing the value.
Index Calculation in HashMap:
Hashcode of the key may be very large to create an array. Hashcode generated may be in the range of integer and if we create arrays for such a long range, then it could be memory consuming task.
index = hashCode(key) & (length - 1)
The expression hashCode & (length-1) does a bitwise AND on hashcode using length-1, which is like a bitmask, to return only the low-order bits of hashcode, thereby making for a super-fast variant of hashcode % length.
In case of a collision i.e., the index generated already has an entry, first verify if both the keys are same, if yes then replace the value, Otherwise, connect this node object to the previous node object via linked list.
Using the get () method to fetch the data from the HashMap class.
Calculate hash code of Key, and then calculate the index as done in case of put () method. Go to index of the array and compare the first element’s key with the given key. If both are equals then return the value, otherwise, check for the next element if it exists. If the next node is null then return null, otherwise go to the next node and compare keys, and repeat the same until the key is not found or next is not null.
Hash code of the null key is 0.
In Hashmap put (insertion), remove (deletion) and get (search) operations are performed at constant time i.e, time complexity is O(1) with the assumption that key-value pairs are well distributed across the buckets.
Q: What are the advantages of MVVM?
A: Android applications built using MVVM are more robust, fast, scalable and very less prone to memory leaks. In MVVM ViewModel is the key between View and Model.
The important key point about MVVM is that View has reference to the ViewModel but not in reverse and that makes the application’s UI-Components related memory leak-proof.
Each View may have a dedicated ViewModel or may be shared by multiple in case of fragments to enable sharing data cross fragments of an activity. MVVM is a more suitable candidate for automated testing.
The other advantages of MVVM are:
(a). Maintainability
(b). Testability
(c). Extensibility
(d). Single responsibility
Q: What are ViewModel?
A: A ViewModel object provides the data for a specific UI component, such as a fragment or activity, and contains data-handling business logic to communicate with the model. For example, the ViewModel can call other components to load the data, and it can forward user requests to modify the data. The ViewModel doesn't know about UI components, so it isn't affected by configuration changes, such as recreating an activity when rotating the device.
There are certain points to mention about ViewModel :
- ViewModel survives rotation & other configuration changes.
- ViewModel keeps running while the activity is on the back stack.
- ViewModel is Lifecycle agnostic. You can override onCleared (to clear disposables for example) just before the ViewModel is about to get killed.
- ViewModel promotes simple and concise code.
- ViewModel promotes reactiveness based on state down to the view by letting the view observe the live data inside the view model.
- ViewModel promotes immutability.
- ViewModel promotes testing.
Q: What is Livedata ?
A: Livedata is a mechanism to observe the changes in the data and reflect those on the specific view.
So Livedata is nothing but a data holder class which is life-cycle aware and observes the modifications in data but updates only those ui components of app which are in active state.
One of the best uses of live data is that, since it is life-cycle aware, so we don't have to update the UI again from our side.
A LiveData object is usually stored within a ViewModel object and is accessed via a getter method:
class NameViewModel : ViewModel() {
// Create a LiveData with a String
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
// Rest of the ViewModel...
}
And how to start observing a LiveData object:
class NameActivity : AppCompatActivity() {
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
private val model: NameViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Other code to setup the activity...
// Create the observer which updates the UI.
val nameObserver = Observer<String> { newName ->
// Update the UI, in this case, a TextView.
nameTextView.text = newName
}
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.currentName.observe(this, nameObserver)
}
}
To set the data in the LiveData methods like 'setValue' and 'postValue' can be used.
nameViewModel.currentName.setValue(/** updated data **/);
or
nameViewModel.currentName.postValue(/** updated data **/);
Q: What are the advantages of live data?
A: Here are the few of advantages of live data
- LiveData can be used with libraries like Room Persistent Library, Coroutines, etc.
- Before notifying any observer about data change, LiveData verifies if that is alive or not.
- The observers will be informed about the data change, as and when it happens.
- On Activity recreation only the latest data will be provided by LiveData.
- There are no memory leaks.
- Views will always receive the most recent data.
- onChanged parameter in Observer interface is annotated as @Nullable so we must always handle null case in our onChanged implementation.
- While retrieving data we usually want to notify our Observers when loading started or error occurred, so… we end up with next workaround by creating some kind of Resource class.
- Sometimes we want data to be consumed only once, like a SnackBar message or Dialog trigger, hence SingleLiveEvent or Event wrappers.
A: MutableLiveData is a subclass of LiveData which is used for some of its properties (setValue/postValue) and using these properties we can easily notify the UI when onChange() is called. Only using LiveData object we can’t do this. So, we have to convert the target object to MutableLiveData/MediatorLiveData for notifying on each time of changing data.
java.lang.Object
↳android.arch.lifecycle.LiveData<T>
↳android.arch.lifecycle.MutableLiveData<T>
↳android.arch.lifecycle.MediatorLiveData<T>
A: When changing the data on the Main thread, then MutableLiveData class’s both setValue and postValue will work in the same manner i.e., they will update the value and notify the observers., and when changing the LiveData on the background thread, use the MutableLiveData class’s postValue method.
- setValue() is called directly from caller thread, synchronously notifies observers and changes LiveData value immediately. It can be called only from MainThread.
- postValue() uses inside something like this new Handler (Looper.mainLooper()). post (() -> setValue()), so it runs setValue via Handler in MainThread. It can be called from any thread.
- postValue() is slower as compared to setvalue()
Q: What are the differences between lazy Vs lateinit
A: Kotlin library provides two different access modifiers for property declaration. Here in this answer, we will highlight the difference between these two access modifiers and how we can use them in our application.
- lateinit can only be used with a var property whereas lazy will always be used with val property. A lateinit property can be reinitialized again and again as per the use whereas the lazy property can only be initialized once.
- lateinit can't have custom getter or setter whereas lazy has custom getter. A lateinit property can't have a custom getter whereas a lazy property has a block that gets executed whenever the first time that property is called.
- In order to check if a lateinit property is initialized or not, we can use the extension function to KProperty directly which returns a boolean if the property is initialized or not.
print(::lateinitUser.isInitialized)
- lateinit properties can't be of primitive data types whereas lazy properties can be of primitive date types also.
- We can't define the thready safety in case of lateinit property but in case of lazy, we can choose between SYNCHRONIZED, PUBLICATION and NONE.
- A lazy property can be of nullable type but a lateinit property can't be of nullable type.
- Accessing a lateinit property before it has been initialized throws a special exception that clearly identifies the property being accessed and the fact that it hasn’t been initialized. We can't ever access a lazy property before it hased been initialized. Remember that the lazy property can be null, but the initialization will still happen when the first time the property will be called.
val lazyUser: User? by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
User(
age = 5,
userName = "Ram Sewak"
)}
Q: Differentiate between Singleton Vs Static
# Singleton is a design pattern.
Static classes are basically a way of grouping classes together in Java.
# In Singleton Memory is allocated once the object is created.
In Static class Memory is allocated immediately after any of the class members is accessed.
# Singleton implementation can either have static members or instance members.
Static classes can contain static members only.
# Singleton class can implement any other interface or base class if required.
Static classes cannot implement the interface or any other base class.
# Singleton classes can be used as a method parameter.
Static class cannot be used as a method parameter.
# Singleton pattern uses Heap memory.
Static classes use stack memory.
# Singleton works within the scope of Garbage Collector as it uses Heap memory.
Static classes are Out of scope for Garbage Collector as it uses stack memory.
# Singleton supports Dependency Injection (DI) implementation as it follows OOPS concepts.
Static classes cannot implement Dependency Injection (DI) as DI is Interface-driven.
# Singleton is an architectural pattern and not a language feature.
Static is a language feature and not an Architectural pattern.
# In Singleton Disposal of objects is possible.
It cannot dispose of the static class as there is no instance created.
Q: What are sealed classes?
A: As the word sealed suggests, sealed classes conform to restricted or bounded class hierarchies. A sealed class defines a set of subclasses within it. It is used when it is known in advance that a type will conform to one of the subclass types. Sealed classes ensure type safety by restricting the types to be matched at compile-time rather than at runtime.
The sealed classes also have one another distinct feature, their constructors are protected by default. A sealed class is implicitly abstract and hence it cannot be instantiated.
// A sealed class with a string property
sealed class Fruit(val x : String)
{
// Two subclasses of sealed class defined within
class Apple : Fruit("Apple")
class Mango : Fruit("Mango")
}
// A subclass defined outside the sealed class
class Pomegranate: Fruit("Pomegranate")
// A function to take in an object of type Fruit
// And to display an appropriate message depending on the type of Fruit
fun display(fruit: Fruit)
{
when(fruit)
{
is Fruit.Apple -> println("${fruit.x} is good for iron")
is Fruit.Mango -> println("${fruit.x} is delicious")
is Pomegranate -> println("${fruit.x} is good for vitamin d")
}
}
fun main()
{
// Objects of different subclasses created
val obj = Fruit.Apple()
val obj1 = Fruit.Mango()
val obj2 = Pomegranate()
// Function called with different objects
display(obj)
display(obj1)
display(obj2)
}
Q: What is flow?
A: Flow in Kotlin is a better way to handle the stream of data asynchronously that executes sequentially.
A flow is a stream of multiple, asynchronously computed values. Flows emit values as soon as they are done computing them. A flow consists of a producer and a consumer. As the names suggest, a producer emits values while the consumer receives the values.
The emit() will help in sending values to the consumer.
The collect is used to collect the values emitted by producer.
One important feature that flows has is that they support backpressure. The backpressure occurs when the Consumer is not done consuming the data, and the Producer is producing it, which can result in data loss.
Q: Difference between <uses-permission> and <permission> tags
A: <uses-permission> are for those system permissions which your app needs, in order to function properly.
For example, your app connects to some API's and fetches your data from them and for that you require internet. Now in order to use internet you must declare this permission in AndroidManifest.xml and need to give this permission to your android device to access INTERNET.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
<permission> describes how app developers can use the security features provided by Android to define their own permissions. To enforce your own permissions, you must first declare them in your AndroidManifest.xml using one or more <permission> elements.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<permission
android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
android:description="@string/permdesc_deadlyActivity"
android:label="@string/permlab_deadlyActivity"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous" />
...
</manifest>
Q: What is the recommended way to perform discrete, 'transactional' background tasks in Android?
A: The recommended way going forward is using WorkManager APIs, that makes it easy to specify deferrable, asynchronous tasks and when they should run under the circumstances you choose, or recurring tasks that run at a specified interval. Internally WorkManager might use JobScheduler, Firebase-JobDispatcher, Executor, and AlarmManager for running the task.
Q: Idiomatic way to remove duplicate strings from the array
A: Following are the ways to remove duplicates from an array in Koltin
- distinct ()
val list = arrayOf("One","Two","Three", "Two","Three","Four")
println(list.distinct())//One, Two, Three, Four : The order is maintained here
- toSet ()
val list = arrayOf("One","Two","Three", "Two","Three","Four")
println(list.toSet())//One, Two, Three, Four : The order is maintained here
- toMutableSet ()
val list = arrayOf("One","Two","Three", "Two","Three","Four")
println(list.toMutableSet())//One, Two, Three, Four : The order is maintained here
- toHashSet ()
val list = arrayOf("One","Two","Three", "Two","Three","Four")
println(list.toHashSet())//Four, One, Two, Three : The order is not maintained here
- let: Executing a lambda on non-null objects.
- let: Introducing an expression as a variable in a local scope.
- apply: Object configuration.
- run: Object configuration and computing the result.
- also: Additional effects.
- with: The grouping function calls on an object.
Comments
Post a Comment