Scala

Scala

Made by DeepSource
Use .lastOption to access the last element SC-P1001
Performance
Major

Certain Scala structures such as List implement methods such as .reverse that allows you to reverse the contents of a structure. This however can be an expensive operation and depends upon the kind of structure and the number of elements in it. Therefore, directly accessing the last element via .lastOption is more concise and performant than reversing an entire collection and then accessing the first element.

Use .isEmpty or .nonEmpty to check if structure is empty SC-P1002
Performance
Major

Scala allows you to use comparison operators such as == and != against List() and Set() to check if a structure is empty or not. However, this method is considered to be in-efficient as doing so instantiates a new and empty structure which is only disposed off by the GC when deemed appropriate, thus causing an additional overhead. Therefore, it is suggested that you use the structures' .isEmpty and .nonEmpty methods to check if the respective structures are empty or not.

Consider filtering first and then sorting SC-P1003
Performance
Major

Algorithms such as sorting and filtering depend upon size of a structure, i.e. the number of elements in a structure. If you wish to arrange your elements in a specified order and select only a subset of these elements, it is suggested that you first filter the elements according to your criteria and then sort them as this potentially reduces the number of elements to be sorted, thus reducing the overall time spent performing this operation.

Consider using the appropriate overloaded method when searching for a single char SC-P1004
Performance
Major

Methods such as String.indexOf and String.lastIndexOf allow you to search for an occurrence of either a single char or a substring within a String. If you'd like to search for an occurrence of a single char, it is recommended that you use the appropriate method that takes a Char as a parameter rather than a String as the former approach is more performant and recommended.

Calling List.size is inefficient SC-P1005
Performance
Major

Scala's List data-structure is an immutable sequence of elements, implemented as a linked list. Therefore, methods such as .size have a complexity of O(n). Repeatedly calling such methods can impact the performance of your application. Therefore, it is suggested that you use a different structure such as an Array or an ArrayBuffer depending whichever that suites your needs.

Benchmarks -

val numsList = (1 to 1000000).toList

// 2713250ns
time {
  numsList.size
}

val numsArray = (1 to 1000000).toBuffer

// 11750ns
time {
  numsArray.size
}
Appending to List is in-efficient SC-P1007
Performance
Major

Scala's List data-structure is an immutable sequence of elements, implemented as a linked list. Therefore, operations such as append have a complexity of O(n). Repeatedly calling such methods can impact the performance of your application. If you need to append a large number of elements, it is suggested that you use a different structure such as an ArrayBuffer or a Vector depending on whichever that suites your needs.

Consider combining successive .filter() calls SC-P1009
Performance
Major

Certain Scala collections support methods such as .filter, allowing you to select elements from your collection based on specified conditions. Since each filter call iterates through the entire collection, it is recommended that you combine/chain such consecutive calls to avoid re-iterations.

Consider using .findLast() over .reverse.find() SC-P1012
Performance
Major

The reverse method reverses all the ordering of the collection. Chaining it with find() returns the first element that satisfies the given predicate. However, the reverse operation here is inefficient as elements except the first-satisfying element are discarded.

It is recommended that you instead use .findLast() as:

  1. There is no reversing involved, and,

  2. No resources are allocated for the intermediate buffer to hold the reversed order as the operation itself is made redundant.

Consider using the efficient alternative .reverseIterator over .reverse.iterator SC-P1010
Performance
Major

The reverse method reverses the ordering of the collection. Chaining it with iterator returns the iterator for this reversed order. However, consider using the provided suitable and efficient alternative .reverseIterator as it is defined for this very specific purpose.

This is more suitable and efficient as:

  1. There is no reversing involved, and,

  2. No resources are allocated for the intermediate buffer to hold the reversed order as the operation itself is made redundant.

Consider using .collectFirst() over .collect().headOption SC-P1011
Performance
Major

The collect() method collects the elements that satisfy the specified predicate. Chaining it with headOption returns the first element from this collection. However, the collect operation here is inefficient as elements except the first one are discarded without use.

It is recommended that you instead use .collectFirst() as:

  1. Iteration is terminated as soon as the first element that satisfies the predicate is found, and,

  2. No resources are allocated for the intermediate buffer.

Calling garbage collector manually does not necessarily improve performance SC-P1008
Performance
Critical

The Java Virtual Machine (JVM) ships with garbage collector(s) that are responsible for reclaiming the heap space and freeing unused resources as deemed necessary during an application's lifetime. They are reliable, performant, well-tested and are invoked as deemed necessary. Manually invoking the GC does not necessarily improve the application's performance and in some cases may even adversely impact the performance. If you wish to improve your application's performance, consider - 1. Profiling your application for in-efficient codepath and resource leaks