Kotlin - apply, let, run, also, takeIf

apply: return current receiver once anonymous function complete
package examples

fun main() {
    plus(1,2).apply {
        println(this) // 3
        println(toDouble()) // 3.0
    }
}

fun plus(a: Int, b: Int): Int {
    return a + b
}

let: pass receiver to lambda you provided
package examples

fun main() {
    plus(1,2)?.let { println(it) }
}

fun plus(a: Int, b: Int): Int? {
    return a + b
}

run: Pass execution value. 
package examples

fun main() {
    val grade = 59
    grade.run(::isPassed)
            .run(::comment)
            .run(::println)
}

fun comment(passed:Boolean):String {
    if (passed) {
        return "Good job"
    } else {
        return "Oh no"
    }
}

fun isPassed(grade: Int): Boolean {
    return grade >= 60
}

also: similar to "let" with more side effect
package examples

fun main() {
    val grade = 59
    grade.run(::isPassed)
            .run{comment(this, "QQ")}
            .also(::println)
        .also{ println("$it again") }
}

fun comment(passed:Boolean, suffix:String):String {
    if (passed) {
        return "Good job$suffix"
    } else {
        return "Oh no$suffix"
    }
}

fun isPassed(grade: Int): Boolean {
    return grade >= 60
}

takeIf: Provide predicate to decide will run or not
package examples

fun main() {
    60.takeIf { isPassed(it) }?.run { println("Good Job") }
}

fun isPassed(grade: Int): Boolean {
    return grade >= 60
}


Kotlin - Numbers

Types
  • Byte
  • Short
  • Int
  • Long
  • Float
  • Double

Convert string to number
package examples

fun main() {
    println("1.01".toIntOrNull()) // null (not 1)
    println("1".toInt())
    println("1.01".toDouble())
    println("1.01".toBigDecimal())
    println("1.01e".toBigDecimal()) // NumberFormatException
}

Convert int to double
package examples

fun main() {
    val i = 1
    val d = 0.5
    println(i - d) // 0.5

    println(i.javaClass)  // int
    println(i.toDouble()) // 1.0
}

Format number to string: %
package examples

fun main() {
    println("%.2f".format(1.123456)) // 1.12
}

Convert Double to Int
package examples

import kotlin.math.roundToInt

fun main() {
    val d15 = 1.5
    val d14 = 1.4
    println(d15.roundToInt()) // 2
    println(d14.roundToInt()) // 1
    println(d15.toInt()) // 1
    println(d14.toUInt()) // 1

    val md15 = -1.5
    val md14 = -1.4
    println(md15.roundToInt()) // -1
    println(md14.roundToInt()) // -1
    println(md15.toInt()) // -1
    println(md14.toUInt()) // 0
}


Kotlin - Strings

indexOf and substring
  • indexOf
  • substring
  • split
package examples

fun main() {
    println("abc".indexOf('c'))     // 2
    println("abc".substring(1))  // bc
    println("abcdefg".substring(1 until 5)) // bcde
    println("abcdefg".substring(1 .. 5)) // bcdef
    println("a,b,c,d,e".split(",")) // [a, b, c, d, e]
    val (v1,v2,v3) = "a,b,c,d,e".split(",")
    println("$v1, $v2, $v3") // a, b, c
}

Replace with regular expression
package examples

fun main() {
    val replaceResult = "abc".replace(Regex("b"), transform = {
        when(it.value) {
            "b" -> "B"
            else -> it.value
        }
    })
    println(replaceResult) // aBc
}

Compare String
package examples

fun main() {
    val s1 = "" + "a"
    val s2 = "a"
    println(s1 == s2) // true
    println(s1 === s2) // true
}

Unicode and forEach
package examples

fun main() {
    println("\u0045") // E

    "abc".forEach { println(it) } // print a b c in separated lines
}


Kotlin - Nullable

Nullable
  • "String?" in return type shows the function may return null
  • API caller need use "?." to prevent NullPointerException
package examples

fun main() {
    println(getString(true))         // null
    println(getString(false))        // hello
    println(getString(true)?.length) // null
    println(getString(false)?.length) // 5
}

