
1、来了老弟?
2、映射为List: map{},mapIndexed{},mapNotNull{},mapIndexedNotNull{}
val numbers = setOf(1, 2, 3)
println(numbersmap { it 3 })
//[3, 6, 9]
println(numbersmapIndexed { idx, value -> value idx })
//[0, 2, 6]
3、双路合并
(1)zip()将两个集合中具有相同位置的元素构建配对。
val list1 = listOf(1, 2, 3)
val list2 = listOf("a", "b", "c")
val list = list1zip(list2)
println(list)
//[(1, a), (2, b), (3, c)]
val list3 = list1zip(list2) { l1, l2 -> "${l1}----${l2}" }
println(list3)
//[1----a, 2----b, 3----c]
(2)反向转换unzip(),listunzip()得到一个Pair对象
val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
println(numberPairsunzip())
//([one, two, three, four], [1, 2, 3, 4])
4、关联
根据集合元素和与其关联的某些值构建 Map。
(1) Map associateWith() 。其中原始集合的元素是键,值来自给定的转换函数。 如果两个元素相等,则仅保留最后一个。
val numbers = listOf("one", "two", "three", "four")
val map = numbersassociateWith { itlength }
println(map)
//{one=3, two=3, three=5, four=4}
(2) associateBy()。 键来自给定的转换函数,原始集合中的元素是值。也可以使用keySelector和valueTransform设置键和值。两个元素相等,则仅保留最后一个。
val numbers = listOf("one", "two", "three", "four")
println(numbersassociateBy { itfirst()toUpperCase() })
//{O=one, T=three, F=four}
println(numbersassociateBy(keySelector = { itfirst()toUpperCase() }, valueTransform = { itlength }))
//{O=3, T=5, F=4}
(3)associate()。键和值都是根据集合元素生成的。associate() 会生成临时的 Pair 对象,这可能会影响性能。
data class FullName(val firstName: String, val lastName: String)
fun parseFullName(fullName: String): FullName {
val nameParts = fullNamesplit(" ")
if (namePartssize == 2) {
return FullName(nameParts[0], nameParts[1])
} else throw Exception("Wrong name format")
}
val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")
println(namesassociate { name -> parseFullName(name)let { itlastName to itfirstName } })
//{Adams=Alice, Brown=Brian, Campbell=Clara}
5、打平
flatMap()可以打平集合中对象的某个类型为list的字段的值。
data class StringContainer(val values: List<String>)
val containers = listOf(
StringContainer(listOf("one", "two", "three")),
StringContainer(listOf("four", "five", "six")),
StringContainer(listOf("seven", "eight"))
)
println(containers)
//[StringContainer(values=[one, two, three]), StringContainer(values=[four, five, six]), StringContainer(values=[seven, eight])]
println(containersflatMap { itvalues })
//[one, two, three, four, five, six, seven, eight]
//即可以打平集合中对象的某个类型为list的字段的值
6、字符串表示
(1)joinToString() 根据提供的参数从集合元素构建单个 String。
val numbers = listOf("one", "two", "three", "four")
println(numbers)
//[one, two, three, four]
println(numbersjoinToString())
//one, two, three, four
println(numbersjoinToString("-", "开始", "结束"))
//开始one-two-three-four结束
println(numbersjoinToString("-", "开始", "结束", 3))
//开始one-two-three-结束
println(numbersjoinToString("-", "开始", "结束", 3, "等等"))
//开始one-two-three-等等结束
println(numbersjoinToString("-", "开始", "结束", 3, "等等", { it -> ittoUpperCase() }))
//开始ONE-TWO-THREE-等等结束
(2)joinTo() 执行相同的 *** 作,但将结果附加到给定的 Appendable (可追加的)对象。
val numbers = listOf("one", "two", "three", "four")
val listString = StringBuffer("The list of numbers: ")
numbersjoinTo(listString, "-", "开始", "结束", 3, "等等", { it -> ittoUpperCase() })
println(listString)
//The list of numbers: 开始ONE-TWO-THREE-等等结束
7、过滤
(1)filter()。只能检查集合中元素的值。
val numbers = listOf("one", "two", "three", "four")
val longerThan3 = numbersfilter { itlength > 3 }
println(longerThan3)
//[three, four]
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMapfilter { (key, value) -> keyendsWith("1") && value > 10 }
println(filteredMap)
//{key11=11}
(2)filterIndexed()。可以检查元素的索引和元素的值。
val numbers = listOf("one", "two", "three", "four")
val filteredIdx = numbersfilterIndexed { index, value -> (index != 0) && (valuelength < 5) }
println(filteredIdx)
//[two, four]
(3) filterNot()。使用否定条件来过滤集合。
val numbers = listOf("one", "two", "three", "four")
val filteredNot = numbersfilterNot { itlength <= 3 }
println(filteredNot)
//[three, four]
(4)filterIsInstance<T>() 返回给定类型的集合元素。
val numbers = listOf(null, 1, "two", 30, "four")
println(numbersfilterIsInstance<String>())
//[two, four]
(5)filterNotNull() 返回所有的非空元素。在一个 List<T> 上被调用时,filterNotNull() 返回一个 List<T: Any>。
val numbers = listOf(null, "one", "two", null)
println(numbersfilterNotNull())
//[one, two]
8、划分
partition() – 根据集合中元素的值进行过滤,并且返回一个Pair<List,List>。第一个list表示符合条件的集合;第二个list表示不符合条件的集合。
val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numberspartition { itlength > 3 }
println(match)
//[three, four]
println(rest)
//[one, two]
9、集合元素检查
(1)
如果至少有一个元素匹配给定谓词,那么 any() 返回 true。
如果没有元素与给定谓词匹配,那么 none() 返回 true。
如果所有元素都匹配给定谓词,那么 all() 返回 true。注意,在一个空集合上调用 all() 始终都会返回 true 。
val numbers = listOf("one", "two", "three", "four")
println(numbersany { itendsWith("e") })
//true
println(numbersnone { itendsWith("a") })
//true
println(numbersall { itendsWith("e") })
//false
println(emptyList<Int>()all { it > 5 })
//true
(2)当any() 和 none()不设置条件时, 它们只是用来检查集合是否为空。 如果集合中有元素(即使是null),any() 返回 true,否则返回 false;none() 则相反
10、集合加减:plus与minus
val numbers = listOf("one", "two", "three", "three", "four")
//集合加和,第二个 *** 作数可以是集合,也可以是元素
val plusList = numbers + "five"
println(plusList)
//[one, two, three, three, four, five]
//如果第二个 *** 作数是一个集合,那么移除其元素在原始集合中的 所有 出现。
val minusList1 = numbers - listOf("three")
println(minusList1)
//[one, two, four]
//如果第二个 *** 作数是一个元素,那么 minus 移除其在原始集合中的 第一次 出现
val minusList2 = numbers - "three"
println(minusList2)
//[one, two, three, four]
11、分组
(1) groupBy()
val numbers = listOf("one", "two", "three", "four", "five")
//根据转换函数得到key,value来自于集合的元素
println(numbersgroupBy { itfirst()toUpperCase() })
//{O=[one], T=[two, three], F=[four, five]}
//根据转换函数得到key,value来自于对原有集合元素的转换结果
println(numbersgroupBy(keySelector = { itfirst() }, valueTransform = { ittoUpperCase() }))
//{O=[one], T=[two, three], F=[four, five]}
(2) grouping()
在分组后,对所有的分组进行一次 *** 作。eachCount() 计算每个组中的元素。还有fold()、reduce()、aggregate()等。
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbersgroupingBy { itfirst() }eachCount())
//{o=1, t=2, f=2, s=1}
12、取集合的一部分
(1)slice() 返回给定索引处的集合元素列表。
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbersslice(13))
//[two, three, four]
println(numbersslice(04 step 2))
//[one, three, five]
println(numbersslice(setOf(3, 5, 0)))
//[four, six, one]
(2)take和drop
val numbers = listOf("one", "two", "three", "four", "five", "six")
//从头开始获取指定数量的元素
println(numberstake(3))
//[one, two, three]
//从尾部开始获取指定数量的元素
println(numberstakeLast(3))
//[four, five, six]
//从头开始去除给定数量的元素
println(numbersdrop(1))
//[two, three, four, five, six]
//从尾部开始去除给定数量的元素
println(numbersdropLast(5))
//[one]
(3)takeWhile()和dropWhile()
val numbers = listOf("one", "two", "three", "four", "five", "six")
//不停地获取元素,直到遇到使表达式为false的首个元素。如果首个集合元素便使表达式为false,则结果为空。
println(numberstakeWhile { !itstartsWith('f') })
//[one, two, three]
//从尾部开始,如上
println(numberstakeLastWhile { it != "three" })
//[four, five, six]
//不停地删除元素,直到遇到使表达式为false的首个元素,然后返回剩余的元素。如果首个集合元素便使表达式为false,则返回集合所有的元素。
println(numbersdropWhile { itlength == 3 })
//[three, four, five, six]
//从尾部开始,如上
println(numbersdropLastWhile { itcontains('i') })
//[one, two, three, four]
(4)chunked()
将集合分为指定大小的子集
val numbers = (013)toList()
println(numberschunked(3))
//[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]
val numbers = (013)toList()
//将集合切割成指定大小的子集后,对子集元素进行转换
println(numberschunked(3) { itsum() })
//[3, 12, 21, 30, 25]
(5)windowed()
val numbers = listOf("one", "two", "three", "four", "five")
//检索指定大小的所有可能子集
println(numberswindowed(3))
//[[one, two, three], [two, three, four], [three, four, five]]
//设置步长
println(numberswindowed(3, 2))
//[[one, two, three], [three, four, five]]
//partialWindows为true时,即使剩余的元素数量小于窗口长度,也会返回结果
println(numberswindowed(3, 2, true))
//[[one, two, three], [three, four, five], [five]]
//对得到的所有子集进行转换
println(numberswindowed(3, 2, true, { list -> listmap { ittoUpperCase() } }))
//[[ONE, TWO, THREE], [THREE, FOUR, FIVE], [FIVE]]
(6)zipWithNext()
val numbers = listOf("one", "two", "three", "four", "five")
//从头开始,返回所有的相邻元素对(Pair)
println(numberszipWithNext())
//[(one, two), (two, three), (three, four), (four, five)]
//s1,s2即相邻元素对
println(numberszipWithNext { s1, s2 -> s1length > s2length })
13、取单个元素
(1)elementAt()获取指定索引处的元素
val str = linkedSetOf("one", "two", "three", "four", "five")elementAt(3)
(2)elementAtOrNull()
val numbers = listOf("one", "two", "three", "four", "five")
//越界后返回null
println(numberselementAtOrNull(5))
//null
(3)elementAtOrElse()
val numbers = listOf("one", "two", "three", "four", "five")
//越界后返回lambda表达式的结果
println(numberselementAtOrElse(5) { index -> "The value for index $index is undefined" })
//The value for index 5 is undefined
(4)first()和last()
first()和last()也可以根据表达式查找。但是如果没有查找到目标元素,将会抛出异常。用 firstOrNull() 和 lastOrNull()替代,如果没有找到,会返回null。
可以使用find() 代替 firstOrNull();使用 findLast() 代替 lastOrNull()
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbersfirst { itlength > 3 })
//three
println(numberslast { itstartsWith("f") })
//five
(5) random()
随机返回一个元素。对于空集合会抛出异常。可以使用randomOrNull()替代,会返回null。
14、排序
(1)sortedWith(comparator: Comparator<in T>)
//compareBy()可根据给定的lambda表达式返回Comparator
println(listOf("aaa", "bb", "c")sortedWith(compareBy { itlength }))
//[c, bb, aaa]
(2) sorted() 和 sortedDescending()
val numbers = listOf("one", "two", "three", "four")
//自然升序
println(numberssorted())
//[four, one, three, two]
//自然降序
println(numberssortedDescending())
//[two, three, one, four]
(3) sortedBy(lambda表达式) 和 sortedByDescending(lambda表达式)
val numbers = listOf("one", "two", "three", "four")
val sortedNumbers = numberssortedBy { itlength }
println(sortedNumbers)
//[one, two, four, three]
val sortedByLast = numberssortedByDescending { itlast() }
println(sortedByLast)
//[four, two, one, three]
(4)reversed()和asReversed()
var numbers = mutableListOf("one", "two", "three", "four")
//返回原有集合的倒序副本,且和原有集合没有关联
println(numbersreversed())
//[four, three, two, one]
//返回原有集合的倒序视图,且和原有集合相关联。即改变原有的集合,已得到的倒序视图会发生改变。
val reversedNumbers = numbersasReversed()
println(reversedNumbers)
//[four, three, two, one]
numbersadd("five")
println(reversedNumbers)
//[five, four, three, two, one]
(5)shuffled()
返回一个以随机顺序排列的含有原有集合元素的新list
val numbers = listOf("one", "two", "three", "four")
println(numbersshuffled())
15、聚合
(1)聚合 *** 作如min()、max()、average()、sum()这些都只是对于数字类型的集合可用。count()计算集合中元素数量。
minBy{}、maxBy{}接收一个表达式;minWith{}、maxWith{}接收一个Comparator对象,可以由compareBy{}产生。
sumBy{}、sumByDouble{}接收一个表达式。前者对int类型的元素求和,并返回int。后者对Double类型的元素求和,并返回Double。
(2)fold()和reduce()。以及OrNull版本。
val numbers = listOf(5, 1, 3, 2)
//第一步的两个 *** 作数分别是集合中第一个和第二个元素。(则第一个元素无法乘以2)
println(numbersreduce { sum, element -> sum + element 2 })
//17
//为sum设置了初始值。每一次的 *** 作数都是sum和当前的集合元素。(可以保证每一个元素都乘以2)
println(numbersfold(0) { sum, element -> sum + element 2 })
//22
(3) reduceRight() 和 foldRight()从尾部开始进行计算。以及OrNull版本。
(4)foldIndexed()和reduceIndexed()将元素索引作为参数进行 *** 作。以及OrNull版本。
val numbers = listOf(5, 2, 10, 4)
println(numbersfoldIndexed(0) { idx, sum, element -> if (idx % 2 == 0) sum + element else sum })
//15
println(numbersreduceIndexed { idx, sum, element -> if (idx % 2 == 0) sum + element else sum })
//15
(5)reduceRightIndexed() 与 foldRightIndexed()从尾部开始进行计算。以及OrNull版本。
16、List *** 作
(1)getOrElse()、getOrNull()
val numbers = listOf(1, 2, 3, 4)
//越界时,返回null
println(numbersgetOrNull(5))
//越界时,返回表达式的结果,it等于index
println(numbersgetOrElse(6, { it }))
(2) indexOf() 返回元素第一个位置。 lastIndexOf() 返回元素最后一个位置。
(3)indexOfFirst() 和 indexOfLast() 可以接收一个表达式。
(4)二分查找 binarySearch()
要求该列表按照一定的顺序(自然排序或函数参数中提供的另一种排序)按升序排序过。
查询失败将返回 (-insertionPoint - 1),其中 insertionPoint 为应插入此元素的索引,以便列表保持排序。
如果存在多个目标元素返回其任一索引。
val numbers = mutableListOf("one", "two", "three", "four")
numberssort()
println(numbers)
//four, one, three, two]
println(numbersbinarySearch("two"))
// 3
println(numbersbinarySearch("z"))
// -5
println(numbersbinarySearch("two", 0, 2))
// -3
(5)通过Comparator使用二分查找
data class Product(val name: String, val price: Double)
val productList = listOf(
Product("WebStorm", 490),
Product("AppCode", 990),
Product("DotTrace", 1290),
Product("ReSharper", 1490))
println(productListbinarySearch(Product("AppCode", 990), compareBy<Product> { itprice }thenBy { itname }))
(6)fill()将集合中所有元素更新为指定值
val numbers = mutableListOf(1, 2, 3, 4)
numbersfill(3)
println(numbers)
//[3, 3, 3, 3]
17、set *** 作
(1)union()获取并集。对于有序集合, *** 作数顺序决定元素顺序。a union b
(2)intersect()获取交集。a intersect b
(3)subtract()获取差集。a subtract b
18、map *** 作
filter()、filterKeys()、filterValues()
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
println(numbersMapfilter { (key, value) -> keyendsWith("1") && value > 10 })
//{key11=11}
println(numbersMapfilterKeys { itendsWith("1") })
//{key1=1, key11=11}
println(numbersMapfilterValues { it < 10 })
//{key1=1, key2=2, key3=3}
这章理一下channel,先分享一句学习时候看到的话: Do not communicate by sharing memory; instead, share memory by communicating 。本来好像是用在 go 上的,但也有着异曲同工之妙啊
channel 顾名思义是管道,有入口与出口。因此最底层有 sendChannel&receiveChannel
Produce = Coroutine + Channel
produce 也是产生协程,跟普通的 launch 不同他会返回一个 receiveChannel ,后面会看到 receiveChannel 是一个迭代器,同时会 suspend 在 hasNext和next() 上,因此另一个协程就可以使用 forin 等待接受。
同时, produce 发射完成后是会自己关闭的,省的我们自己关闭信道:
通过 job 的 invokeOnCompletion 实现。
与 produce 相反返回 sendChannel
我们看这里用了 offer 而不是 send ,我们可以把 forin 先简单的写成以下形式:
假设队列里没有东西时, enqueue 一个 receiveHasNext 进行等待。过会解释一下 channel 的原理。现在只要知道,当有 sendersend 时,与 receive 关联的 cont 就会被调用 resume ,那么显而易见,当 action 正在处理时队列中没有 receiver ,而 offer 是不会 suspend 的,因此事件就被抛弃。
这里我们使用 CONFALTED ,即合并所有事件,因此接受者永远处理最近一个。原理如下:
当 offer 失败时需要 suspend 等待,(说明还没有接受者或者人家正忙着),插入 sendBuffered ,同时移除前面已有的 sendBuffered
这样永远是最近一个生效。
其实看 abstractChannel 会先看到一个 queue ,这时候显而易见会把它当做是像 linkedlist 那种塞数据的地方。但其实 queue 是用来放 receive/send node 。当队列为空时, send 时会先从队列取第一个 receiveNode ,取不到就 suspend ,把自己当成 sendNode 放入;不然就把数据直接交给 receiveNode 。
具体channel实现时,例如 ArrayChannel(buffer) ,会多加一个 buffer 队列,当队列为空时, send 时会先从队列取第一个 receiveNode ,取不到就放入 buffer 队列,如果 buffer 队列满了,把自己当成 sendNode 放入就 suspend ;同时把不然就把数据直接交给 receiveNode 。
参考
select 可以等任何一个回来,也可以等 await :
跟 linux 里的 select 其实类似,(能知道是哪个吗?):
能看到 onReceive 是实现 SelectCaluse1 ,同时在 selectBuilderImpl 环境下:
所以会往 queue 中 enqueue 两个 receive节点。 以
同时能看到如果任何一次 select 节点获取数据以后:
会调用 blockstartCoroutineUnintercepted :
之前讲过 startCoroutineUnintercepted 其实就是 functioninvoke() ,所以就调用 blockinvoke(select的completion是自己) ,获得值后通过 uContresume 即可。
这个和 defered 即 job(Support) 搞在一起:
可以看到当任务成功后, select 会被继续进行
首先解决一个问题,一个 sender 多个 receiver 是怎么处理的。
因为是1vs1消费。只有第一个会收到,因为它插在等待队列的第一个。用 broadcast 可以保证大家都收到。它维护一个 subscribe 的 user list ,所有消费者都能收到 channelsend 的 element
可以实现跟 RX 一样的 *** 作符,接受者收到后经过转换再进行发送返回最终新的 receiveChannel
channel 是 hot 的。
Provide abstraction for cold streams
这个todo,后续再说。
Even smarter async with coroutine actors
官方文档
在 map 中,键和值的类型都是用户定义的。 对基于键的访问启用了各种特定于 map 的处理函数,从键获取值到对键和值进行单独过滤。 在此页面上,我们提供了来自标准库的 map 处理功能的描述。
要从 Map 中检索值,必须提供其键作为 get() 函数的参数。 还支持简写 [key] 语法。 如果找不到给定的键,则返回 null 。 还有一个函数 getValue() ,它的行为略有不同:如果在 Map 中找不到键,则抛出异常。 此外,还有两个选项可以解决键缺失的问题:
要对 map 的所有键或所有值执行 *** 作,可以从属性 keys 和 values 中相应地检索它们。 keys 是 Map 中所有键的集合, values 是 Map 中所有值的集合。
可以使用 filter() 函数来 过滤 map 或其他集合。 对 map 使用 filter() 函数时, Pair 将作为参数的谓词传递给它。 它将使用谓词同时过滤其中的键和值。
还有两种用于过滤 map 的特定函数:按键或按值。 这两种方式,都有对应的函数: filterKeys() 和 filterValues() 。 两者都将返回一个新 Map ,其中包含与给定谓词相匹配的条目。 filterKeys() 的谓词仅检查元素键, filterValues() 的谓词仅检查值。
由于需要访问元素的键, plus ( + )与 minus ( - )运算符对 map 的作用与其他集合不同。 plus 返回包含两个 *** 作数元素的 Map :左侧的 Map 与右侧的 Pair 或另一个 Map 。 当右侧 *** 作数中有左侧 Map 中已存在的键时,该条目将使用右侧的值。
minus 将根据左侧 Map 条目创建一个新 Map ,右侧 *** 作数带有键的条目将被剔除。 因此,右侧 *** 作数可以是单个键或键的集合: list 、 set 等。
要将新的键值对添加到可变 Map ,请使用 put() 。 将新条目放入 LinkedHashMap (Map的默认实现)后,会添加该条目,以便在 Map 迭代时排在最后。 在 Map 类中,新元素的位置由其键顺序定义。
要一次添加多个条目,请使用 putAll() 。它的参数可以是 Map 或一组 Pair : Iterable 、 Sequence 或 Array 。
如果给定键已存在于 Map 中,则 put() 与 putAll() 都将覆盖值。 因此,可以使用它们来更新 Map 条目的值。
还可以使用快速 *** 作符将新条目添加到 Map 。 有两种方式:
使用 Map 中存在的键进行 *** 作时,将覆盖相应条目的值。
要从可变 Map 中删除条目,请使用 remove() 函数。 调用 remove() 时,可以传递键或整个键值对。 如果同时指定键和值,则仅当键值都匹配时,才会删除此的元素。
还可以通过键或值从可变 Map 中删除条目。 在 Map 的 keys 或 values 中调用 remove() 并提供键或值来删除条目。 在 values 中调用时, remove() 仅删除给定值匹配到的的第一个条目。
minusAssign ( -= ) *** 作符也可用于可变 Map 。
CSDN 编者按“如果我们把人类文明想象成汽车的话,那么软件开发行业就相当于汽车的引擎,编程语言就像引擎的燃料。”作为一名开发者,需跟随技术潮流的发展来学习新技术。2020年,你有计划新学一门编程语言吗?
本文作者从一名架构师的角度,详细分析了7种现代编程语言的优点与功能,你对哪门语言最感兴趣呢?
作者 | Md Kamaruzzaman,软件架构师
译者 | 弯月,责编 | 伍杏玲
封图| CSDN 下载于视觉中国
出品 | CSDN(ID:CSDNnews)
以下为译文:
如果我们把人类文明想象成汽车的话,那么软件开发行业就相当于汽车的引擎,而编程语言就像引擎的燃料。作为一名开发者,今年你应该学习哪种编程语言呢?
学习一种新的编程语言无疑是时间、精力和智力上的巨大投资, 但是学习一种新的编程语言可以提升你的软件开发技术力,促进你的职业发展。
在这里,我将献上一份现代编程语言的列表,这些语言不仅有助于提高你的生产力,而且还可以促进你的职业发展,并让你成长为更优秀的开发人员。这份列表还涵盖了非常广泛的领域:系统编程、应用程序开发、Web开发、科学计算等。
什么是现代编程语言?
“现代编程语言”这个说法本身就很含糊。许多人认为Python和JavaScript等语言是现代编程语言,还认为Java是一种古老的编程语言。实际上,这几种语言大约在同一时间出现:1995年。
大多数主流编程语言是上个世纪开发的:七十年代(如C)、八十年代(如C ++)、九十年代(如Java、Python、JavaScript)。这些语言在设计上并没有考虑现代软件开发生态系统:多核CPU、GPU、快速的互联网、移动设备、容器和云等。尽管许多语言中的许多功能都已进行一些改进,如并发等,而且在不断调整自己以适应时代,但它们依然保留了向后兼容性,无法抛弃那些过时的旧功能。
在这方面,Python就做得很好(某种意义上也未必是好事),Python 2和Python 3两者之间有明确的分界线。很多语言常常会为解决同一个问题提供十余种的方法,同时又没有顾及到开发人员的感受。根据StackOverflow的开发人员调查,大多数旧时的主流编程语言在“最可怕的语言”排名都名列前茅:
如果非要在新旧编程语言之间划个界限的话,那么应该是2007年6月29日,也就是第一台iPhone发行的时候。在这之后,编程语言界发生了很大变化。因此,在本文的列表中,我只考虑2007年以后的编程语言。
为什么要学习新语言?
首先,现代编程语言充分利用现代计算机硬件(多核CPU、GPU、TPU)、移动设备、大量数据、高速互联网、容器和云的优势。大多数现代编程语言会关注开发人员的体验,比如:
简洁明了的代码(减少样板代码)
内置的并发支持
空指针安全
类型推断
简洁的功能集
降低学习难度
融合所有编程范例的最佳功能
本文列表的许多编程语言都带有革命性地变化,并将永久地改变软件行业。一些已成为主流编程语言,还有一些则有望取得突破。因此选择这些语言作为第二种编程语言是明智的做法。
Rust
一直以来,系统编程语言环境主要由靠近硬件的语言(如C、C ++等)主导。尽管它们可以完全控制程序和硬件,但是它们缺乏内存安全性。即使它们支持并发,使用C/C ++编写并发程序也很困难,因为没有并发安全性。还有一些流行的编程语言是解释性语言,例如Java、Python、Haskell。这些语言具备安全性,但需要庞大的运行时或虚拟机。由于它们的运行时间长,因此Java等语言不适合于系统编程。
许多人曾尝试将C/C ++的功能与Java、Haskell的安全性相结合。然而,Rust才是第一个成功实现了这一点的编程语言。
Graydon Hoare在业余项目中开发出了Rust,他的灵感来自研究编程语言Cyclone。Rust是开源的,由Mozilla与许多其他公司和社区一起领导这门语言的开发。Rust于2015年首次发布,并很快引起了社区的关注。
主要特征:
通过所有权和借用概念提供内存安全和并发安全。
内存安全和并发安全在编译时确保,即如果程序代码可以编译,那么内存既安全又没有数据竞争。这是Rust最吸引人的功能。
它还提供了Haskell中元编程的表现力。凭借不可变的数据结构和功能编程功能,Rust提供了功能并发和数据并发。
Rust的速度非常快,纯Rust的性能甚至优于纯C。
在没有运行时的情况下,Rust可以完全控制现代硬件(TPU、GPU、多核CPU)。
Rust具有LLVM支持。因此,Rust提供一流的与WebAssembly的互 *** 作性,而且Web代码也非常快。
流行度:
自2015年首次亮相以来,Rust已被开发人员广泛接受,并在StackOverflow开发人员调查中连续四年(2016、2017、2018、2019)被评选为最受欢迎的语言:
根据GitHub Octoverse的调查,Rust是运行速度第二快的语言,仅次于Dart:
此外,根据编程语言流行度排名网站PyPl的数据,Rust排名第18位,并呈上升趋势:
对比Rust提供的功能集,我们就会明白为什么微软、亚马逊、Google等科技巨头相继宣布投资Rust作为一种长期的系统编程语言。
根据Google统计的趋势,在过去的5年中,Rust的热度每年都在增加。
主要用途:
系统编程
Serverless 计算
商业应用
主要竞争对手:
C
C++
Go
Swift
Go
在本世纪初,Google面临两个扩展问题:开发扩展和应用程序扩展。开发扩展问题指的是他们不能仅通过投入开发人员的方式来添加更多功能。应用程序扩展问题则指他们无法开发出一款能够扩展到Google级别的计算机集群的应用程序。
所以在2007年左右,Google创建了一种新的编程语言,用于解决这两个扩展问题。两位才华横溢的Google软件工程师Rob Pike(UTF-8)和Ken Thompson(UNIX OS)创建了一种新语言。
2012年,Google正式发布了第一版的Go编程语言。Go是一种系统编程语言,但与Rust不同,它还具有Runtime和垃圾收集器(几兆字节)。但是与Java或Python不同,这个Runtime包含了生成的代码。最后,Go生成了一个本地的二进制代码,可以在没有附加依赖项或运行时的情况下在计算机中运行。
主要特征:
Go具有一流的并发支持。Go不通过线程和锁提供“共享内存”并发性,因为编程难度太大。相反,它提供了基于CSP的消息传递并发性(基于Tony Hoare的论文)。Go使用“ Goroutine”(轻量级绿色线程)和“ Channel”进行消息传递。
Go最大的杀手级功能是:简单,它是最简单的系统编程语言。新手软件开发人员只需几天就可以编写高效的代码,就像Python一样。有些大规模的云原生项目(如Kubernetes、Docker)都是用Go编写的。
Go还内置了垃圾收集器,这意味着开发人员无需担心C/C++中的内存管理问题。
Google投入了大量资金打造Go。因此Go拥有大量的工具支持。新手Go开发人员拥有大量的工具生态系统。
一般,开发人员80%的时间都花在了维护现有代码上,用于编写新代码的时间只占20%。由于其简单性,Go在语言维护方面表现出色。如今,Go在业务应用程序中大量使用。
流行度:
Go一问世就受到了软件开发社区热烈的欢迎。2009年-2018年,Go一直在TIOBE编程语言排行榜上徘徊。Go的成功为Rust等新一代编程语言铺平了道路。
如今,Go已是主流编程语言。最近,Go团队宣布了有关“Go 2”的消息,这门编程语言的发展会更加稳固。
几乎在所有的流行编程语言排行榜中,Go的排名都很高,已超过许多现有的语言。自2019年12月以来,在TIOBE指数排名中,Go名列第15位:
根据StackOverFlow的调查,十大最受喜爱的编程语言中,Go也位列其中:
此外,根据GitHub的数据,Go也是十大发展最迅速的语言之一:
Google趋势显示,在过去的5年中,Go的热度每年都在增加。
主要用途:
系统编程
Serverless 计算
商业应用
云原生开发
主要竞争对手:
C
C++
Rust
Python
Java
Kotlin
Java 是企业软件开发领域无可争议的王者。近年来,Java受到了一些负面评论:过于冗长,大量样板代码,容易出现意外的复杂性。但是,关于Java虚拟机(JVM)的争论却很少。JVM是软件工程的杰作,经过了时间的考验,提供了硬核的runtime。
多年来,Scala等JVM语言一直在努力克服Java的缺点,想成为更好的Java,但他们都失败了。最终,这场提升Java的探索以Kotlin的诞生结束。Jet Brains(流行的IDE IntelliJ背后的公司)开发了Kotlin,它可以在JVM上运行,克服了Java的很多缺点,提供许多现代功能。
与Scala不同的是,Kotlin比Java更简单,还可在JVM中提供与Go或Python开发人员同等的生产力。
Google宣布Kotlin是一流的Android应用开发语言,因此Kotlin在社区中的接受度得到了大幅提高。自2017年以来,同样受欢迎的Java Enterprise框架Spring也开始支持Kotlin。我曾尝试结合Kotlin与Reactive Spring使用,体验非常棒。
主要特征:
Kotlin的主要卖点在于其语言设计。我总是将Kotlin视为JVM上的Go/Python,因为它简洁明了的代码。因此,Kotlin的生产力很高。
与许多其他现代语言一样,Kotlin提供了Null指针、安全性、类型推断等功能。
由于Kotlin也运行在JVM中,因此现有Java库庞大的生态系统都可供使用。
Kotlin是一流的Android应用开发语言,并且已经超过Java,成为开发Android应用的首选。
Kotlin得到了JetBrains和Open Source的支持,因此具有出色的工具支持。
Kotlin有两个有趣的项目:Kotlin Native(将Kotlin编译为原生代码)和kotlinjs(Kotlin到JavaScript)。如果成功,则可以在JVM外部使用Kotlin。
Kotlin还提供了一种简单的方式来编写DSL(域特定语言)。
流行度:
自2015年首次发布以来,Kotlin的知名度不断飙升。根据Stack Overflow,Kotlin是2019年第四大最受欢迎的编程语言:
Kotlin还是增长最快的编程语言之一,排名第四:
在流行编程语言排名网站PyPl的排名中,Kotlin名列第十二名,并具有较高的上升趋势:
自从Google宣布Kotlin是一流的Android应用开发语言以来,Kotlin的流行趋势出现了大幅上涨,如下所示:
主要用途:
企业应用程序
主要竞争对手:
TypeScript
JavaScript是一门优秀的编程语言,在2015年之前,JavaScript有很多缺点。著名的软件工程师Douglas Crockford写了一本书名为《JavaScript: The Good Parts》,暗示了JavaScript有很糟的部分。无模块化,还有“回调地狱”,因此开发人员都不喜欢维护特别大的JavaScript项目。
Google甚至还开发了一个平台,可将Java代码反编译为JavaScript代码(GWT)。许多公司和个人都曾尝试开发更好的JavaScript,例如CoffeeScript、Flow、ClojureScript。最终,微软的TypeScript取得了成功。
微软的一队工程师在著名的Anders Hejlsberg的带领下,创建了JavaScript的静态类型、模块化超集——TypeScript。
TypeScript可以编译为JavaScript。于2014年首次发布后,TypeScript很快引起了社区的关注。Google当时还计划开发JavaScript的静态类型超集。Google对TypeScript青睐有加,以至于他们没有开发新的语言,而是选择与微软合作改进TypeScript。
Google选择TypeScript作为其SPA框架Angular 2+的主要编程语言。此外,流行的SPA框架React也提供对TypeScript的支持。另一个流行的JavaScript框架Vuejs也宣布将使用TypeScript开发新的Vuejs 3:
另外,nodejs的创建者Ryan Dahl已决定使用TypeScript来开发安全的Nodejs替代品Deno。
主要特征:
流行度:
开发人员喜欢TypeScript的优雅语言设计。在StackOverFlow最受欢迎的语言类别的调查中,TypeScript与Python并列第二名:
根据GitHub的排名,TypeScript是增长最快的编程语言之一,排名第五:
从GitHub的贡献度来看,TypeScript排名第七,打进了前十:
Google的趋势表明,在过去的几年中,TypeScript的热度越来越高:
主要用途:
主要竞争对手:
Swift
当初乔布斯拒绝在iOS中支持Java(和JVM),他认为Java不再是主流编程语言。如今我们发现乔布斯当初的估计是错的,虽然iOS仍然不支持Java。苹果选择了Objective-C作为iOS中的首选编程语言。Objective-C是一门很难掌握的语言,它不支持现代编程语言所要求的高生产力。
后来,苹果的Chris Lattner和其他人开发了一种多范例、通用的、编译编程语言——Swift,来替代Objective-C。Swift的第一个稳定版本于2014年发布。Swift还支持LLVM编译器工具链(也由Chris Lattner开发)。Swift与Objective-C代码库具有出色的互 *** 作性,并且已确立为iOS应用开发中的主要编程语言。
主要特征:
流行度:
开发人员对Swift的喜爱不亚于许多其他现代编程语言。根据StackOverflow的调查,Swift在最受欢迎的编程语言中排名第六:
2019年,在TIOBE的编程语言排名中,Swift的排名上升到了第10名。鉴于这种编程语言只有5年的历史,可以说是成绩斐然:
Google的趋势表明,在过去的几年中,Swift的热度出现了激增:
主要用途:
主要竞争对手:
Dart
Dart是Google出品的第二大编程语言。Google是Web和Android领域的巨头,因此Google在Web和应用领域开发自己的编程语言也不足为奇。在丹麦软件工程师Lars Bak(领导Chrome的 JavaScript V8引擎开发)的带领下,Google于2013年发布了Dart。
Dart是一种通用编程语言,支持“强类型”和“面向对象”编程。Dart也可以转编译为JavaScript,凡是JavaScript可以运行的任何地方(例如Web、移动、服务器)几乎都可以运行 Dart。
主要特征:
流行度:
根据GitHub Octoverse数据显示,Dart是2019年增长最快的编程语言,去年它的流行度增长了五倍:
根据TIOBE指数显示,Dart排名第23,仅用了4年时间就超过了很多其他的现代编程语言:
根据StackOverflow的调查,Dart在最受欢迎的编程语言中排名第12:
受Flutter的影响,Google的趋势表明,在过去的两年中,Dart的热度急剧上升:
主要用途:
主要竞争对手:
Julia
本文提及的大多数编程语言都是由大型公司开发的,但Julia是个例外。科技计算领域通常都会使用动态语言,例如Python、Matlab。虽然这些语言提供易于使用的语法,但不适用于大规模的科技计算。他们需要使用C/C ++库执行CPU密集型任务,因此这就产生了著名的“两种语言”的问题,因为他们需要粘合代码来绑定两种语言。由于编写的代码需要在两种语言之间来回切换,因此总是会损失部分性能。
为了解决这个问题,麻省理工学院的一队研究人员计划从头开始创建一种新的语言,这种语言既可以利用现代硬件的优势,而且还结合其他语言的优势。于是,Julia诞生了。
Julia是一种动态的高级编程语言,提供一流的并发、并行和分布式计算支持。Julia的第一个稳定版本于2018年发布,并很快受到社区和行业的关注。Julia可用于科学计算、人工智能和许多其他领域,而且还可以解决“两种语言”的问题。
主要特征:
流行度:
Julia在许多领域主要与Python竞争。由于Python是最流行的编程语言之一,因此Julia想晋升主流还需要几年的时间。
虽然Julia非常新(只有一岁),但仍在TIOBE指数中排到第43名:
Google趋势显示,在过去的一年中,Julia的热度在稳步增长:
但是考虑到Julia的功能集,以及NSF、DARPA、NASA、因特尔等公司的推动,相信Julia取得突破的进展只是时间的问题。
主要用途:
主要竞争对手:
原文链接:>
本文为 CSDN 翻译,转载请注明来源出处。
End
Python
Matlab
科学计算
高性能计算
数据科学
可视化
与Rust一样,Julia的主要特征在于语言的设计。这种语言在不牺牲性能的情况下,将高性能和科学计算中现有编程语言的一些功能结合在一起。就目前的情况来看,Julia出色地完成了这项任务。
Julia是一种动态编程语言,支持类型系统但类型不是必须的。因此,Julia这种编程语言很容易学习,生产力很高。
Julia的核心是多调度编程范例。
Julia内部支持并发、并行和分布式计算。
Julia为I/O密集型任务提供异步I/O。
Julia的运行速度非常快,可用于需要数百万个线程的科学计算。
JavaScript
TypeScript
应用开发
UI开发
与Go一样,Dart也非常注重开发人员的工作效率。由于Dart简洁的语法,以及高效的生产力,受到开发人员的喜爱。
Dart还提供“强类型”和“面向对象”编程。
Dart是少数同时支持JIT编译(运行时编译)和AOT编译(创建时编译)的编程语言之一。因此,Dart可以针对JavaScript运行时(V8引擎),并且Dart可以编译为快速的原生代码(AOT编译)。
跨平台原生应用程序开发平台Flutter选择了Dart作为开发iOS和Android应用的编程语言。从那以后,Dart的流行度越来越高。
与Goog的Go编程语言一样,Dart也具有出色的工具支持和庞大的Flutter生态系统。Flutter的日益普及也会推动Dart的采用率升高。
Objective-C
Rust
Go
iOS应用开发
系统编程
客户端开发(通过WebAssembly)
Swift的杀手级功能之一是其语言设计。语言本身很简单,语法简洁,比Objective-C更高效。
Swift还提供了现代程序语言的功能:null安全。此外,它还提供了语法糖来避免“厄运金字塔”。
作为一种编译语言,Swift和C++一样快。
Swift支持LLVM编译器工具链。因此,我们可以在服务器端编程,甚至浏览器编程(使用WebAssembly)中使用Swift。
Swift提供了自动引用计数(ARC)支持,可抑制内存管理的不善。
JavaScript
Dart
Web UI开发
服务器端开发
与Go或Kotlin同样,TypeScript的主要特征也是语言设计。TypeScript凭借其简洁明快的代码,成为了目前最优雅的编程语言之一。就开发人员的生产力而言,它与JVM或Go/Python上的Kotlin并驾齐驱。TypeScript是生产力最高的JavaScript超集。
TypeScript是JavaScript的强类型超集,特别适合大型项目,而且可以称为“可扩展的JavaScript”。
单页应用程序框架的“三巨头”(Angular、React、Vuejs)为TypeScript提供了出色的支持。在Angular中,TypeScript是首选的编程语言。在React和Vuejs中,TypeScript越来越受欢迎。
最大的两家技术巨头:微软和Google正在合作开发由活跃的开源社区支持的TypeScript。因此,TypeScript拥有最好的工具支持。
由于TypeScript是JavaScript的超集,因此凡是可以运行JavaScript的任何地方都可以运行TypeScript,包括浏览器、服务器、移动设备、物联网设备和云。
Java
Scala
Python
Go
一般情况下,java编程开发程序员都掌握了许多的编程开发工具和框架来辅助项目工作。今天我们就一起来了解一下,对于java程序员来说有哪些好用的编程框架语言。
Kotlin是JVM上比较新的语言之一,来自IntelliJ开发商JetBrains。它是一种静态类型语言,旨在提供一种混合OO和FP的编程风格。Kotlin编译器生成的字节码与JVM兼容,可以在JVM上运行及与现有的库互 *** 作。2017年,谷歌支持将其用于Android开发,Kotlin获得了重大突破。
JetBrains有一个明确的目标:让Kotlin成为一种多平台语言,并提供Java互 *** 作性。Kotlin近的成功和成熟水平为它进入服务器端提供了一个很好的机会。
选择Kotlin的理由
许多语言都试图成为更好的Java。Kotlin在语言和生态系统方面做得都很好。成为更好的Java,同时又要保护JVM和巨大的库空间,这是一场姗姗来迟的进化。这种方法与来自JetBrains和谷歌的支持相结合,使它成为一个真正的竞争者。让我们来看看Kotlin带来的一些特性。
类型推断——类型推断是一等特性。Kotlin推断变量的类型,而不需要显式指定。在需要明确类型的情况下,也可以指定类型。
通过引入var关键字,Java10也在朝着类似的方向发展。虽然表面看起来类似,但它的范围仅限于局部变量,不能用于字段和方法签名。
严格空检查——Kotlin将可空代码流视为编译时错误。它提供了额外的语法来处理空检查。值得注意的是,它提供了链式调用中的NPE保护。
与Java互 *** 作——Kotlin在这方面明显优于其他JVM语言。它可以与Java无缝地交互。可以在Kotlin中导入框架中的Java类并使用,反之亦然。值得注意的是,Kotlin集合可以与Java集合互 *** 作。
不变性——Kotlin鼓励使用不可变的数据结构。常用的数据结构(Set/List/Map)是不可变的,除非显式地声明为可变的。变量也被指定为不可变(val)和可变(var)。昌平北大青鸟发现所有这些变化对状态可管理性的影响是显而易见的。
简洁而富有表达力的语法——Kotlin引入了许多改进,这些改进对代码的可读性产生了重大影响。
以上就是关于kotlin集合高效使用全部的内容,包括:kotlin集合高效使用、Kotlin协程源码分析(二)之Channel、Kotlin 中 Map 使用等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)