This is a premium alert message you can set from Layout! Get Now!

Kotlin queue guide for Android

0

The Kotlin programming language is a great choice for Android development. However, like any programming language, it requires considering time and space complexities and utilizing the optimal approach to account for these. Therefore, having a solid grasp of data structures and algorithms in Kotlin will play a crucial role in guaranteeing better code efficiency.

One of these data structures is the Kotlin queue, which is a collection interface that is used to store and remove data following the FIFO concept, meaning that the first value to come in will be the first to go out. In this article, we’ll explore Kotlin queues in depth, covering the different types and their benefits. To follow along with this tutorial, you’ll need the following:

  • Basic knowledge of Kotlin
  • Android Studio or IntelliJ IDE installed

Table of contents

Let’s get started!

What is a Kotlin queue?

A queue is a type of interface collection in Kotlin that enables you to structure your data in a more efficient manner based on your chosen preference. The most popular implementation of the queue interface is the LinkedList, while others include ArrayDeque and PriorityQueue.

Why do we need queues in Android development?

The importance of the queue in Android development cannot be overstated. The queue functions as a buffer anywhere data or an event is stored to be processed later. Essentially, a queue is a collection designed for holding elements prior to processing.

Aside from the basic collection operations, Kotlin queues provide additional operations like insertion, extraction, and inspection. These methods exist in two forms, those that throw an exception when the operations fail, and others that return a special value like null, true, or false.

Some important applications of the Kotlin queue include multi programming, network and job scheduling, and shared resources. Multi programming involves multiple programs running in a system’s main memory; organizing these programs in a queue ensures orderliness in the system. Job scheduling occurs when a computer is scheduled to execute a particular number of jobs one after another. These jobs, which are assigned to the processor, are organized in a queue. Finally, a queue functions as a waiting list for a single shared resource.

In addition, queues are used in network devices like a switch or router. Another application is a mailing queue, which involves a directory that stores data and controls files for mail messages.

In Kotlin, we can use queues to manage large amounts of data with ease or to handle inter-process communication.

Type of queues in Kotlin

There are four major types of queues in Kotlin: a simple queue, priority queue, circular queue, and double-ended queue.

Simple queue

In a simple queue, also known as a linear queue, the insertion of elements, called enqueue operations, occurs at the backend, and the removal of elements, known as dequeue operations, occurs at the frontend.

Priority queue

The priority queue arranges elements in a queue based on some priority. For example, if the element with the highest value has priority, it creates a queue with a decreasing order of values. Alternately, if the element with the lowest value has the highest priority, it will create a queue with an increasing order of values.

Circular queue

Linear queues and circular queues are actually quite similar. The elements in a circular queue act as a ring, meaning the last element is connected to the first element. When there is an empty space, the memory is used more efficiently. When no element is present at a particular position in the queue, then another element can be added to the position.

Dequeue

In a dequeue, also known as a double ended queue, an element can be inserted or removed from both ends of the queue, unlike other queues, which have only one end. However, it may not obey the FIFO operations.

Implementation of a queue

To implement our queue in Kotlin, we have two options. For one, sequential allocation involves implementing a queue using an array, which we can use to organize a limited number of elements. On the other hand, a  LinkedList allocation involves implementing a queue using a LinkedList, which can organize an unlimited number of elements.

Creating a Kotlin queue

The code snippet below shows the process of instantiating a queue in Kotlin using a LinkedList:

import java.util.LinkedList

fun main(args: Array<String>)
{
     val namesOfVideoGames = LinkedList<String>()
     namesOfVideoGames.addAll(list.Of("playstation5","Sega","X-Box","Nintendo"));

     for (games in namesOfVideoGames){
         println(games)
        }
}

After the instantiation process, we use a forEach loop to list out all the elements that were added to the queue:

output:
playstation5
Sega
X-Box
Nintendo

Methods of a Kotlin queue: enqueue, dequeue, isEmpty, and peek

There are four operations for a queue:

  • dequeue: Removes the element at the front of the queue and returns it
  • enqueue: Inserts an element at the back of the queue and returns true if the operation is successful
  • isEmpty: Checks if the queue is empty using the count property
  • peek: Returns the element at the front of the queue but does not remove it

Adding elements in a queue

