Kotlin is made by JetBrains (the same as that did IntelliJ the IDE).
See their website here:
Compiled with Java11.
To use with IntelliJ, you can select your project SDK, if you have multiple ones.
Use File | Project Structure... | Project Settings | Projects
to choose Java 11
.
If you are not using intellij, you can run with:
kotlinc hello.kt
You need to create the gradle file build.gradle
(support groovy or kotlin) then add dependencies and configurations.
For gradle to pick up the source and test files, you will need to organise your folders like:
βββ src
βββ main
βΒ Β βββ kotlin
βΒ Β βββ package
βββ test
βββ kotlin
βββ package
You can now try to run the tests (using the gradle wrapper ./gradlew
instead of gradle
to
use the gradle version with which the project has been built with):
./gradlew test
And the complete one with coverage:
./gradlew clean build test jacocoTestReport
Some principles
- Inheritance : kill off duplicate codes
- Implement with a Mother class implemented by a daughter class
- Polymorphism : abstraction of implementation
- Implement using interface and generic functions
- Encapsulation : hiding the changes, protects data
- Implement by using restrictive access to data or contructers
Objects comparison:
equals
: should not throw an exceptionhashCode
: to compare (find) the object in a list
Encapsulation problems:
- Don't use
setSomething
andgetSomething
if you need getters / setters but rather:- A Method with a verb to change something
- A property with a noun to have the value of something
- Control the data flow
- You want to control how the value of your object is handled
- You don't want anyone using the data without knowing how to
- Make everything as private as possible
- Data object, feature envy
- Classes finishing by
-er
or-or
- Should be a job of the class, or implemented as a pattern
- Use
`
(back tick) to define method's name with space:
@Test
fun `valid parameters` { ... }
- Overload Objects to generate new ones easily:
val Number.teaspoons get() = Quantity(this, Unit.teaspoon)
Quantity(1.5, Unit.teasponn)
// Can now be written
1.5.teaspoons
- Before a recursion, ask yourself these questions:
- What is the original question?
- What is the recursive question?
- What are the Terminal condition? (when the recursive stops)
- The
?
is used in Kotlin to handle null:
// The Rectangle? makes the function returns Rectangle or null
fun mayReturnRectangleOrNull() : Rectangle? { ... }
// With "?." the .rectangleMethod() will only occur when mayReturnRectangleOrNull() returns a rectangle
mayReturnRectangleOrNull()?.rectangleMethod()
// Elvis ?: to have another value if the preceeding one return null
val somethingNotNull = emptyRectangle()
return mayReturnRectangleOrNull() ?: somethingNotNull
- The
!!
to force the function to operate eventhough it can be null:
return if (list.isEmpty) -1 else list.min()!! //list can be null, without !! it would complain, but can still return null
- Using the
this@Class
inside of alist.apply { this.prepend(this@Class) }
, you are calling thethis
of the class (sothis@Class
to differentiate from the otherthis
(element of the list that you apply to).
When you have to create a recursive function, you first answer this three questions:
- What is the original question: What you are actually trying to do?
- What is the recursive question: What will you base your recursion on?
- What are the terminal conditions: When should the recursive question stopped and return an answer?
Any
for any typeinit {}
to check the values inputed at the creation of the classoverride
at the beginning of the function to override it:
override fun equals(other: Any?) { ... }
operator
to override an operator function. Here an example with the comparison operator (>
,<
, ...)
operator fun compareTo(other: Probability) { ... }
infix
function are function where you can omit the.
:
infix fun isCompatibleWith(other: Unit): Boolean { ... }
// calling the function using the infix notation
unit isCompatibleWith otherUnit
// is the same as
unit.isCompatibleWith(otherUnit)
typealias
is used to define a name for a function signature (hence alias) usually used to simplify simple functions into a type:
internal typealias CostStrategy = (Double) -> Double
flatMap
transforms a list of list of stuff into a simple list of stuff
list.flatMap { List<List<Path>> } // returns List<Path>
-
onEach
is the same aslist.map{ this.apply { ... } }
-
sumByDouble
is the same aslist.map{}.sum{}