icon-cookie
The website uses cookies to optimize your user experience. Using this website grants us the permission to collect certain information essential to the provision of our services to you, but you may change the cookie settings within your browser any time you wish. Learn more
I agree
IrenaBaby
122 articles
My Web Markups - IrenaBaby
  • method whenever there are no parameters and the method accesses mutable state only by reading fields of the containing object (in particular, it does not change mutable state).
  • abstract modifier in front of the class
  • Note that the contents method in class Element does not carry an abstract modifier. A method is abstract if it does not have an implementation
  • which says that client code should not be affected by a decision to implement an attribute as a field or method.
  • In particular, you can override a parameterless method with an empty-paren method, and vice versa. You can also leave off the empty parentheses on an invocation of any function that takes no arguments.
  • To summarize, it is encouraged style in Scala to define methods that take no parameters and have no side effects as parameterless methods, i.e., leaving off the empty parentheses. On the other hand, you should never define a method that has side-effects without parentheses, because then invocations of that method would look like a field selection.
  • If you leave out an extends clause, the Scala compiler implicitly assumes your class extends from scala.AnyRef, which on the Java platform is the same as class java.lang.Object.
  • ... extends Element ...
  • in Scala it is forbidden to define a field and method with the same name in the same class,
  • class LineElement(s: String) extends ArrayElement(Array(s))
  • The ++ operation concatenates two arrays
  • In Scala, as in Java, you do this by adding a final modifier to the member
  • ++
  • To do this you simply declare the entire class final by adding a final modifier to the class declaration.
  • A straightforward solution is to create a companion object of class Element and make this be the factory object for layout elements. That way, you need to expose only the class/object combo of Element to your clients, and you can hide the three implementation classes ArrayElement, LineElement, and UniformElement.
  • Such parameterless methods are quite common in Scala. By contrast, methods defined with empty parentheses, such as def height(): Int, are called empty-paren methods. The recommended convention is to use a parameterless
  • uniform access principle
  • it is recommended to still write the empty parentheses when the invoked method represents more than a property of its receiver object. For instance, empty parentheses are appropriate if the method performs I/O, or writes reassignable variables (vars), or reads vars other than the receiver's fields, either directly or indirectly by using mutable objects.
  • Another way to think about this is if the function you're calling performs an operation, use the parentheses, but if it merely provides access to a property, leave the parentheses off.
  • You can also prefix a class parameter with var,
  • val
  • Another difference is that in Scala, fields and methods belong to the same namespace. This makes it possible for a field to override a parameterless method.
  • Scala's two namespaces are: values (fields, methods, packages, and singleton objects) types (class and trait names)
  • You can avoid the code smell by combining the parameter and the field in a single parametric field definition, as shown in Listing 10.5:
  • Note that now the contents parameter is prefixed by val.
  • Finally, it is possible to add modifiers such as private, protected,[5] or override to these parametric fields, just as you can do for any other class member. Consider, for instance, the following class definitions:
  • Here, the syntax "for ((line1, line2) <- ...)" allows you to name both elements of a pair in one pattern, i.e., line1 stands now for the first element of the pair, and line2 stands for the second.
  • The modifier is optional if a member implements an abstract member with the same name.
  • Specifically, arrays in Scala inherit from a class scala.Seq,
  • The zip method picks corresponding elements in its two arguments and forms an array of pairs. For instance, this expression:
30 annotations
  • line <- fileLines(file)
  • in Scala assignment always results in the unit value, (). Thus, the value of the assignment "line = readLine()" will always be () and never be ""
  • You can do this by binding the result to a new variable using an equals sign (=). The bound variable is introduced and used just like a val, only with the val keyword left out
  • finally
  • You can do this with a for expression by adding a filter: an if clause inside the for's parentheses.
  • Just keep adding if clauses.
  • }
  • {
  • yield
  • The syntax of a for-yield expression is like this: for clauses yield body
  • throw is an expression that has a result type.
  • The while and do-while constructs are called "loops," not expressions, because they don't result in an interesting value.
  • Because no equals sign precedes its body, greet is defined to be a procedure with a result type of Unit.
  • Boolean = true
  • greet() == ()    
  • With the "file <- filesHere" syntax, which is called a generator
  • , we iterate through the elements of filesHere
  •  if file.getName.endsWith(".scala")
  • You can include more filters if you want.
  • If you add more than one filter on a generator, the filter's if clauses must be separated by semicolons.
  • ;
  • If you add multiple <- clauses, you will get nested "loops."
  • file <- filesHere
  • Technically, an exception throw has type Nothing.
  • trimmed = line.trim
  • If you prefer, you can use curly braces instead of parentheses to surround the generators and filters. One advantage to using curly braces is that you can leave off some of the semicolons that are needed when you use parentheses.
  • catch
  • case ex: FileNotFoundException => // Handle missing file
  • case ex: IOException => // Handle other I/O error
  • Scala does not require you to catch checked exceptions, or declare them in a throws clause
  • The value computed in the finally clause, if there is one, is dropped.
31 annotations
  • programs should be decomposed into many small functions that each do a well-defined task.
  • Scala offers an additional approach: you can define functions inside other functions. Just like local variables, such local functions are visible only in their enclosing block. Here's an example:
  • local functions can access the parameters of their enclosing function.
  • A function literal is compiled into a class that when instantiated at runtime is a function value.[2] Thus the distinction between function literals and values is that function literals exist in the source code, whereas function values exist as objects at runtime.
  • To make a function literal even more concise, you can use underscores as placeholders for one or more parameters, so long as each parameter appears only one time within the function literal
  • Multiple underscores mean multiple parameters, not reuse of a single parameter repeatedly.
  • you can also replace an entire parameter list with an underscore.
  • A partially applied function is an expression in which you don't supply all of the arguments needed by the function. Instead, you supply some, or none, of the needed arguments.
  • In situations where a function is not required, attempting to use this form will cause a compilation error. Here's an example:
  • free variable,
  • Intuitively, Scala's closures capture variables themselves, not the value to which variables refer
  • Scala allows you to indicate that the last parameter to a function may be repeated.
  • As the previous example demonstrates, the closure created for (x: Int) => x + more sees the change to more made outside the closure.
  • The same is true in the opposite direction. Changes made by a closure to a captured variable are visible outside the closure.
  • tail-call optimization is limited to situations in which a method or nested function calls itself directly as its last operation, without going through a function value or some other intermediary
  • To accomplish this, you'll need to append the array argument with a colon and an _* symbol, like this
  • : _*
  • You also won't get a tail-call optimization if the final call goes to a function value.
  • argument to the scala shell or to the scalac compiler.
  • The function value (the object) that's created at runtime from this function literal is called a closure.
  • In this case, you've supplied the first and last argument to sum, but the middle argument is missing.
  • val b = sum(1, _: Int, 3)
  • The name arises from the act of "closing" the function literal by "capturing" the bindings of its free variables.
  • If you are writing a partially applied function expression in which you leave off all parameters, such as println _ or sum _, you can express it more concisely by leaving off the underscore if a function is required at that point in the code.
  • a bound variable,
  • If you think you might be confused by tail-call optimizations when looking at a stack trace, you can turn them off by giving a: -g:notailcalls
  • the instance used is the one that was active at the time the closure was created
  • To denote a repeated parameter, place an asterisk after the type of the parameter. For example:
  • *
  • Functions like approximate, which call themselves as their last action, are called tail recursive. The Scala compiler detects tail recursion and replaces it with a jump back to the beginning of the function, after updating the function parameters with the new values.
30 annotations
  • The identifiers n and d in the parentheses after the class name, Rational, are called class parameters. The Scala compiler will gather up these two class parameters and create a primary constructor that takes the same two parameters.
  • you can only access their value on the object on which add was invoked.
  • The Scala compiler will compile any code you place in the class body, which isn't part of a field or a method definition, into the primary constructor
  • The require method takes one boolean parameter. If the passed value is true, require will return normally. Otherwise, require will prevent the object from being constructed by throwing an IllegalArgumentException.
  • a class.
  • In Scala, every auxiliary constructor must invoke another constructor of the same class as its first action. In other words, the first statement in every auxiliary constructor in every Scala class will have the form "this(...)".
  • constructors other than the primary constructor are called auxiliary constructors.
  • the Scala convention is to use camel case for constants, such as XOffset.
  • A constant is more permanent.
  • A mixed identifier
  • An alphanumeric identifier
  • implicit def intToRational(x: Int) = new Rational(x)
  • To access the numerator and denominator on that, you'll need to make them into fields. Listing 6.1 shows how you could add these fields to class Rational.[
  • One way in which Scala's conventions depart from Java's involves constant names.
  • The primary constructor is thus the single point of entry of
  • if a class doesn't have a body, you don't need to specify empty curly braces
  • class parameters can be used directly in the body of the class
  • A precondition is a constraint on values passed into a method or constructor, a requirement which callers must fulfill. One way to do that is to use require,[1] like this:
  • The `$' character also counts as a letter, however it is reserved for identifiers generated by the Scala compiler. Identifiers in user programs should not contain `$' characters, even though it will compile;
  • In Scala, the word constant does not just mean val.
  • As a result, it is best to avoid identifiers like to_string, __init__, or name_.
  • A literal identifier
  • The Scala compiler will internally "mangle" operator identifiers to turn them into legal Java identifiers with embedded $ characters. For instance, the identifier :-> would be represented internally as $colon$minus$greater. If you ever wanted to access this identifier from Java code, you'd need to use this internal representation.
  • An operator identifier
  • implicit conversion
  • The implicit modifier in front of the method tells the compiler to apply it automatically in a number of situations.
26 annotations
  • Alternatively, you can put the + at the end of a line. For just this reason, whenever you are chaining an infix operation such as +, it is a common Scala style to put the operators at the end of the line instead of the beginning:
  • On the other hand, a semicolon is required if you write multiple statements on a single line:
  • def add(b: Byte) { sum += b }
  • In the next line, cache += (s -> cs), the passed string key is mapped to the integer checksum value, and this key-value pair is added to the cache map.
  • Public is Scala's default access level.
  • A singleton object definition looks like a class definition, except instead of the keyword class you use the keyword object.
  • Another way to express such methods is to leave off the result type and the equals sign, and enclose the body of the method in curly braces. In this form, the method looks like a procedure, a method that is executed only for its side effects.
  • One important characteristic of method parameters in Scala is that they are vals, not vars
  • In the absence of any explicit return statement, a Scala method returns the last value computed by the method.
  • Another shorthand for methods is that you can leave off the curly braces if a method computes only a single result expression.
  • One puzzler to watch out for is that whenever you leave off the equals sign before the body of a function, its result type will definitely be Unit.
  • To use the trait, you first write "extends Application" after the name of your singleton object
  • When a singleton object shares the same name with a class, it is called that class's companion object.
  • in Scala, you can name .scala files anything you want, no matter what Scala classes or code you put in them.
  • You must define both the class and its companion object in the same source file.
  • scalac
  • However, singleton objects extend a superclass and can mix in traits. Given each singleton object is an instance of its superclasses and mixed-in traits, you can invoke its methods via these types, refer to it from variables of these types, and pass it to methods expecting these types.
  • Any standalone object with a main method of the proper signature can be used as the entry point into an application
  • fsc
  • fsc -shutdown
  • Then instead of writing a main method, you place the code you would have put in the main method directly between the curly braces of the singleton object. That's it
  • Scala provides a trait, scala.Application
  • you should inherit from Application only when your program is relatively simple and single-threaded.
23 annotations
  • if a method takes only one parameter, you can call it without a dot or parentheses
  • Note that this syntax only works if you explicitly specify the receiver of the method call. You cannot write "println 10", but you can write "Console println 10".
  • When you apply parentheses surrounding one or more values to a variable, Scala will transform the code into an invocation of a method named apply on that variable.
  • Similarly, when an assignment is made to a variable to which parentheses and one or more arguments have been applied, the compiler will transform that into an invocation of an update method that takes the arguments in parentheses as well as the object to the right of the equals sign
  • You parameterize an instance with types by specifying one or more types in square brackets
  • If the method name ends in a colon, the method is invoked on the right operand.
  • Applying this functional philosophy to the world of objects means making objects immutable
  • a shorthand way to specify an empty list is Nil
  • For an immutable sequence of objects that share the same type you can use Scala's List class.
  • Once you have a tuple instantiated, you can access its elements individually with a dot, underscore, and the one-based index of the element.
  • If you prefer an immutable map, no import is necessary, as immutable is the default map.
  • Like lists, tuples are immutable, but unlike lists, tuples can contain different types of elements.
  • These _N numbers are one-based, instead of zero-based
  • This -> method, which you can invoke on any object in a Scala program, returns a two-element tuple containing the key and value
14 annotations
  • type inference, Scala's ability to figure out types you leave off
  • in Scala you specify a variable's type after its name, separated by a colon. For example: scala> val msg2: java.lang.String = "Hello again, world!"
  • vals and vars
  • Function definitions start with def
  • Following the function's result type is an equals sign and pair of curly braces that contain the body of the function.
  • (arg: String)
  • if a function consists of just one statement, you can optionally leave off the curly braces.
  • In Scala, arrays are zero based, and you access an element by specifying an index in parentheses.
  • The empty parentheses indicate the function takes no parameters
  • The function's name
  • Unit is greet's result type. A result type of Unit indicates the function returns no interesting value. Scala's Unit type is similar to Java's void type,
  • is followed by a comma-separated list of parameters in parentheses
  • A type annotation must follow every function parameter, preceded by a colon
  • After the close parenthesis of max's parameter list you'll find another ": Int" type annotation. This one defines the result type of the max function itself.
  • Note that Java's ++i and i++ don't work in Scala. To increment in Scala, you need to say either i = i + 1 or i += 1
  • def max2(x: Int, y: Int) = if (x > y) x else y
  • ()Unit
  • If a function literal consists of one statement that takes a single argument, you need not explicitly name and specify the argument.
  • args.foreach(println)
  • As demonstrated here, Scala's if expression can result in a value, similar to Java's ternary operator.
  • To summarize, the syntax for a function literal is a list of named parameters, in parentheses, a right arrow, and then the body of the function. This syntax is illustrated in Figure 2.2.
21 annotations
  • Now let’s run the app in the background, in detached mode:
  • These portable images are defined by something called a Dockerfile.
  • This port remapping of 4000:80 is to demonstrate the difference between what you EXPOSE within the Dockerfile, and what you publish using docker run -p
  • Accessing the name of the host when inside a container retrieves the container ID, which is like the process ID for a running executable.
  • docker build -t friendlyhello .
  • The tag is optional, but recommended, since it is the mechanism that registries use to give Docker images a version
  • so you need to map ports to the outside world
  • docker run -p 4000:80 friendlyhello
  • Run the app, mapping your machine’s port 4000 to the container’s published port 80 using -p:
  • No matter where docker run executes, it pulls your image, along with Python and all the dependencies from requirements.txt, and runs your code
  • docker run -d -p 4000:80 friendlyhello
  • Now run the build command. This creates a Docker image, which we’re going to tag using -t so it has a friendly name.
  • docker build -t friendlyhello . # Create image using this directory's Dockerfile docker run -p 4000:80 friendlyhello # Run "friendlyname" mapping port 4000 to 80 docker run -d -p 4000:80 friendlyhello # Same thing, but in detached mode docker container ls # List all running containers docker container ls -a # List all containers, even those not running docker container stop <hash> # Gracefully stop the specified container docker container kill <hash> # Force shutdown of the specified container docker container rm <hash> # Remove specified container from this machine docker container rm $(docker container ls -a -q) # Remove all containers docker image ls -a # List all images on this machine docker image rm <image id> # Remove specified image from this machine docker image rm $(docker image ls -a -q) # Remove all images from this machine docker login # Log in this CLI session using your Docker credentials docker tag <image> username/repository:tag # Tag <image> for upload to registry docker push username/repository:tag # Upload tagged image to registry docker run username/repository:tag # Run image from a registry
13 annotations
  • 虽然处理器会对指令进行重排序,但是它会保证程序最终结果会和代码顺序执行结果相同
  • 缓存一致性问题
  • 通常称这种被多个线程访问的变量为共享变量
  • 指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性
  • 也就是说,要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。
  • Java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现。由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。
  • Java提供了volatile关键字来保证可见性
  • 可以通过volatile关键字来保证一定的“有序性”(具体原理在下一节讲述)。另外可以通过synchronized和Lock来保证有序性
  • 通过synchronized和Lock也能够保证可见性
  • happens-before原则
  • 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:   1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。   2)禁止进行指令重排序。
  •  volatile关键字禁止指令重排序有两层意思:   1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;   2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行