import java.util.LinkedList
fun main()
{
        val queueExample = LinkedList<Int>()

    queueExample.add(1)
    queueExample.add(2)

    print(queueA.poll())
}

The code above shows the addition of numerical values 1 and 2 to the queueExample.

The poll() and remove() methods differ only in their respective behaviors when the queue is empty. The poll() method returns a null value, while the remove() method throws an exception. The poll() method of a queue interface returns and removes the element at the frontend of the container:

public A remove() {
    A y = poll();
    if (y != null)
        return y;
    else
        throw new NoSuchElementException();
}


val universityStudentQueue: Queue<String> = LinkedList<String>(mutableListOf("Peter", "Joe", "Elena", "Rocky", "Groovy"))
  println(universityStudentQueue) 
  universityStudentQueue.add("Barack")
  println(universityStudentQueue)

The code snippet above shows the addition of string values to a queue list. Here, we are using a set of name values to instantiate the universityStudentQueue, and later we’re printing these names, which are Peter, Joe, Elena, Rocky, and Groovy. However, an extra name is added to this queue list, Barack. Notice that this new value goes to the last position of the queue following the strict FIFO concept.

Adding elements to the end of a queue

We can add elements to the end of a queue using either the addLast method or the add method:

import java.util.LinkedList

fun main(args: Array<String>)
{
    var universityStudentQueue = LinkedList<String>();
    universityStudentQueue.addAll(listOf("Mary", "Glory", "Becky"))

   universityStudentQueue.addLast("Michael")
}

OfferLast: Safely add elements to a queue

The code below demonstrates a safe alternative to the addLast method, known as known as OfferLast. If the queue capacity constraint is reached or exceeded, it throws an exception. When the add elements fails, it returns false:

import java.util.LinkedList

fun main(args: Array<String>)
{
    var universityStudentQueue = LinkedList<String>();
    universityStudentQueue.addAll(listOf("Mary", "Glory", "Becky"))

    val offerLast: Boolean = planetsQueue.offerLast("Jupiter")

    println("Offer last result =  $offerLast")

    for(student in universityStudentQueue)
    {
        println(student)
    }
}


Output:
Offer last result = true
Mary
Glory
Becky

pollFirst: Safely remove elements from a queue

pollFirst is an alternative to the removeFirst function, returning null upon failing to remove elements from the queue instead of throwing an exception:

import java.util.LinkedList

fun main(args: Array<String>)
{
    var universityStudentQueue = LinkedList<String>();
    universityStudentQueue.addAll(listOf("Elena", "Peter", "Roosevelt"))

    var student = universityStudentQueue.pollFirst()
    println(student)

    student = universityStudentQueue.pollFirst()
    println(student)

    student = universityStudentQueue.pollFirst()
    println(student)

    student = universityStudentQueue.pollFirst()
    println(student)
}


Output:
Elena
Peter
Roosevelt
null

The last result from the pollFirst function of the queue returns null because the queue is empty, and pollFirst has no more elements to remove at that point.

peekFirst: Safely get elements from a queue

peekFirst or peekFunction is used to pick the first element from a queue. It is an alternative to the getFirst function or the first property, returning null instead of throwing an exception when no elements are retrieved:

import java.util.LinkedList

fun main(args: Array<String>)
{
    var universityStudentQueue = LinkedList<String>();
    universityStudentQueue.addAll(listOf("Owoitakata", "Lucky", "Leroey"))

    var student = universityStudentQueue.peekFirst()
    println("Peekfirst $student")

    student = universityStudentQueue.pollFirst()
    println("Removed $student")

    student = universityStudentQueue.pollFirst()
    println("Removed $student")

    student = universityStudentQueue.pollFirst()
    println("Removed $student")

    student = universityStudentQueue.peekFirst()
    println("PeekFirst $student")
}



Output:
Peekfirst Owoitakata
Removed Owoitakata
Removed Lucky
Removed Leroey
PeekFirst null

Handling queue errors in Kotlin

As an asynchronous programming paradigm, Kotlin requires good exception and error handling techniques.

Whenever you initiate an asynchronous operation, it will run through without any error and finish with the result. This poses a real threat because errors that occur during program execution might go unnoticed. As with any unhandled exception, the application would normally crash.