fun getString(isNull: Boolean): String? {
    if (isNull) return null
    return "hello"
}

Post action if not null
package examples

fun main() {
    println(getInt(false)?.let {
        println(it)
        it + 100
    })
}

fun getInt(isNull:Boolean): Int? {
    if (isNull) return null
    else return 5
}

Double bang operation
  • "!!." will throw exception when return value was null
package examples

fun main() {
    println(getInt(false)!!.let {
        println(it)
        it + 100
    })
    println(getInt(true)!!.let { // throw kotlin.KotlinNullPointerException due to !!.
        println(it)
        it + 100
    })
}

fun getInt(isNull:Boolean): Int? {
    if (isNull) return null
    else return 5
}

Default value if null
package examples

fun main() {
    println(getInt(true) ?: 100) // print 100
}

fun getInt(isNull:Boolean): Int? {
    if (isNull) return null
    else return 5
}

Compute differently when null and not-null
package examples

fun main() {
    // print null and kotlin.Unit because println returns Unit
    println(getInt(true) ?.and(100) ?: println("null"))
}

fun getInt(isNull:Boolean): Int? {
    if (isNull) return null
    else return 5
}


Kotlin - Anonymous Function and function type

Anonymous function
package examples

fun main() {
    var f = {
        println("hello")
    }() // print hello
}

Function type
package examples

fun main() {
    {
        println("construstor ")
    }()
    var f = {
        println("hello f1")
    }

    val f2: () -> Unit = {
        println("hello f2")
    }

    f()
    f2()
}

Implicit Return
  • Anonymous function support return last line of value
package examples
fun main() {
    var f = { //
        "implicit return"
        "ABC" // Print ABC
    }
    println(f())
}

Anonymous Function argument
package examples

fun main() {
            // arg types                return type   arg names
    val f : (String, String, String) -> Int =         {a, b, c ->
        a.length + b.length + c.length
    }
    println(f("aa", "fff", "ee"))
}

Default argument name: it
  • "it" is the default argument name when there is only one parameter in anonymous function
package examples

fun main() {
    val f : (String) -> Int = {
        it.length
    }
    println(f("Gss"))
}

Return type inference
  • No need to specify return type
package examples

fun main() {
    val f = {
        "hello"
    }
    println(f())
}
  • Need provide arg name when no return type specified
package examples

fun main() {
    val f = { name:String ->
        "hello $name"
    }
    println(f("FF"))
}

Function as argument
package examples

fun main() {
    println(count("hello", {it == 'l'}))
}

fun count(s:String, exclude:(Char) -> Boolean): Int {
    var result = 0
    for (c in s) if (!exclude(c)) result++
    return result
}
  • Lambda argument should be moved out of parentheses (Intellij suggestion)
    (When function is the latest argument)
package examples

fun main() {
    println(count("hello") {it == 'l'})
}

fun count(s:String, exclude:(Char) -> Boolean): Int {
    var result = 0
    for (c in s) if (!exclude(c)) result++
    return result
}

Function Inlining
  • Inlining removes the need for the JVM to use an object instance and to perform variable memory allocations for the lambda.
package examples

fun main() {
    println(count("hello") {it == 'l'})
}

inline fun count(s:String, exclude:(Char) -> Boolean): Int {
    var result = 0
    for (c in s) if (!exclude(c)) result++
    return result
}

Function Reference
  • Use "::" to reference a function
package examples

fun main() {
    run(::printHello)
}

fun run(f: () -> Unit) {
    f()
}

fun printHello() {
    println("hello")
}

Return Function Type
package examples

fun main() {
    create()("john")
}

fun create(): (String) -> Unit {
    return {
        println("hello $it")
    }
}


Kotlin - Functions Basic

  • Function parameter is read-only

Ex. Private function (Default is public)
package examples

fun main() {
    val i = 100
    printS(i)
    println(publicPrint(i))
}

fun publicPrint(i: Int):String {
    return when(i) {
        in 0..100 -> "0-100"
        else -> "else"
    }
}

private fun printS(i: Int) {
    return when(i) {
        in 0..100 -> println("0-100")
        else -> println("else")
    }
}