12 annotations
10 annotations
  • Overriding methods always use the same default parameter values as the base method. When overriding a method with default parameters values, the default parameter values must be omitted from the signature:
  • the
  • When a function is called with both positional and named arguments, all the positional arguments should be placed before the first named one
  • If a default parameter precedes a parameter with no default value, the default value can be used only by calling the function with named arguments:
  • But if a last argument lambda is passed to a function call outside the parentheses, passing no values for the default parameters is allowed:
  • Note that the named argument syntax cannot be used when calling Java functions, because Java bytecode does not always preserve names of function parameters.
  • Variable number of arguments (vararg) can be passed in the named form by using the spread operator:
  • foo(strings = *arrayOf("a", "b", "c"))
  • // `return Unit` or `return` is optional
  • Only one parameter may be marked as vararg
  • Inside a function a vararg-parameter of type T is visible as an array of T, i.e. the ts variable in the example above has type Array<out T>.
  • Infix notation Functions can also be called using infix notations when They are member functions or extension functions; They have a single parameter; They are marked with the infix keyword.
  • 1 shl 2
  • If a function does not return any useful value, its return type is Unit. Unit is a type with only one value - Unit. This value does not have to be returned explicitly
  • spread operator (prefix the array with *):
  • Local function can access local variables of outer functions (i.e. the closure)
  • To be eligible for the tailrec modifier, a function must call itself as the last operation it performs
  • and you cannot use it within try/catch/finally blocks.
  • When a function is marked with the tailrec modifier and meets the required form, the compiler optimises out the recursion, leaving behind a fast and efficient loop based version instead:
  • Kotlin does not infer return types for functions with block bodies
