字幕列表 影片播放 列印英文字幕 ROMAIN GUY: Good morning, everyone. [APPLAUSE] Wait, don't cheer us. Cheer the next speakers. So I'm Romain Guy, representing the Platform team on Android, and this is Tor Norbye representing the Tools team. But you're not here for us. You are here for very special speakers. TOR NORBYE: Yeah, so Romain and I have been incredibly excited about this official announcement of Kotlin. We both love Kotlin, in case you hadn't noticed already. And we don't take any more time from the speakers of honor. So without further ado, here they are. [APPLAUSE] HADI HARIRI: Hello, everyone. Aw, that's nice. So I was thinking the other day, the first time that I ever did a talk on Kotlin, it was like 4 and 1/2 years ago. And they gave me a room for 900 people and 7 people showed up. So it's kind of nice to see more of you show up today. Thank you. [APPLAUSE] Anyway I've got roughly around 30 minutes. Actually, a little bit less. 28 minutes to give you a whirlwind tour of Kotlin, so I'm not going to cover the entire language. I'm going to try show you as much as I possibly can and how you can use it and where it provides you with some benefits, OK? So I'm going to try and do it all with live coding, so if it all goes terribly wrong, there's a Google video-- I mean there's a YouTube video of this somewhere as well. So you can watch that. OK, so we're going to start with something very simple that you've already seen, data class. And I'm in a file called main. So data class, I'm going to create a new type called money, and it's going to happen amounts which is of type Int. I know, don't say anything for now. And it's going to have a currency of type string. OK? And this is both properties, and they're going to be read only properties. So this is something that you're already familiar with. It's essentially a data class. Let's go ahead and compare that to a Java one that I have done earlier. So split vertically. And let's get the Java money up-- actually, let's go down this side. Java money-- so there you go. That's kind of the equivalent of what I've just written, right. A JavaBean essentially, a data class that provides two getters. They're immutable, so they're read only. And this data modifier over here, what that's doing is essentially giving me a whole bunch of things, like the to string, it's giving me the clone, which in Kotlin it's called copy, it's doing the equals, it's doing the hashCode. Now you say, OK, well that's great. Brilliant, but why do I need that? Because any good IDE is going to generate that for me. It is true, it does. But the problem is that that's code you're going to have to maintain. And every time you add a new property, you're going to have to go back and change that code. And the other issue that you're going to have is you don't know, in fact, if that code is the standard stuff that Kotl-- that IDE has generated for you, or you've tweaked it a little bit. OK? So it's not just about saving on typing on the first line. Right. Now what I'm going to do is go ahead and create a function main. Let's close this guy over here. And this is the top entry point of Kotlin, so you have a public static void main in a class. You don't need that in Kotlin. So in Kotlin, you can put everything in the top level. It's kind of like JavaScript in a good way. And so you don't have to-- and I want to reiterate, every function and everything that I'll show you today, I'm going to just add it in the file as a top level thing, but that doesn't mean that you don't have any more member functions. Anything, any class, even a data class can have member functions. But for brevity and for the purpose of what I'm showing you, I'm just going to put it as top level, OK? So I'm going to create a new instance of money. We're going to call it, for example, tickets. And I'll say Money 100, and it's going to be dollars, right? And I'll get into the explicit type here, but essentially here what I'm doing is type inference. So Kotlin is very strong in type inference, and as much as it can infer, it will for you. So you don't have to explicitly tell the type. And then I'll say, for example, popcorn. Let's say tickets, copy, right? So what that's going to do is basically copy the previous one for me, and all of the properties. So if I don't pass any parameters in, it's going to just take the same values as it has before, OK. So I can pass in a new parameter and say, you know, in Spain, for example, popcorn is seven times the price of the entry of the cinema, so that's going to be like 500 euros. Right? And now I can do things like, for instance, if tickets is not equal to popcorn, then println "they are different!" So what this is doing is a property comparison one by one. It is not doing a point of comparison. For point of comparisons, we have the triple equal, right? Different to JavaScript, there isn't a chart of 600 different positions you have to remember. And this, by the way, is font ligature, so don't get confused with that, we didn't introduce a new symbol. OK. So I can go ahead and just run this, and I get they are different. And if I change this to 100 and I put this as dollars and I run this, it's going to say to you that nothing, because they are the same. OK? Now one of the features we keep boosting about is the interop between Java and Kotlin. So we have this Java money one over here, so I'm going to go ahead and create an instance of it. I'll say javaMoney equals javaMoney, and it will be 100 and it'll be dollars. And then if I do javaMoney, you can see that I don't have any getters. Well, I do have, actually, a getter, so I can do get amount, but if I write getAmount, complete it, the IDE's already going to replace that for property, because we don't have really like getters and setters, we just have properties. So that's consuming Java from Kotlin. And if I go over to the Java over here, and let's go ahead and create a public statics void main, and I'll do-- so let's see, I've got to declare the type. Money equals new money, 100, and dollars, and-- OK. That's the other thing. Semicolons in Kotlin are optional. And the reason they're optional is so that you can have endless arguments over whether you should use them or not. We are trying to compete with JavaScript there. OK, so money.getAmount. So now I'm using a Java type-- sorry, a Kotlin type from Java, so I'm getting the getters and the setters, right? So idiomatic depending on how you are using it. And that's just different Java files, different Kotlin files in a single project, working seamlessly without any issues. Right, so now let's go ahead and create some functions. So I'm going to create a function called sendPayment. That takes a money-- and Money-- and it's going to println the money out. And of course we have string interpolation, so I could say, sending money.amount. And you don't have to put these curly braces if it's just a single property that you're passing in, as we'll just see in a moment. So now I can call this and say, for example, sendPayment, tickets, right? Now Kotlin, we also have-- notice one thing here, I'm not defining the return type. By default it's unit, which is kind of like void, but it's not. It's actually a object which is essentially a singleton, a single instance of an object. And if it is a unit, you don't have to put it there, right? So I'm going to add a new parameter here and I'm going to say, for example, with message. And this is gone to have string, and you can have default parameters. So here, notice that there's no compilation error because I made a default parameter. This saves you a lot in times of overloaded function, overloaded member functions, right? I can just have default parameters and then do what I want. And you can have multiple default parameters. And since you can have multiple default parameters and you can alternate which one you want to pass in, you can also do names parameters. So, in fact, I could say message equals "Good luck!" and money equals tickets. And this is kind of useful as well when you are using-- you're talking to legacy code, for example, some function that you can't modify, and it's got 600 parameters, and they're probably 500 of them are true and false Booleans, it kind of gives you some insight into what parameters I'm passing in in every position. Oh yeah. I love it when people crap-- clap. [LAUGHTER] And I'm thinking to myself, well this is going well. Anyway, right, let's go. Edit that out, like adult supervision. Right. One other thing with Kotlin is that when we have functions that are really, really easy, like essentially returning a single value, you can just do single expression functions. So I omit the return type explicitly, I omit the curly braces, and I just return the actual function that I want to do. OK? So, in fact, the concept of expression comes in many places in Kotlin. So for instance, let's create another function that's called convert ToDollars. convertToDollars, and this is going to take a money. Money, and it's going to return Money. And then what we're going to do here is a when statement, so that's essentially case, right. So when money_currency is dollars, then we'll do return money as is, right, because I don't need to do anything. And if it's EUR, then what I'm going to do is return, we're going to do money.amount times-- sorry, I've got to create a new instance. Money, and then it's going to be money.amount times BigDecimal 1.10, and then that's going to be dollars. And else, throw IllegalArgumentException, "not the currency you're interested in!" So this you can actually treat a when as an expression. So I can remove this return over here, remove this return over here, put it just here, and then this just makes the when always return an expression. And in fact, you can even remove the return here, remove the Money here, and remove that there, and you get a single expression. OK? Single expression function. Now one thing that you notice here that this is giving me an error because this is-- I'm trying to operate a BigDecimal with an int, so we're going to go and refactor this, and we're going to call it BigDecimal, OK. Now talking about BigDecimal, oh, here we go. BigDecimal, BigDecimal 100 and BigDecimal-- I love typing BigDecimal. I love it. So we've got this over here. Now if you look at, actually, BigDecimal-- so if I create a new BigDecimal, we'll call it bd1 equals BigDecimal 100. You can see the bd1 gives me a whole bunch of functions like divide, multiply, all of these things. What if I wanted to do something like a percent? I wanted a percentage of BigDecimal. Now normally you would, basically, inherit from that and then create your own version and have all of these things, but in Kotlin, one of the features that we've added-- and if you're familiar with C#-- is called extension functions, which essentially means that you can take any class, any type, and extend it. So I can take a function of BigDecimal, I put the name of the class that I want to extend, and I say I want to do a percent. And what is the percentage that I want to do, for example, an integer, and then it would be, let's see. So given that this is an extension function, it's going to have an instance of that class, of that object, right. So I can use that, reference that with this. And I say this multiplied by the percentage-- and then this has got to to be wrapped in a big decimal again-- percentage. And then that divide-- and then another BigDecimal 100. And what's wrong with this, that should be percentage. So percent-- age. OK, so now what happens is that on bd1, I have percentage. OK. And I could do percent 7, and that would give me a certain percent. And that extension function gets included anywhere where it is defined in the package. So here in this case, I have it in com.jetbrains.gio and that will get included there. So you can create extension functions, and we'll see that the standard library actually consists of a whole bunch of extension functions. Now we'll take this one step further, because I can actually extend everything. So let's go ahead and extend an integer. So I'll say fun Int. percentOf and here will do the reverse. So I want like 10 percent of something, right. So I'll say money, for instance, I want 10 percent of money. And that's going to return the-- let's see, it's going to return money. Then it will be amount.multiply and then here it's going to reference the actual instance, so it will be this-- and again, this has to be wrapped in BigDecimal, and then divide by 100. OK. And I think I got that in the right order. If the implementation is wrong, doesn't matter. Who cares. Anyway, so now what I can do is something like this. Seven percentOf BigDecimal 100. OK? Oh no, sorry. Money. So I can do Money-- no, don't clap yet. Money. Oh, let's just take the money I have. 7.percentOf(popcorn). OK, nice? Let's do a little bit nicer. What I want to do is, in fact, something like this. I want to do 7 percentOf popcorn. That would be nice. And you can actually do that. You see that little wiggly there? Squiggly? Alt, Enter, add 'infix'. There you go. OK so any extension function that has a single parameter can be called an infix notation. And what I've done is essentially add the infix over there. And this is some of the things that allow you know, with Kotlin, to kind of create the whole DSL approach to things. Right. So one thing that I hated doing here is all of this BigDecimal. That's a pain. And in Kotlin, when you want to create a value of type long, you can say long 100L, and that will be of type long. And it would be awesome if I could do like, bd2 equals 100BD, but you can't, and we don't have that built in. But what we do have in Kotlin is called extension properties. So they're exactly like extension functions, except they extend with properties. So I could do something like .bd, right? And now-- or let's, so now-- see, it even says, do you want to create an extension property on type integer? Yes. So this is going to return a BigDecimal. And then here, I'm going to do return BigDecimal, and this, which is the instance. And I can, in fact, convert this to an expression to make it easier. So there you go. Now I have 100.bd. So when I'm passing that in, it looks much nicer than BigDecimal, I could just do 100.bd. OK? And one other thing around functions that you can do is, there are certain operators that you can extend. So you can extend, for example, the plus operator. And what I'm going to do is I'm not going to type this out, I've just got a nice little thing that has done that for me. See how fast I am at typing? So what I've essentially done is now override the plus operator for money. So now I can say costs equals tickets plus popcorn, right. And that allows me to add to monetary amounts. OK, you could do that with plus, minus, multiply. A bunch of built-in conventions that you can follow for certain operators that allow you to do that. OK. So we've been creating a whole bunch of types here. And let me go ahead and delete all the stuff so we can focus. We've been creating a bunch of types here. Notice that in any of these types that I've created, I've never actually specified the type, and you can. So I can do, for instance, val train costs, for example, train is of type Money and then initialize it to some new value, right. 100.bd, and then dollars. Now if I go ahead and do train=null, it's going to give me an error. And it's going to give me actually two errors. One of them is because that's immutable variable. So I can fix that. I've now made this mutable. You see that the IDE underlines it, so it wants to point it out that this is really something you're going to shy away from. We don't enforce immutability in Kotlin, but we kind of do recommend it. Like all of the lists and all of these things are immutable by default. So I can't assign null in Kotlin because Kotlin tries to get rid of the null pointer exception by saying that types aren't nullible by default, right. But there are times when you want to have a type that is nullable for whatever reason, you're bored. And you can add a question mark, and then that will give you the ability to assign null to that type. Now normally when you're working with Kotlin, you probably don't want to do this. You probably don't want to have nullable types, but since we're interopping with Java, Java can be null. So if I create a function here that is, for instance, fun javaMoney, and that takes money of type JavaMoney and does whatever with it. So let's say I do println money.amount is valid. So this can be null. It could, if it's called by an instance that a function that, for example, is returning this type, it could be null. And you can indicate that by adding the question mark. When you do that, you can see that the IDE is going to give you error. It says only safe operators, or the double exclamation mark are valid here, because it's essentially saying you're going to run into a null reference exception. So there's two ways you can solve this. First of all, you can say, for example, money, not null. And then do a if not null, then go ahead and operate with it. Put this one upstairs in there. OK. That's one way. Or the shorter way is just to use the safe operator or Elvis operator, which is over here. So now we just say if money is not null, then do something. Now if you want to have fun, you can also do that. And that says, I know it's null, but I want to shoot myself in the foot. OK? And you've got to be careful with that, because a lot of times when people start with Kotlin, they get all of this little squigglies over here, and they're like, well I actually don't know if it's going to be null because I really want it to not being null. So I'm not going to handle the case where it's not null, so I'll just do that. And then they run the app and they're like, wait a minute, you set Kotlin got rid of null reference exceptions. Yes. OK. What else. Right. So let's switch to some other stuff, like higher order functions. Now you're all familiar with a high order function, which is basically a function that takes a function or returns a function, and we have those in Kotlin. So we can say findEmails users List of User, and then I'll create a new function, which is a predicate. So I'm passing in a function here, right, a function that takes a string and returns a Boolean. OK? And then this probably is going to return a list of users. So essentially what I'm doing is I'm filtering on a list of users. Right. So I'll do this later. To do later. OK. This to do, by the way, is built in. You can use it instead of not implemented exception-- non implemented error. And it does a additional thing that we won't get into, but nothing is actually very nice in Kotlin, but we won't cover that now. It's nothing to worry about. I just made that up. OK. OK, thank you. So now how do I use this? I can do findEmails, right, and I'll say-- I actually have a user, let's create some users here. So usersFromJSONFile. And I have some uses over here, so users.json. So this is actually a function that I have ready, which is basically using json to read some users from a file. And this is a typical data classs that you've already seen, the only new thing here is that this also got an enum class with a property Role. OK? So now I can do like users, and then I'll pass in that function. Now I can pass in the name function by using the column column reference, or a can pass in a lambda. And in Kotlin, lambda follows this syntax. You pass in the parameter name, and then you say, for example, the parameter name ends with right .com. So I'm getting a list of users that end with .com. Now when you have a single parameter in Kotlin, you can actually omit having to explicitly mention it and replace it with it. So similar to Groovy, you can just use it. The other thing that you can doing in Kotlin is when the last parameter to a function is another function, you can actually not include it in the brackets. So it feels a little bit like it's outside. And this is, again, one of the characteristics that allow us to create nice DSLs, and you can even do this like multi-line. So if you look at findEmails now, in a sense it could actually feel like it's part of the language, but it isn't, it's actually a function. And when we implemented aasynchronous programming with coroutines, we didn't like-- you know, if you're familiar with C#, C# does their sync or wait, there are keywords in the language. In Kotlin, there are not, they're essentially just functions. So that gives you the flexibility of deciding how you want to do different things. Now you don't have to do all of these things, because all of these things are built-in. So, for example, if I say dotComUsers, I say users.filter, and you can see that as I complete this, it actually opts for the version of including out of the parameter. So I can say the email.endsWith .com. And then I can go and sort by it.id. And then let's go ahead and do, for example, map that to a pair of it.email and it.username. OK? So all of these functions are actually built in in that small standard library that ships, that you're not going to problems on Android, it's very small. And they're all in, essentially, extension functions on top of collections, generic collections. So you have all of those functional things that are very in fashion these days. And so this obviously gives you a pair, and in fact, you can do this even nicer, if instead of doing pair, it, to. So a map, email, to username. And guess what it is? It's just an infix function that creates a pair. OK.? Now sometimes I don't go through the whole map. I just want to, for example, say get back a single element. And what you can also do is destructure classes, data classes in Kotlin. So I could do something like id, username, and email. OK and then I can just use the ID. And this is great, but then the IDE complains and says, well this variable is never used. In that case, you can actually replace that with an underscore. So there you go. And you can destructure the values you want. Anything that you don't want to use, replace with an underscore and you're good to go. Right. So what else can I show you? OK. So I've got some other code here. If you're familiar with the concept of algebraic data types, it's essentially a type that can be of one type or another, like for instance a Boolean. Now in Kotlin, the way that we do that is with coclasses. But before I get into that, let me go ahead and do an open here. Notice the first thing here, that user result is giving me an error. Because by default in Kotlin, you cannot inherit from classes. So all classes are essentially final. If you want to inherit from classes, you have to use the open modifier, right? Now I've used the sealed, and the sealed is essentially saying that this is the hierarchy that user result has. Like, there's not going to be any other class anywhere that is going to inherit from user result. Everything that's going to inherit from user result has to be in the same file, or you can make these, of course, subclasses. So I could move this up there and this would be a subclass, but then I would have to prefix it with user result. OK. Now I've just created it as a class outside, So why would I want to do this? Because it looks good. No. Well, this is actually good because when you're doing some things, it's often like your invoking a function and you're like, OK, well if it's successful, I want it to return a value. If it's null, I'm going to pass in a message. And then you get this type that contains the values that you want to return when it's successful, it contains the types that you want to return when there's a message, and then you've got to figure out the semantics of which properties are applied to an error situation, which properties are applied to non-error situation, or you can just throw an exception. In this case, you can use a function that basically returns two types. And then based on the result, do different things. So here I say, for instance, when-- let's create an instant val, result equals userresult-- sorry, retrieveusers. So now I can do when result is success, then we're going to do, for instance, well we're going to get the result, and then we're going to do users forEach println the name. OK? username. And then we're going to do a failure. Result println result.message. OK? So now based on the result, based on the type that is returned to me, I can do different things. I notice one thing over here, that this has gone green. I don't know if you see it on the big screen, but this has gone green. And this is a Smart cast. So that's another thing that we have in Kotlin, and you saw that when I was doing the null check, that is said this is not null, because it is Smart casting. So you don't have to explicitly come over here again and say, oh, I know that this is of type success, let me go ahead and cast this to type success, to then access the property. The compiler will do that for you, that's what the smart casting is. Right. And last but not least, before hand it off to Andrey quickly just mention, also, that a lot of the things you've been seeing with the filter map, all of those things, those are essentially eager evaluation. But we also have the ability to do lazy evaluation. So I can do val, for example, sorry, generateSequence, and then have something, for instance, 1. And then here, we'll do it times 10, and then we'll do values. Now I'll say values.take(10), and then forEach println it. Now this is essentially creating a sequence, a generator that is infinite. It's never going to stop. It's going to start at one and multiply by 10. But what I'm saying here is that I just want to take 10 elements and then print them out. And what it will do is basically consume that until it hits 10. It prints out-- go away-- it prints out a beautiful Christmas tree that's one-sided. OK, pyramid, whatever, and stops there. And anything that you have, like for example, the users that we had, users from Jason, users.json, you can say asSequence and convert it into lazy evaluation as well. OK? That's all we have the time to show you today. Obviously, there's way more to the language. Go online, learn everything about it, and thank you very much. And I'll hand it off to Andrey. ANDRY BRESLAV: Thank you, Hadi. Hello, everybody. So as you've seen Kotlin already has many things in store, but I am the nasty person who adds new futures before you learn the existing ones. So I'll be tell you stories now, but I'll need to find a clicker. Do I have a clicker? No, OK. OK, so I'll be telling stories without a clicker. So my job here is to tell you about what we're going to have in the future versions of Kotlin-- oh, thank you very much. And the first big thing we're working on now is platforms, supporting different platforms. So historically, Kotlin compiles to JVM bytecode, same as the Java programming language. So we can run a server on the desktop and of course on Android. And it's just the same bytecode everywhere, this is why we can run old versions of Android as well as new ones. But the story doesn't end there, because we are adding new platforms. And recently, we've added-- but God doesn't like platforms-- recently we added JavaScript, which means Kotlin can now compile to JavaScript code and run in the browser or on node.js. So now we support three, major, very popular virtual machines, JVM, Android Dalvik, and JavaScript VMs. But there are many US cases where a virtual machine is not practical or is simply unavailable. For example, for iOS, virtual machines are severely restricted. You can't do dynamic code generation, or for a small embedded system, a VM doesn't fit in. Or for, say, a Linux command line tool, the VM will be a starting tool for too long. So it's a no go there, and that's why we're working on something called Kotlin/Native, it's currently available as a technology preview. And there, we basically use LVM to compile Kotlin down to a native code, to stand along binaries that can run on different platforms. Currently, we support iOS, Linux, and Mac, and Windows is in the works. So this is taking us to this vision with Kotlin, when it can run inside every component of a modern application, on any platform you like. So think full stack web applications with the server and the client both written in Kotlin, or think reuse code between mobile platforms, Android and iOS for example. Or mix the two previous use cases and get like a real multiplatform scenario. So our vision for Kotlin is having different models in the same project compile to a different platforms. And of course, you we want to share code there, right? Because if you support so many different things, you want to run the same code in different places. And we're working on making that possible. But there is a very important thing, because previously, many projects tried to unify platforms. And this often ends up being like the least common denominator, when you take only things that are available on all platforms, you are basically stuck with a minimal interface, and that's something we don't want to have there. So we want you to be able to use all the platform-specific fancy APIs like the newest version of Android or something else as much as you like. And if you want to share some code, only then you have to resort to some common APIs. So the idea there is that you have a common model with lots of business logic and stuff, and it can work side by side with a platform specific model written also in Kotlin, and those two can talk to each other. So when you need, you leverage the platform API, and when you need, you use the Kotlin code. So take away here, our future is multiplatform. Next-- oh. Next big thing is couroutines. So the rationale there is pretty straightforward, everybody needs to write asynchronous code, right? Because the world is too big now for sequential execution. And it's our reality, but it's hard, right? Who has written asynchronous code? Quite so many hands. Those of you who don't actually will be doing this very soon. And the problem is, it's rather hard, actually, to write sequential code. Or it was hard before languages learned to support you in doing that, because a language can help you there a lot. So basically what we have with coroutines in Kotlin, you're right asynchronous code the same way you write synchronous code. So what do you use in synchronous code? Loops, ifs, breaks and continues, things like that, right? And it's the same things you're using with coroutines for asynchronous code, so that the language keeps track of everything and you don't have to express an intricate control flow for a synchronous computation in your code. No call backs, no fancy functional structures, it's just plain old sequential-looking code. And isn't it cool? Thank you. So the idea with coroutines is that you basically have the same abstraction for asynchronous and synchronous. And also, it's a nice metaphor to think of them as almost free of threads. Like here is the only code example I'm showing you. Basically, very many things that are traditionally done with threads can be done with coroutines, but coroutines are extremely cheap. So here on the slide, I have a code that creates 100,000 coroutines. Think about that. 100,000 coroutines existing in parallel, and each one of them waits for one second and returns one. So this program completes in, completes in one second, almost one second, because all the coroutines wait in parallel, of course. But if you tried to do this with threads, it just doesn't work. 100,000 threads don't fit into memory. That's it. So with coroutines, it's a win-win situation. You get lots of performance, so it's very efficient, and the code is simple. So take away here, check out coroutines, because our future will likely to even more asynchronous than our present. So I'm almost done, and if you want to learn more about Kotlin, check out our website. We have a section for Android. And also, we'll have a question and answer session right after this talk, so come over to the Developer sandbox, section C. Myself and Hadi will be answering questions there. So thank you very much for your attention.
B1 中級 美國腔 Kotlin介紹(Google I/O'17 (Introduction to Kotlin (Google I/O '17)) 157 9 nctuharuka 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字