Default parameter value
package examples

fun main() {
    printNumber(50) // print 50
    printNumber() // print 100
}

fun printNumber(n: Int = 100) {
    println(n)
}

One line function
package examples

fun main() {
    printNumber(50) // print 50
    printNumber() // print 100
}

fun printNumber(n: Int = 100) = println(n)

Named argument
package examples

fun main() {
    printABC(1,2,3) // print 1,2,3
    printABC(c=1, a=2, b=3)  // print 2,3,1
}

fun printABC(a:Int,b:Int,c:Int) {
    println("a=$a, b=$b, c=$c")
}

Unit type and Nothing type
  • Unit type is same as void in Java
  • Nothing type is same as throwing UnSupportedException in Java
package examples

fun main() {
    val u1 : Unit = printABC(1,2,3) // print 1,2,3
    val u2 : Unit = printABC(c=1, a=2, b=3)  // print 2,3,1
    println(u1) // Print kotlin.Unit
    println(u2) // Print kotlin.Unit
    notImplemented()
    println("No reachable") // won't be printed
}

fun notImplemented(): Nothing = throw NotImplementedError()

fun printABC(a:Int,b:Int,c:Int) {
    println("a=$a, b=$b, c=$c")
}
Output
a=1, b=2, c=3
a=2, b=3, c=1
kotlin.Unit
kotlin.Unit
Exception in thread "main" kotlin.NotImplementedError: An operation is not implemented.
    at examples.HelloKt.notImplemented(Hello.kt:11)
    at examples.HelloKt.main(Hello.kt:8)
    at examples.HelloKt.main(Hello.kt)

Process finished with exit code 1

Backticks function name
  • It's for Java and Kotlin reserved words conflict solution
  • It's useful when writing unit test code
package examples

fun main() {
    `this is a book test`()
}

fun `this is a book test`() {
    println("assert this is a book")
}

File-level variable
examples/MyNumber.kt
package examples

const val MAX = 10000

examples/Hello.ky
package examples

// const val MAX = 30 // can't declare MAX twice under the same package
fun main() {
    println(MAX) // don't need specify
}

example2/MyNumber2.kt
package example2

const val MAX = 4000 // can use same name as examples/MyNumber.kt
const val MAX2 = examples.MAX // can reference another packages constant


Kotlin String Template

  • until
  • downTo
  • Compare by char
  • Convert to list
package examples

fun main() {
    val age = 100
    if (age in 150 downTo 0) {
        println("downTo")
    }
    if (age in 0 until 100) {
        println("until")
    }
    val c = 'X'
    val s = c in 'a'..'q'
    println(s)


    val downToList = (10 downTo 0).toList()
    println(downToList)


    val untilList = (0 until 10).toList()
    println(untilList)


    val b = false
    val ss = "${if(b) "Yes" else "No"}"
    println(ss)
}


kotlin - when

When
package examples

fun main() {
    var name = "John"
    val greet = when(name) {
        "John" -> "Hello John"
        else -> "Unknown"
    }
    println(greet)
}

When + if else
package examples

fun main() {
    val i = 50
    val s = when(i) {
        in 0..50 -> "0-50"
        in 51..100 -> "51-100"
        else -> if (i in 101..150) "101-150" else "Out Of Range"
    }
}


Kotlin - if-else and comparing

if-else
package examples

fun main() {
    var n = 0
    if (n > 0) {
        println("> 0")
    } else if (n == 0) {
        println("== 0")
    } else {
        println("< 0")
    }
}


if in range
package examples

fun main() {
    var r = 100
    if (r in 10..50) {
        println("0-50")
    } else if (r in 50..100) {
        println("50-100") // print this
    } else {
        println("> 100")
    }
}

Conditional Expression - With braces
package examples

fun main() {
    var success = true
    var s = if (success) {
        "Good"
    } else {
        "Bad"
    }
    println(s)
}

Conditional Expression - No braces
package examples

fun main() {
    var success = true
    var s = if(success) "Good" else "Bad"
    println(s)
}

Conditional Expression - No braces wrap line
package examples