20 annotations
  • Overriding methods always use the same default parameter values as the base method. When overriding a method with default parameters values, the default parameter values must be omitted from the signature:
  • the
  • When a function is called with both positional and named arguments, all the positional arguments should be placed before the first named one
  • If a default parameter precedes a parameter with no default value, the default value can be used only by calling the function with named arguments:
  • But if a last argument lambda is passed to a function call outside the parentheses, passing no values for the default parameters is allowed:
  • Note that the named argument syntax cannot be used when calling Java functions, because Java bytecode does not always preserve names of function parameters.
  • Variable number of arguments (vararg) can be passed in the named form by using the spread operator:
  • foo(strings = *arrayOf("a", "b", "c"))
  • // `return Unit` or `return` is optional
  • Only one parameter may be marked as vararg
  • Inside a function a vararg-parameter of type T is visible as an array of T, i.e. the ts variable in the example above has type Array<out T>.
  • Infix notation Functions can also be called using infix notations when They are member functions or extension functions; They have a single parameter; They are marked with the infix keyword.
  • 1 shl 2
  • If a function does not return any useful value, its return type is Unit. Unit is a type with only one value - Unit. This value does not have to be returned explicitly
  • spread operator (prefix the array with *):
  • Local function can access local variables of outer functions (i.e. the closure)
  • To be eligible for the tailrec modifier, a function must call itself as the last operation it performs
  • and you cannot use it within try/catch/finally blocks.
  • When a function is marked with the tailrec modifier and meets the required form, the compiler optimises out the recursion, leaving behind a fast and efficient loop based version instead:
19 annotations
  • ::toBeSynchronized
  • A lambda expression is always surrounded by curly braces;
  • One other helpful convention is that if a function literal has only one parameter, its declaration may be omitted (along with the ->), and its name will be it:
  • it
  • A higher-order function is a function that takes functions as parameters, or returns a function
  • Note that the parentheses in a call can be omitted entirely if the lambda is the only argument to that call.
  • If the lambda parameter is unused, you can place an underscore instead of its name: map.forEach { _, value -> println("$value!") }
  • To declare a nullable variable of a function type, enclose the entire function type in parentheses and put the question mark after it: var sum: ((Int, Int) -> Int)? = null
  • However, if you do need to specify it explicitly, you can use an alternative syntax: an anonymous function.
  • If the inferred return type of the lambda is not Unit, the last (or possibly single) expression inside the lambda body is treated as the return value.
  • However, if you do need to specify it explicitly, you can use an alternative syntax: an anonymous function.
  • has to be specified explicitly (or is assumed to be Unit) for anonymous functions with a block body.
  • Function Literals with Receiver
  • A return statement without a label always returns from the function declared with the fun keyword. This means that a return inside a lambda expression will return from the enclosing function, whereas a return inside an anonymous function will return from the anonymous function itself.
  • Kotlin provides the ability to call a function literal with a specified receiver object. Inside the body of the function literal, you can call methods on that receiver object without any additional qualifiers. This is similar to extension functions, which allow you to access members of the receiver object inside the body of the function. One of the most important examples of their usage is Type-safe Groovy-style builders. The type of such a function literal is a function type with receiver: sum : Int.(other: Int) -> Int The function literal can be called as if it were a method on the receiver object: 1.sum(2) The anonymous function syntax allows you to specify the receiver type of a function literal directly. This can be useful if you need to declare a variable of a function type with receiver, and to use it later. val sum = fun Int.(other: Int): Int = this + other Lambda expressions can be used as function literals with receiver when the receiver type can be inferred from context. class HTML { fun body() { ... } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() // create the receiver object html.init() // pass the receiver object to the lambda return html } html { // lambda with receiver begins here body() // calling a method on the receiver object }
15 annotations
  • e call site.
  • e
  • The inline modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call site
  • The inline modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call site.
  • but noinline ones can be manipulated in any way we like: stored in fields, passed around etc.
  • reified type parameters,
  • noinline
  • a bare return is forbidden inside a lambda, because a lambda can not make the enclosing function return:
  • as
  • A type that does not have a run-time representation (e.g. a non-reified type parameter or a fictitious type like Nothing) can not be used as an argument for a reified type parameter.
  • Note that some inline functions may call the lambdas passed to them as parameters not directly from the function body, but from another execution context, such as a local object or a nested function. In such cases, non-local control flow is also not allowed in the lambdas. To indicate that, the lambda parameter needs to be marked with the crossinline modifier: inline fun f(crossinline
  • MyTreeNode::class.java
  • Normal functions (not marked as inline) can not have reified parameters
  • the public API inline functions are not allowed to use non-public-API declarations, i.e. private and internal declarations and their parts, in their bodies.
  • An internal declaration can be annotated with @PublishedApi, which allows its use in public API inline functions. When an internal inline function is marked as @PublishedApi, its body is checked too, as if it were public.
  • You can also annotate an entire property, which marks both of its accessors as inline: inline var bar: Bar
  • The inline modifier can be used on accessors of properties that don't have a backing field
17 annotations
  • by map
  • Delegated properties take values from this map (by the string keys –– names of properties):
  • The handler passed to the vetoable is called before the assignment of a new property value has been performed.
  • For a read-only property (i.e. a val), a delegate has to provide a function named getValue that takes the following parameters: thisRef — must be the same or a supertype of the property owner (for extension properties — the type being extended); property — must be of type KProperty<*> or its supertype. this function must return the same type as property (or its subtype).
  • Providing a delegate (since 1.1)
  • This works also for var’s properties if you use a MutableMap instead of read-only Map:
  • Local Delegated Properties (since 1.1) You can declare local variables as delegated properties. For instance, you can make a local variable lazy: fun example(computeFoo: () -> Foo) { val memoizedFoo by lazy(computeFoo) if (someCondition && memoizedFoo.isValid()) { memoizedFoo.doSomething() } } The memoizedFoo variable will be computed on the first access only. If someCondition fails, the variable won't be computed at all.
  • For a mutable property (a var), a delegate has to additionally provide a function named setValue that takes the following parameters: thisRef — same as for getValue(); property — same as for getValue(); new value — must be of the same type as a property or its supertype
  • Both of the functions need to be marked with the operator keyword.
  • this::prop is a reflection object of the KProperty type describing prop itself.
10 annotations
  • class
  • val c = MyClass::class
  • The reference is a value of type KClass.
  • To obtain a Java class reference, use the .java property on a KClass instance.
  • Bound Class References (since 1.1)
  • we can also pass it as a value, e.g. to another function. To do this, we use the :: operator:
  • ::isOdd
  • class
  • :: can be used with overloaded functions when the expected type is known from the context
  • Alternatively, you can provide the necessary context by storing the method reference in a variable with an explicitly specified type: val predicate: (String) -> Boolean = ::isOdd // refers to isOdd(x: String)
  • If we need to use a member of a class, or an extension function, it needs to be qualified. e.g. String::toCharArray gives us an extension function for type String: String.() -> CharArray.
  • val c = MyClass::class
  • The reference is a value of type KClass. Note that a Kotlin class reference is not the same as a Java class reference. To obtain a Java class reference, use the .java property on a KClass instance.
  • Bound Class References (since 1.1)
  • but we can also pass it as a value, e.g. to another function. To do this, we use the :: operator:
  • :: can be used with overloaded functions when the expected type is known from the context
  • If we need to use a member of a class, or an extension function, it needs to be qualified. e.g. String::toCharArray gives us an extension function for type String: String.() -> CharArray.
  • For a mutable property, e.g. var y = 1, ::y returns a value of type KMutableProperty<Int>, which has a set() method
  • println(strs.map(String::length)) // prints [1, 2, 3]
  • println(prop.get(A(1))) // prints "1"
  • To access a property that is a member of a class, we qualify it:
  • Constructors are referenced by using the :: operator and adding the class name.
  • Bound Function and Property References (since 1.1)
  • The expression ::x evaluates to a property object of type KProperty<Int>, which allows us to read its value using get() or retrieve the property name using the name property.
  • A property reference can be used where a function with no parameters is expected:
  • println(String::lastChar.get("abc")) // prints "c"
26 annotations
  • Note that Kotlin does not have a new keyword.
  • All classes in Kotlin have a common superclass Any
  • open
  • On the JVM, if all of the parameters of the primary constructor have default values, the compiler will generate an additional parameterless constructor which will use the default values.
  • A class in Kotlin can have a primary constructor and one or more secondary constructors
  • If the primary constructor does not have any annotations or visibility modifiers, the constructor keyword can be omitted:
  • class Customer public @Inject constructor(name: String) { ... }
  • The class can also declare secondary constructors, which are prefixed with constructor
  • ate to the primary constructor, either directly or indirectly through another secondary constructor(s)
  • The primary constructor cannot contain any code. Initialization code can be placed in initializer blocks, which are prefixed with the init keyword:
  • Destructuring Declarations
  • In fact, for declaring properties and initializing them from the primary constructor, Kotlin has a concise syntax:
  • If the constructor has annotations or visibility modifiers, the constructor keyword is required, and the modifiers go before it:
  • If the class has a primary constructor, each secondary constructor needs to delegate to the primary
  • Any is not java.lang.Object; in particular, it does not have any members other than equals(), hashCode() and toString()
  • If the class has a primary constructor, the base type can (and must) be initialized right there,
  • The open annotation on a class is the opposite of Java's final: it allows others to inherit from this class. By default, all classes in Kotlin are final
  • In a final class (e.g. a class with no open annotation), open members are prohibited.
  • A member marked override is itself open
  • Kotlin requires explicit annotations for overridable members (we call them open) and for overrides:
  • open fun v()
  • override fun v() {}
  • If you want to prohibit re-overriding, use final
  • and they must have a compatible type
  • Each declared property can be overridden by a property with an initializer or by a property with a getter method.
  • interface Foo { val count: Int }
  • Destructuring
  • Inside an inner class, accessing the superclass of the outer class is done with the super keyword qualified with the outer class name: super@Outer:
  • super<Base>
  • You can also override a val property with a var property, but not vice versa
  • Destructuring Declarations
  • if a class inherits many implementations of the same member from its immediate superclasses, it must override this member and provide its own implementation
  • we do not need to annotate an abstract class or function with open – it goes without saying.
  • In Kotlin, unlike Java or C#, classes do not have static methods
  • If you need to write a function that can be called without having a class instance but needs access to the internals of a class (for example, a factory method), you can write it as a member of an object declaration inside that class.
35 annotations
  • ::toBeSynchronized
  • A lambda expression is always surrounded by curly braces;
  • One other helpful convention is that if a function literal has only one parameter, its declaration may be omitted (along with the ->), and its name will be it:
  • it
  • A higher-order function is a function that takes functions as parameters, or returns a function
  • Note that the parentheses in a call can be omitted entirely if the lambda is the only argument to that call.
  • If the lambda parameter is unused, you can place an underscore instead of its name: map.forEach { _, value -> println("$value!") }
  • To declare a nullable variable of a function type, enclose the entire function type in parentheses and put the question mark after it: var sum: ((Int, Int) -> Int)? = null
  • However, if you do need to specify it explicitly, you can use an alternative syntax: an anonymous function.
  • If the inferred return type of the lambda is not Unit, the last (or possibly single) expression inside the lambda body is treated as the return value.
  • However, if you do need to specify it explicitly, you can use an alternative syntax: an anonymous function.
  • has to be specified explicitly (or is assumed to be Unit) for anonymous functions with a block body.
  • Function Literals with Receiver
  • A return statement without a label always returns from the function declared with the fun keyword. This means that a return inside a lambda expression will return from the enclosing function, whereas a return inside an anonymous function will return from the anonymous function itself.
  • Kotlin provides the ability to call a function literal with a specified receiver object. Inside the body of the function literal, you can call methods on that receiver object without any additional qualifiers. This is similar to extension functions, which allow you to access members of the receiver object inside the body of the function. One of the most important examples of their usage is Type-safe Groovy-style builders. The type of such a function literal is a function type with receiver: sum : Int.(other: Int) -> Int The function literal can be called as if it were a method on the receiver object: 1.sum(2) The anonymous function syntax allows you to specify the receiver type of a function literal directly. This can be useful if you need to declare a variable of a function type with receiver, and to use it later. val sum = fun Int.(other: Int): Int = this + other Lambda expressions can be used as function literals with receiver when the receiver type can be inferred from context. class HTML { fun body() { ... } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() // create the receiver object html.init() // pass the receiver object to the lambda return html } html { // lambda with receiver begins here body() // calling a method on the receiver object }
15 annotations
  • there are no implicit widening conversions for numbers
  • NOTE: Octal literals are not supported.
  • c.toInt() - '0'.toInt() // Explicit conversions to numbers
  • Characters are represented by the type Char. They can not be treated directly as numbers
  • t,
  • the arrayOfNulls() library function can be used to create an array of a given size filled with null elements
  • // Creates an Array<String> with values ["0", "1", "4", "9", "16"] val asc = Array(5, { i -> (i * i).toString() })
  • unlike Java, arrays in Kotlin are invariant. This means that Kotlin does not let us assign an Array<String> to an Array<Any>,
  • To create an array, we can use a library function arrayOf() and pass the item values to i
  • i
  • Another option is to use a factory function that takes the array size and the function that can return the initial value of each array element given its index:
  • Kotlin also has specialized classes to represent arrays of primitive types without boxing overhead: ByteArray, ShortArray, IntArray and so on. These classes have no inheritance relation to the Array class, but they have the same set of methods and properties.
  • A raw string is delimited by a triple quote ("""), contains no escaping and can contain newlines and any other characters:
  • NaN is considered equal to itself NaN is considered greater than any other element including POSITIVE_INFINITY -0.0 is considered less than 0.0
  • $. To encode any other character, use the Unicode escape sequence syntax: '\uFF00'.
  • As a consequence, smaller types are NOT implicitly converted to bigger types. This means that we cannot assign a value of type Byte to an Int variable without an explicit conversion
  • The following escape sequences are supported: \t, \b, \n, \r, \', \", \\ and \$
17 annotations