It is a very risky move to assume that any asynchronous operation is going to run through successfully without error. To fully understand error and exception handling in coroutine execution, it is important to understand how these errors and exceptions are propagated in the first place.

In Kotlin, there are only unchecked exceptions, and these can only be caught at run time. The general way to throw an exception is by using a throw expression, as shown in the code snippet below:

throw Exception("Exception occurred here")

Note that all the exception classes are descendants of the Throwable class. Some common exceptions in Kotlin queue include:

  • NullPointerException: Usually thrown when an attempt is made to invoke a property or method on a null object
  • Arithmetic Exception: Thrown when an invalid arithmetic numeric operation is performed
  • SecurityException: Thrown when there is a security violation
  • ArrayIndexOutOfBoundException: Thrown when we try to access an invalid index value of an array

Let’s consider the code snippet below as an example of an arithmetic exception:

fun main(args : Array<String>){
    var number = 500 / 0      // arithmetic exception is thrown here
    println(number)
}

The four common ways to handle exception in Kotlin are:

  • try...catch
  • try-catch-finally
  • try-finally

try...catch

The try block writes statements that you think can throw an exception, while the catch block writes the exception handling code:

fun main(args: Array<String>)
{        
        try
    {
        var i: Int = 100;
        throw Exception("Exception thrown in first try!")
    }
    catch(e: Exception)
    {
        e.printStackTrace()
    }
    println("Successful!")        
}

Try-catch-finally

The try-catch-finally exception is very important because of the finally block, which helps you to write code that always executes. Therefore, whatever happens in a try block, whether an exception occurs or not, the statements in finally block will get executed:

fun main(args: Array<String>)
{        
        try
    {
        var i: Int = 1000;
        throw Exception("Exception thrown in first try!")
    }
    catch(e: Exception)
    {
        e.printStackTrace()
    }
    finally{
        println("Finally Block Result!")
    }
}

Try-finally

The try-finally exception has only try and finally blocks. It is useful because it helps a block to ensure that resources are released properly:

fun main(args: Array<String>)
{        
        try
    {
        var i: Int = 10;
        throw Exception("Throwing Exception!")
    }
    finally
    {
        println("Break the rules!");
    }
}

Retrying failed items on a queue based system

In a queue-based system, we can implement retry logic to enable the system to execute a particular code snippet a specified number of times. In the code below, we write our code inside of a try...catch block inside of a loop with a specified maximum retry value:

import kotlin.random.Random

const val MAXIMUM_NUMBER_OF_RETRIES = 4

fun main() {
    for (i in 0..MAXIMUM_NUMBER_OF_RETRIES) {
        try {
            // generate 0 or 1 with equal probability
            val zeroOrOne = Random.nextInt(2)
           println("The random number is.. $zeroOrOne")

            // 50% probability of "ArithmeticException: / by zero"
            val rand = 1 / zeroOrOne

           // don't retry on success
            break
        } catch (e: ArithmeticException) {
           // handle exception
           println(e.message) // log exception

           // Sleep time is 1 seconds before retrying
          Thread.sleep(1000)

          // throw exception if the last re-try fails
          if (i == MAXIMUM_NUMBER_OF_RETRIES) {
                throw e
            }
        }
    }
}

Below is the output:

The random number is...0
/ by zero
The random number is...0
/ by zero
The random number is...0
/ by zero
The random number is...1

In the code snippet above, the output value varies. If the code throws an ArithmeticException, the control goes to the catch block. After this exception is handled, the retry happens every second. After all retries are exhausted, and the last retry fails, the system throws the exception.

Conclusion

In this tutorial, we explored Kotlin queues in depth, including their creation, operations, exceptions, and discussing ways to handle errors when they occur. We began with an introduction to Kotlin queues and their benefits in Android development. Then, we covered the process of Kotlin queue instantiation and some methods used by queues to perform certain operations.

I think you would also agree that the Kotlin queue data-structure provides an immense advantage in making your code more efficient. Happy coding!

The post Kotlin queue guide for Android appeared first on LogRocket Blog.



from LogRocket Blog https://ift.tt/ruDo9sl
Gain $200 in a week
via Read more

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.
Post a Comment

Search This Blog

To Top