fun main() {
    var r = 100
    var s = if (r < 60) "< 60"
            else if (r == 60) "60"
            else "> 60"
    println(s)
}

Conditional Expression - No braces with nested if-else
package examples

fun main() {
    var r = 100
    val s = if (r < 60)
                if (r < 30) "0 ~ 30"
                else "30-60"
            else if (r == 60) "60"
            else "> 60"
    println(s)
}

Compare
package examples

fun main() {
    var s1 = setOf("a")
    var s2 = setOf("a")

    // value is the same
    println(s1 == s2) // true
    println(s1 != s2) // false

    // reference is different
    println(s1 === s2) // false
    println(s1 !== s2) // true
}


Kotlin - Hello World, Define variable and const

Hello.kt
fun main(args: Array<String>) {  
   println("Hello, world!")
}

Define variable
package examples

fun main(args: Array<String>) {
    // variable type declaration
    var i = 0;
    var i2: Int = 0
    println("hwllo " + ++i + ++i2)

    // can skip type declaration
    var s = "string"
    println("string: " + s)

    var c : Char = 'a'
    println("Char" + c)

    var b = true
    var d = 0.123
    var list = listOf("a","b","c")
    println(list)

    var set : Set<String> = setOf("d","e", "f", "d")
    println(set)

    var map = mapOf("a" to 1, "b" to 2)
    println(map)

    // read only => val
    val pp = i
    println(pp)
}

Declare const
package examples

const val MAX = 100

fun main() {
    // const can't be declared within method
//    const val MAX = 100
    println(MAX)
}





Sprint Boot - List files to Flux

Books suggestion
@GetMapping("/unable_files")
public Flux<FileInfo> wrongListFiles() throws IOException {
    return Flux.fromIterable(Files.newDirectoryStream(Paths.get("C:/Python33")))
            .map(path -> new FileInfo(path.getFileName().toString(), path.toAbsolutePath().toString()));
}

But it always encounter error
2020-05-17 02:45:23.134 ERROR 6980 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [3b6f7b07-1]  500 Server Error for HTTP GET "/unable_files"

java.lang.IllegalStateException: Iterator already obtained
    at sun.nio.fs.WindowsDirectoryStream.iterator(WindowsDirectoryStream.java:117) ~[na:1.8.0_92]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
    |_ checkpoint ? Handler com.example.demo.FileController#wrongListFiles() [DispatcherHandler]
    |_ checkpoint ? HTTP GET "/unable_files" [ExceptionHandlingWebHandler]
Stack trace:
        at sun.nio.fs.WindowsDirectoryStream.iterator(WindowsDirectoryStream.java:117) ~[na:1.8.0_92]
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:79) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]

Fixed
  • FIleInfo.java 
package com.example.demo;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class FileInfo {

    private String name;
    private String path;

}
  • list files
@GetMapping("/files")
public Flux<FileInfo> listFiles() throws IOException {
    return Flux.fromStream(Files.list(Paths.get("C:/Python33")))
            .map(path -> new FileInfo(path.getFileName().toString(), path.toAbsolutePath().toString()));
}

Client
$ curl -s http://localhost:8080/files
[{"name":"DLLs","path":"C:\\Python33\\DLLs"},{"name":"Doc","path":"C:\\Python33\\Doc"},{"name":"include","path":"C:\\Python33\\include"},{"name":"isaac","path":"C:\\Python33\\isaac"},{"name":"Lib","path":"C:\\Python33\\Lib"},{"name":"libs","path":"C:\\Python33\\libs"},{"name":"LICENSE.txt","path":"C:\\Python33\\LICENSE.txt"},{"name":"NEWS.txt","path":"C:\\Python33\\NEWS.txt"},{"name":"python.exe","path":"C:\\Python33\\python.exe"},{"name":"pythonw.exe","path":"C:\\Python33\\pythonw.exe"},{"name":"q.py","path":"C:\\Python33\\q.py"},{"name":"README.txt","path":"C:\\Python33\\README.txt"},{"name":"say.py","path":"C:\\Python33\\say.py"},{"name":"Scripts","path":"C:\\Python33\\Scripts"},{"name":"tcl","path":"C:\\Python33\\tcl"},{"name":"test.py","path":"C:\\Python33\\test.py"},{"name":"Tools","path":"C:\\Python33\\Tools"},{"name":"__pycache__","path":"C:\\Python33\\__pycache__"}]

