问题
给定一个函数 rand5()
,它可以随机、等概率地生成 0 到 4 之间的整数。现在希望使用该函数和确定性的计算过程,实现函数 rand7()
,它可以随机、等概率地生成 0 到 6 之间的整数。
今天天气很好,天很晴朗,能见度也很高。坐在窗前,看着太阳一点点沉下去,色彩变得温暖橙黄。于是想到下去骑车拍落日,顺便完成今天的运动量。
向着日落的方向骑行,没过多久便日落西山,只留下一片余晖。
感叹落日的美景与白日的结束之余,一个问题浮现在脑海:我需要至少以多快的速度追赶落日,才能追上它?
如果你使用 Java 开发,你应该听说过 Java 8 引进的 Lambda 表达式,以及用于处理容器类的 Streams API;
如果你用过 JavaScript,你应该也知道高阶函数(如 map
/reduce
, filter
, sort
),以及闭包、箭头函数、generator 之类的概念;
如果你上手过 Kotlin,你可能会被里面漫天飞舞的 let
, apply
, also
, with
函数,以及一层层的花括号包裹的 Lambda 表达式感到印象深刻。
这些新鲜玩意初看起来似乎没有那么直观,甚至很别扭:这些代码块什么时候执行、如何被执行,很难一眼看出来!
尝试用一下后,你或许会想“搞这么花里胡哨的,这不就是省得给接口取名字的语法糖嘛”,然后继续写你的匿名内部类;
又或者,你会对这种简洁又新奇的写法感到欲罢不能,恨不得将整个项目都改写为花括号嵌套花括号,最后连自己都看不明白写了个啥。
但这些“新鲜玩意”其实并不新鲜,其历史甚至可以追溯到图灵第一次提出通用图灵机的概念之前!
这篇文章将试图以程序员的视角介绍函数式编程的概念,以及你为什么应该学习使用它的几个理由。
作为 Android 开发工作了三年多,见过许许多多的屎山代码与令人血压上升的操作,在这里总结一些个人开发经验,希望有所帮助。
最近写 LeetCode 踩了个坑,记录一下。
对于 PriorityQueue 和 ArrayList:
1 | PriorityQueue<Integer> queue; |
下面两个操作是等价的:
1 | // #1 |
然而下面代码中,前两个操作与第三个操作是不等价的:
1 | // #1 |
原因是 PriorityQueue.poll
操作会改变原有队列:弹出堆顶元素,再调整堆使其保持最小堆性质,这一改变对于维护其出列的有序性是必要的。另一方面,如果没有出列再调整这一过程,优先队列并不能保证遍历的有序性:只是简单的前序遍历。
换句话说就是 queue.poll
方法取出元素的顺序是有序的,而 addAll
方法与使用 for-each 循环遍历优先队列不改变原有优先队列,也就不能保证遍历顺序是有序的。这两个顺序不一样!
关于之前源码分析做的 PPT,总结了一些重点内容,包含了详细备注,有兴趣的可以下载下来。
Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
服务分三种类型:
bindService
绑定到服务。绑定服务提供客户端-服务器接口,以便组件与服务进行交互。绑定服务仅当应用组件绑定时才会启动,当全部绑定被取消时,服务会被销毁。服务可以既是启动服务(通过 startService
启动)又是绑定服务(通过 bindService
启动),取决于是否实现 onStartCommand()
和 onBind()
回调方法。