Spring Boot - Flux and RequestBody

  • Controller
  • @RestController
    public class RequestBodyController {

        @PostMapping("/requestBodyFlux")
        public Mono<Void> postFlux(@RequestBody Flux<String> ids) {
            return ids.map(id -> {
                String s = "id:" + id;
                System.out.println(s);
                return s;
            }).then();
        }

    }

  • Client
  • isaac@isaac-PC MINGW64 ~/workspace_github
    $ curl -s -v -H 'Content-Type:application/json' -X POST -d '["a","b","c"]'  http://localhost:8080/requestBodyFlux
    *   Trying ::1...
    * TCP_NODELAY set
    * Connected to localhost (::1) port 8080 (#0)
    > POST /requestBodyFlux HTTP/1.1
    > Host: localhost:8080
    > User-Agent: curl/7.60.0
    > Accept: */*
    > Content-Type:application/json
    > Content-Length: 13
    >
    } [13 bytes data]
    * upload completely sent off: 13 out of 13 bytes
    < HTTP/1.1 200 OK
    < content-length: 0
    <
    * Connection #0 to host localhost left intact

  • Server
  • C:\Users\isaac\workspace_github\spring-boot-study>gradle bootRun
    Starting a Gradle Daemon, 4 busy Daemons could not be reused, use --status for details

    > Task :bootRun

      .   ____          _            __ _ _
    /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
    =========|_|==============|___/=/_/_/_/
    :: Spring Boot ::        (v2.2.7.RELEASE)

    2020-05-17 01:51:11.297  INFO 4060 --- [  restartedMain] com.example.demo.DemoApplication         : Starting DemoApplication on isaac-PC with PID 4060 (C:\Users\isaac\workspace_github\spring-boot-study\build\classes\java\main started by isaac in C:\Users\
    isaac\workspace_github\spring-boot-study)
    2020-05-17 01:51:11.300  INFO 4060 --- [  restartedMain] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
    2020-05-17 01:51:11.364  INFO 4060 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
    2020-05-17 01:51:11.364  INFO 4060 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
    2020-05-17 01:51:14.302  INFO 4060 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
    2020-05-17 01:51:14.634  INFO 4060 --- [  restartedMain] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
    2020-05-17 01:51:14.638  INFO 4060 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 3.781 seconds (JVM running for 4.585)
    id:["a","b","c"]


Spring Boot - Helloworld

Download Spring Initializer

HelloController.java
package com.example.demo;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;


@RestController
public class HelloController {

    @GetMapping
    public String hello(@RequestParam(defaultValue = "", required = false) String name) {
        return "hello " + name;
    }

    @GetMapping("/ids")
    public Flux<String> ids() {
        return Flux.just("1","2","3");
    }
}

Run bootRun
gradle bootRun
Starting a Gradle Daemon, 1 busy and 1 incompatible and 1 stopped Daemons could not be reused, use --status for details

> Task :bootRun

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::        (v2.2.7.RELEASE)


2020-05-12 23:30:11.100  INFO 6864 --- [  restartedMain] com.example.demo.DemoApplication         : Starting DemoApplication on isaac-PC with PID 6864 (C:\Users\isaac\workspace_github\study-practice\build\classes\java\main started by isaac in C:\Users\isa
ac\workspace_github\study-practice)
2020-05-12 23:30:11.103  INFO 6864 --- [  restartedMain] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2020-05-12 23:30:11.150  INFO 6864 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-05-12 23:30:11.150  INFO 6864 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2020-05-12 23:30:12.218  INFO 6864 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2020-05-12 23:30:12.470  INFO 6864 --- [  restartedMain] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-05-12 23:30:12.475  INFO 6864 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 1.683 seconds (JVM running for 2.171)
<=========----> 75% EXECUTING [52s]
> :bootRun

Curl example
$ curl -s http://localhost:8080/ids
123

$ curl -s http://localhost:8080
hello

$ curl -s http://localhost:8080?name=QQQ
hello QQQ



Gradle - application

Run No arg main class
Java 
package examples;
public class TestMain {
    public static void main(String[] params) {
        System.out.println("hello");
    }
}
build.gradle
apply plugin: 'java'
apply plugin: 'application'
mainClassName= 'examples.TestMain'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.12'
}
Run
$ gradle run

> Task :run
hello

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.3/userguide/command_line_interface.html#sec:command_line_warnings


BUILD SUCCESSFUL in 952ms
3 actionable tasks: 3 executed

Run main class with hard code arg
Java
package examples;
public class TestMain {
    public static void main(String[] params) {
        System.out.println("hello " + params[0]);
    }
}
build.gradle
apply plugin: 'java'
apply plugin: 'application'
mainClassName= ‘examples.TestMain'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.12'
}

run.args = ['abc']
Run
apply plugin: 'java'
apply plugin: 'application'
mainClassName= 'examples.TestMain'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.12'
}

run.args = ['abc']

Run main class with command line arg
Java
package examples;
public class TestMain {
    public static void main(String[] params) {
        System.out.println("hello " + params[0]);
    }
}
build.gradle
apply plugin: 'java'
apply plugin: 'application'
mainClassName= 'examples.TestMain'


repositories {
    mavenCentral()
}


dependencies {
    testCompile 'junit:junit:4.12'
}
run.args = [project.args] //simply args can work as well
Run
$ gradle clean run -Pargs=ABC

> Task :run
hello ABC

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.3/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 760ms
4 actionable tasks: 4 executed







Gradle java project - code and test

source code
Hello.java
package examples;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;


public class Hello {


    public String hello() throws IOException {
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("hello.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder s = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
            s.append(line);
        }
        return s.toString();
    }
    
}

prepare build.gradle and apply java plugin
apply plugin: ‘java'

compile java
$ gradle compileJava

BUILD SUCCESSFUL in 620ms
1 actionable task: 1 executed

Clean classes
$ gradle clean

BUILD SUCCESSFUL in 564ms
1 actionable task: 1 executed

Build code and run test
Add junit dependency
apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.12'
}

Add test code
package examples;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

import org.junit.Assert;
import org.junit.Test;

public class HelloTest {

    @Test
    public void hello() throws IOException, URISyntaxException {
        Hello h = new Hello();
        String hello = h.hello();
        String hellotest = new String(Files.readAllBytes(Paths.get(Thread.currentThread().getContextClassLoader().getResource("hellotest.txt").toURI())));
        Assert.assertEquals(hellotest, hello);
    }
   
}

Compile and Test
$ gradle build


Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.3/userguide/command_line_interface.html#sec:command_line_warnings


BUILD SUCCESSFUL in 1s
6 actionable tasks: 6 executed

Test Report
Open in browser: build/reports/tests/test/index.html 

Gradle helloworld task


Edit build.gradle
task helloworld {
    println "Hello world"
}

List tasks and find helloworld
$gradle tasks --all

...
Other tasks
-----------
helloworld
prepareKotlinBuildScriptModel

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

Run task
$ gradle helloworld
> Configure project :
Hello world

BUILD SUCCESSFUL in 931ms


Gradle Helloworld - Main Class

Reference
Thanks 良葛格, his explanation is so simple and good to read and practice!!

Class
package examples;
public class HelloMain {
    public static void main(String[] params) {
        System.out.println("Hello world:" + params[0]);
    }
}

build.gradle
apply plugin:'java'
apply plugin:'application'

mainClassName='examples.HelloMain'

run {
    args username
}

run

$ gradle run -Pusername=Isaac

> Task :run
Hello world:Isaac

BUILD SUCCESSFUL in 721ms
3 actionable tasks: 1 executed, 2 up-to-date

別名演算法 Alias Method

 題目 每個伺服器支援不同的 TPM (transaction per minute) 當 request 來的時候, 系統需要馬上根據 TPM 的能力隨機找到一個適合的 server. 雖然稱為 "隨機", 但還是需要有 TPM 作為權重. 解法 別名演算法...