写给Android开发者的Kotlin入门

Google在今年的IO大会上宣布,将Android开发的官方语言更换为Kotlin,作为跟着Google玩儿Android的人,我们必须尽快了解和使用Kotlin语言。

不过Kotlin毕竟是语言级别的新事物,比起Java来说,从编程思想到代码细节都有不少变化,我们最好先对Kotlin有个整体的基本的了解,然后再去学习和使用,这样才能高效地掌握Kotlin语言。

Java的辉煌与阴影

1995年,当年如日中天的Sun公司发布了Java语言,引起了巨大的轰动,与当时主流的C语言和Basic语言比起来,Java语言简单、面向对象、稳定、与平台无关、解释型、多线程、动态等特点,就像是打开了一个新的世界,一时间风靡全球,云集者众,微软为了模仿Java搞出C#语言,Netscape为了赶时髦硬塞出一个JavaScript语言,IBM则捏着鼻子做了Java IDE Eclipse(日蚀,呵呵)。直到现在,Java在编程世界里还占据着举足轻重的地位,Andy Rubin在开发Android系统时,也很自然地采用了Java和C++(C++负责NDK开发)作为开发语言。

但是,Java毕竟是20多年前的语言了,虽然有不断扩展更新,但是底层设计思想是很难改动的,这就导致它很难实现一些新的语言特性,例如函数式编程、Lambda 表达式、流式API、高阶函数、空指针安全等(虽然Java8实现了部分特性,但是Android还不怎么支持Java8),这些新的语言特性大受好评,可以说解放了编程的生产力,这其实也说明了一个事实:开发效率/时间是软件公司真正的瓶颈,任何能压缩代码量,提高开发效率的举措,都应该受到重视。

而且,Android还存在Java版权危机的问题,收购了Sun公司的Oracle曾向Google索要巨额的Java版权费,这可能也加快了Google寻找Android开发替代语言的动作。

苹果公司已经在用Swift语言替代Object-C语言,Google也找到了替代Java的语言,也就是JetBrains公司(Android Studio也是用该公司的Intelli J改的)主推的Kotlin。

其实,Swift和Kotlin还挺相似的,有一篇Swift is like Kotlin对这两种语言做过简单的对比。

Kotlin的出现

Kotlin也是基于JVM设计的编程语言,算是对Java的温和改良,她是一个开源项目的成果,拥有很高的声望,很多公司、组织、业界大犇都很喜欢她,Square公司的Jake大神(Dagger、ButterKnife、Retrofit、OkHttp...之父)就专门写了篇UsingProject Kotlin for Android为Kotlin站台。

相对Java来说,Kotlin在编写代码时有如下优势:代码简洁高效、函数式编程、空指针安全、支持lambda表达式、流式API等。

执行效率上,Kotlin和Java具有同样的理论速度(都是编译成JVM字节码)。

另外,新语言必须考虑兼容性,为了与存量项目代码和谐共处,Kotlin和Java是互相完美兼容的,两种代码文件可以并存代码可以互相调用文件可以互相转换,库文件也可以无障碍地互相调用,据说使用Kotlin基本不会带来额外的成本负担。

编程语言本质上还是工具,要运用工具提高效率和质量,还要看具体开发者,我们先看看Kotlin相对Java有哪些特色。

Kotlin的特色

Kotlin作为Java的改良,在Android开发中有很多优势,我们先从相对直观的界面绘制开始了解,然后看看Kotlin的语法特点,再慢慢去接触更深层次的编程思想。

简化findViewById

我们知道,Android的架构里,xml布局文件和Activity是松耦合的,Activity中要使用界面元素,必须借助R文件对xml控件的记录,用findViewById找到这个元素。

Kotlin中我们可继续使用findViewById去绑定xml布局中的控件:(TextView)findViewById(R.id.hello);

进一步引用Anko之后,可以使用find函数去绑定控件:find(R.id.hello),不需要类型转换

同时,Kotlin还提供一种更激进的方法,通过在gradule中引用applyplugin:'kotlin-android-extensions',彻底取消findViewById这个函数,具体做法如下:

首先,在app的gradule中,添加引用


添加引用

然后,在Activity中直接根据id使用界面元素


直接操作界面元素

按住Ctrl键,会提示我们这个控件详情


提示详情

点击后,可以直接跳转到xml文件中的控件位置,光标会停留在Id处


直接跳转到控件Id处

这种特性令人联想起C#语言中对界面控件的管理,在C#里,界面的控件可以直接调用,不需要find,这是因为在创建一个Form1.cs界面文件时,IDE会自动创建一个对应的额Form1.designer.cs类,在这个类里,自动管理所有界面控件的对象。

Kotlin也是类似的思路,它会遍历你的xml文件,创建对应的虚拟包给你引用(用Alt+Enter引用),我们使用的控件对象,其实是这个虚拟包里的控件对象。


引用虚拟界面类

为什么说这个包是虚拟的,因为它是kotlin临时创建的,你无法打开它的文件,在编译apk时,Kotlin会自动帮你补充findViewbyId的代码,最终得到的产品其实没变,它只是方便了程序员的书写。

Anko

Anko其实是一种DSL(领域相关语言),是专门用代码方式来写界面和布局的。

上一节针对findViewById,最激进的方式是取消这个函数,这一节更加激进,我们可以连XML布局文件也取消掉。

在XML中定义界面布局当然是有好处的,分层清晰,代码易读,现在AS中预览效果也不错。但是它渲染过程复杂,难以重用(虽然有including),而如果我们用Java代码去替换xml,代码会更加复杂和晦涩。

Anko却实现了在代码中简洁优雅地定义界面和布局,而且由于不需要读取和解析XML布局文件,Anko的性能表现更佳

我们可以看看Anko在Github上的代码示例,用6行代码就做出了一个有输入框、按钮、点击事件和Toast的界面和功能


示例的界面和功能

我们自己写一下这6行代码,首先需要在gradle中添加引用,主要是sdk和v4/v7包


Gradle中引用Anko

然后参照Anko在Github中的示例,实现这6行代码。


参考Github的Anko实例代码

Activity本来会在加载时在onCreate函数里用setContentView函数来寻找布局文件,并加载为自己的界面,在这里,Anko代码替代了setContentView,直接告诉Activity应该如何绘制界面。

(在Fragment里不可以这样直接写verticalLayout,因为加载机制不一样,Fragment需要在onCreateView函数里inflate并返回一个View对象,所以对应的Anko代码也需要写在onCreateView函数里并返回一个View,可以用return with(context){verticalLayout[...]}或者return UI{verticalLayout[...]}.view)

可以看到,代码非常简洁干练,不像以往的Android代码那样拖沓,这既与Kotlin的语法有关,也与Anko能用代码实现界面和布局有关。

这段代码虽然简洁,可是却失去了MVC分层的好处,因为V直接写在业务代码里了,这个问题好解决,我们可以把Anko布局代码放到一个专门的类文件里


抽出Anko布局代码

然后在Activity引用这个布局类来绘制界面


引用Anko布局类

虽然Anko效率很高,代码简洁,清爽直观,但是目前还有很多坑,主要包括:

1.AS并不支持直接预览Anko界面,虽然有个Anko DSL Preview插件,但是需要make才能刷新,而且和现在的AS不兼容。

2.如果要在多版本中动态替换外部资源,需要用动态类加载才能实现,无法借用资源apk实现。

3.不方便根据view的id去即时引用view控件(R文件和inflate这时反而更加灵活)。

另外,Anko还在异步、日志、Toast、对话框、数据库等方面提供优化服务,是否采用就看自身需要了。

Kotlin语法特点

看了上面这些例子,我们发现Kotlin本身的语法和Java有些不一样,新语言嘛,相对Java而言,主要的变化有这么几条:

1.没有“;”

在Kotlin语法里,代码行不需要用“;”结尾,什么都不写就好

2.重要的“:”

在Java里,“:”主要在运算符里出现(for/switch/三元运算符等)。

在Kotlin里,“:”的地位大大提升了,它的用途非常广泛,包括:

定义变量类型

var name:String="my name" //变量name为String类型

定义参数的类型

fun makeTool(id:Int){ //参数id为Int类型

}

定义函数的返回值

fun getAddr(id:Int):String{ //返回值为String类型

}

声明类/接口的继承

class KotlinActivityUI :AnkoComponent<KotlinActivity>{//继承AnkoComponent接口

使用Java类

val intent = Intent(this, MainActivity::class.java) //需要用::来使用Java类,注意是两个“”

3.没有“new”

Kotlin实例化一个对象时不需要new关键字

var list=ArrayList()

4.变量、常量、类型推断

用var定义变量(像js)

var name:String="my name"

用val定义常量(相当于final)

val TAG:String="ClassName"

上面两个例子用:String来定义了数据类型,这个是可以省略的,Kotlin支持类型推断,这两句话你可以写成

var name="my name"

val TAG="ClassName"

5.初始化和延迟加载

在Java里,我们可以定义一个变量,但是并不赋值(int和boolean会有默认值)

但是Kotlin里必须为变量赋值,如果只写一个变量,却不赋值,像下面这样:

var name

编译器会报错,提示你未初始化,你必须赋值为0或者null,或者别的什么值。

不过,我们有时候就是不能在定义变量时就初始化它,比如在Android中我们经常预定义一个View控件而不初始化,但是直到onCreate或onCreateView时才初始化它。

针对这种情况,Kotlin提供了懒加载lazy机制来解决这个问题,在懒加载机制里,变量只有在第一次被调用时,才会初始化,代码需要这样写


在初次调用时初始化变量的lazy机制

lazy只适用于val对象,对于var对象,需要使用lateinit,原理是类似的,只是代码需要这样写


var变量使用lateinit机制

6.空指针安全

在Kotlin里,可以用“?”表示可以为空,也可以用“!!”表示不可以为空。

空指针安全并不是不需要处理空指针,你需要用“?”声明某个变量是允许空指针的,例如:

var num:Int?=null

声明允许为空时,不能使用类型推断,必须声明其数据类型

空指针虽然安全了,但对空指针的处理还是要视情况而定,有时候不处理,有时候做数据检查,有时候还需要抛出异常,这三种情况可以这样写:

val v1 =num?.toInt() //不做处理返回 null

val v2 =num?.toInt() ?:0 //判断为空时返回0

val v3 =num!!.toInt() //抛出空指针异常(用“!!”表示不能为空)

更多空指针异常处理,有一篇NullPointException 利器 Kotlin 可选型介绍的比较全面,值得借鉴

7.定义函数

在Kotlin语法里,定义函数的格式是这样的

fun 方法名(参数名:类型,参数名:类型...) :返回类型{

}

所以,一般来说,函数是这样写的

fun getAddress(id:Int,name:String):String{

    return"got it"

}

由于Kotlin可以对函数的返回值进行类型推断,所以经常用“=”代替返回类型和“return”关键字,上面这段代码也可以写成

fun getAddress(id:Int,name:String)={ //用“=”代替return,返回String类型则交给类型推断

     "got it" //return被“=”代替了

}

如果函数内代码只有一行,我们甚至可以去掉{}

fun getAddress(id:Int,name:String)="got it" //去掉了{}

}

函数也允许空指针安全,在返回类型后面增加“?”即可

fun getAddress(id:Int,name:String) :String?="got it"

有时候,函数的返回类型是个Unit,这其实就是Java中的void,表示没有返回

fun addAddress(id:Int,name:String):Unit{ //相当于java的void

}

不过,在函数无返回时,一般不写Unit

fun addAddress(id:Int,name:String){ //相当于java的void

}

8.用is取代了instance of

代码很简单

if(obj is String)...

9.in、区间和集合

Kotlin里有区间的概念,例如1..5表示的就是1-5的整数区间

可以用in判断数字是否在某个区间

if(x in 1..5){ ...//检查x数值是否在1到5区间

可以用in判断集合中是否存在某个元素

if(name in list){...//检查list中是否有某个元素(比Java简洁多了)

可以用in遍历整个集合

for(i in 1..5){ ...//遍历1到5

for(item in list){...//遍历list中的每个元素(相当于Java的for(String item : list))

另外,in在遍历集合时功能相当强大:

在遍历集合时,可以从第N项开始遍历

for(i in 3..list.size-2){...相当于for (int i = 3; i <= list.size()-2; i++)

可以倒序遍历

for(i in list.size downTo 0) {...相当于for (int i = list.size(); i >= 0; i--)

可以反转列表

for(i in (1..5).reversed())

可以指定步长

for(i in 1.0..2.0 step 0.3) //步长0.3

Kotlin里的集合还都自带foreach函数

list.forEach {...

10.用when取代了switch

switch在Java里一直不怎么给力,在稍老一些的版本里,甚至不支持String

Kotlin干脆用强大的when取代了switch,具体用法如下


when的用法

代码中的参数类型Any,相当于Java中的Obejct,是Kotlin中所有类的基类,至于object关键字,在Kotlin中另有用处...

11.字符串模板

在Java里使用字符串模板没有难度,但是可读性较差,代码一般是

MessageFormat.format("{0}xivehribuher{1}xhvihuehewogweg",para0,para2);

在字符串较长时,你就很难读出字符串想表达什么

在kotlin里,字符串模板可读性更好

"${para0}xivehribuher${para1}xhvihuehewogweg"

12.数据类

数据类是Kotlin相对Java的一项重大改进,我们在Java里定义一个数据Model时,要做的事情有很多,例如需要定义getter/setter(虽然有插件代写),需要自己写equals(),hashCode(),copy()等函数(部分需要手写)

但是在Kotlin里,你只需要用data修饰class的一行代码

data class Client(var id:Long,var name:String,var birth:Int,var addr:String)

Kotlin会自动帮你实现前面说的那些特性。

数据模型里经常需要一些静态属性或方法,Kotlin可以在数据类里添加一个companion object(伴随对象),让这个类的所有对象共享这个伴随对象(object在Kotlin中用来表示单例,Kotlin用Any来表示所有类的基类)


添加companion obejct

13.单例模式

单例是很常见的一种设计模式,Kotlin干脆从语言级别提供单例,关键字为object,如果你在扩展了Kotlin的IDE里输入singleton,IDE也会自动帮你生成一个伴随对象,也就是一个单例


单例类

如果一个类需要被定义为class,又想做成单例,就需要用上一节中提到的companion object

例如,如果我们用IDE新建一个blankFragment,IDE会自动帮我们写出下面的代码,这本来是为了解决Fragment初始化时传值的问题,我们注意到她已经使用了companion object单例


自动生成的代码

如果我们修改一下newInstance这个函数


改成单例

那么,我们用

BlankFragment.newInstance()

就可以调用这个fragment的单例了

14.为已存在的类扩展方法和属性

为了满足开放封闭原则,类是允许扩展,同时严禁修改的,但是实现扩展并不轻松,在Java里,我们需要先再造一个新的类,在新类里继承或者引用旧类,然后才能在新类里扩展方法和属性,实际上Java里层层嵌套的类也非常多。

在Kotlin里,这就简洁优雅地多,她允许直接在一个旧的类上做扩展,即使这是一个final类。

例如,Android中常见的Toast,参数较多,写起来也相对繁琐,我们一般是新建一个Util类去做一个相对简单的函数,比如叫做showLongToast什么的,我们不会想在Activity或Fragment中扩展这个函数,因为太麻烦,我们需要继承Activity做一个比如叫ToastActivity的类,在里面扩展showLongToast函数,然后把业务Activity改为继承这个ToastActivity...

在Kotlin里,我们只需要这样写


扩展函数

就完成了Activity类的函数扩展,我们可以在Activity及其子类里随意调用了


调用扩展函数

需要注意的是,你无法用扩展去覆盖已存在的方法,例如,Activity里已经有一个onBackPressed方法,那么你再扩展一个Activity.onBackPressed方法是无用的,当你调用Activity().onBackPressed()时,它只会指向Activity本身的那个onBackPressed方法。

我们还可以用类似的方式去扩展属性


扩展属性

不过,Kotlin的扩展其实是伪装的,我们并没有真正给Activity类扩展出新的函数或属性,你在A类里为Activity扩展了函数,换到B类里,你就找不到这个函数了。

这是因为,Kotlin为类扩展函数时,并没有真的去修改对应的类文件,只是借助IDE和编译器,使他看起来像扩展而已。

所以,如果类的某些函数只在特殊场景下使用,可以使用灵活简洁的扩展函数来实现。

但是,如果想为类永久性地添加某些新的特性,还是要利用继承或者装饰模式(decorator)。

不过,Kotlin里对于类的家族定义和Java有所不同,我们来看一下

15.类的家族结构

Kotlin关于类的家族结构的设计,和Java基本相似,但是略有不同:

Object:取消,在Java里Object是所有类的基类,但在Kotlin里,基类改成了Any

Any:新增,Kotlin里所有类的基类

object:新增,Kotlin是区分大小写的,object是Kotlin中的单例类

new:取消,Kotlin不需要new关键字

private: 仍然表示私有

protected: 类似private,在子类中也可见

internal: 模块内可见

inner:内部类

public: 仍然表示共有,但是Kotlin的内部类和参数默认为public

abstract:仍然表示抽象类

interface:仍然表示接口

final:取消,Kotlin的继承和Java不同,Java的类默认可继承,只有final修饰的类不能继承;Kotlin的类默认不能继承,只有为open修饰的类能继承

open:新增,作用见上一条

static:取消!Java用static去共享同一块内存空间,这是一个非常实用的设计,不过Kotlin移除了static,用伴随对象(前面提到过的compaion object)的概念替换了static,伴随对象其实是个单例的实体,所以伴随对象比static更加灵活一些,能去继承和扩展。

继承:在Kotlin里,继承关系统一用“:”,不需要向java那样区分implement和extend,在继承多个类/接口时,中间用“,”区分即可,另外,在继承类时,类后面要跟()。所以在Kotlin里,继承类和接口的代码一般是这样的:

class BaseClass : Activity(), IBinder{ //示例

16.构造函数

在Java里,类的构造函数是这样的

pulic 类名作为函数名 (参数) {...}

Java里有时会重载多个构造函数,这些构造函数都是并列的

在Kotlin里,类也可以有多个构造函数(constructor),但是分成了1个主构造函数和N个二级构造函数,二级构造函数必须直接或间接代理主构造函数,也就是说,在Kotlin里,主构造函数有核心地位

主构造函数一般直接写在类名后面,像这么写

class ClientInfo(id:Long,name:String,addr:String){

这其实是个缩写,完全版本应该是

class ClientInfo constructor(id:Long,name:String,addr:String){

主构造函数的这个结构,基本决定了,在这个主构造函数里,没法写初始化代码...

而二级构造函数必须代理主构造函数,写出来的效果是这样的


二级构造函数

17.初始化模块init

上一节提到过,主构造函数里不能写代码,这就很麻烦了,不过还好,Kotlin提供了初始化模块,基本上就是用init修饰符修饰一个{},在类初始化时执行这段儿代码,代码像这样写就行


初始化模块

18.其他

Kotlin还有很多其他的语言特性,本文主要是为了建立对Kotlin的大概印象,更多细节就不再列举了,建议仔细阅读Kotlin官方文档,并且多动手写一些代码。

函数式编程

读到这里,我们发现熟悉Java的人好像很容易学会Kotlin,甚至会感觉Kotlin不像一门新语言。但语法只是让我们能用Kotlin,要想用好Kotlin,就必须理解Kotlin背后的函数式编程理念。

一个用惯了锤子的人,看什么都像是钉子,我们必须先扔掉锤子,再去理解函数式编程。

我们先重新理解一下什么是计算机,什么是编程:

1.计算机:人发明计算机是为了计算数据(二战期间为了把炮弹打得更准,需要解大量的微积分,就造了台计算机帮忙,我们知道第一台通用计算机叫做ENIAC,这名字不是它的昵称绰号,就是它的功能,ENIAC的全称为Electronic Numerical Integrator And Computer,即电子数字积分计算机),直到现在,计算机程序在底层硬件电路上仍然是0和1的计算问题。

2.计算:计算机很笨,它其实只会计算0和1;但是人很聪明,人发现只要能把问题转换成0和1的运算,就可以丢给计算机去处理了,然后,几乎所有的问题,都可以设法转换成0和1的计算问题。

3.程序:一次或几次0和1的计算,几乎不能解决任何问题,需要很多次,步骤很复杂,过程很详细的0和1的计算才行,这种专为计算机提供的复杂而详细的计算步骤,就是计算机程序(为了向计算机传递程序,早期用打孔的纸带,后来用磁带,再后来用软盘,再后来是硬盘、光盘、闪存什么的...)。

4.编程:编程就是编写计算机程序,目的是把具体问题转换成0和1的运算问题,然后交给计算机去处理。

5.语言:编写计算机程序是给计算机用的,所以早期用的都是机器语言(全是0和1)。这样写出来的程序全是0和1,人自己反而看不懂,所以就抽象出汇编语言,就像把英文翻译成中文一样,这样人比较容易看懂。但是汇编语言描述的是底层电路的运算过程(把数据从内存的这里搬到那里,寄存器里的一个数据减去1,另一个数据乘以2),具体的输入、输出以及运算的目的都很难识别出来,所以又抽象出高级语言(C、BASIC等),不用再写底层电路如何操作(高级语言需要先经过编译器生成对应的汇编语言,再交给计算机去操作底层电路),只关心如何实现真实世界的业务逻辑。


编程语言和现实世界

6.抽象:编程的目的是把具体问题转成0和1的计算问题,在高级语言里不用再考虑0和1了,我们可以更自由地把真实世界抽象为某种模型以便编写代码,这种抽象建模的过程,就是我们编程的核心能力

7.流派:关于如何对真实世界进行抽象,是有不同流派的,面向对象是和面向过程对应的,函数式编程是和命令式编程对应的

8.面向过程和面向对象:计算机的使命是用来计算,所有的计算都是有具体过程的,这样就会很自然地把真实世界映射为计算的过程,对真实世界的建模就是直接建出一个个业务的流程,然后去运转而已。但是日益复杂的流程会变成一团乱麻,难以理解,难以修复,难以扩展;

在面向对象中,不再纠结于流程本身,而是抽象出了对象的概念,把业务中的相关要素抽象为互相独立又互相调用的对象,对象和对象之间的关系(继承、封装、多态)成为核心,由于对象的概念更贴近人对于真实世界的理解,而且对象之间的关系也比整条复杂的流程简单,修改或者扩展起来的波及范围也小,容易理解/分解/修改/组合/扩展,所以面向对象非常适合大型的软件工程


面向过程和面向对象

9.命令式编程和函数式编程:换个角度来看,在计算机中实现业务逻辑有两种书写方式,一种是像输入命令一样,一步一步告诉计算机如何处理业务逻辑(还记得吗,计算机很笨,只会做它懂的事情),这就是命令式编程。如果命令有误,就是处理失败,如果要修改业务,就要把整个业务相关的命令都去检查和修改一遍。

另一种是告诉计算机,我需要什么,不去详细地告诉它要怎么做,由于计算机不可能理解我们的需求,所以我们把函数拼接到一起,让数据按照我们设想的方式流动,我们只要在数据流的最前面输入参数,等数据自己流完整个处理过程,就能得到我们需要的数据。如果数据有误或者需要修改业务,我们就去调整这个数据流,将它里面的数据流动调整为我们需要的方式。


命令式和函数式

我们看到,函数式编程的运算过程是高度抽象的,能节省大量运算细节的代码编写和debug工作。

10.区别:面向对象和函数式编程是有区别的,面向对象把真实世界抽象为类和对象,函数式编程则把真实世界抽象为函数;面向对象关心的是对象的行为,以及对象之间的关系,而函数式编程关心的是函数的行为,以及对函数的组合运用;面向对象只要对象不出错,对象关系不出错就可以,函数式编程只要奔涌在函数组合里的数据流按照预期进行转换就可以。

11.选择:在抽象建模的概念里,面向对象因为贴近真实世界,相对简单容易理解,工程上还容易扩展维护,所以很长一段时间以来,面向对象在软件工程领域备受欢迎。

12.现实:从时间上来看,函数式编程其实并不新潮,但是过去主要活跃在大学和实验室里,这几年突然变得火热,背后一定有现实的原因。

13.硬件和并行:这些年来,对计算机的应用越来越广泛,丢给计算机处理的问题越来越多,计算量越来越大,所以计算机CPU就越来越快,一开始还能每18个月翻一番(摩尔定律),到了这几年单核CPU逼近物理极限,提升有限,就开始着重搞多核,并行计算也越来越重要。

14.数据的问题:计算机的本质在于计算数据,而软件最大的问题则是计算错误(出bug),不巧的是,面向对象编程在并行计算里就特别容易出现bug,因为她的核心是各种独立而又互相调用的对象,当多个对象同时处理数据时,就很容易导致数据修改的不确定性,从而引发bug。

15.混合:编程的本质是把真实世界抽象映射到计算机的电路上,采用的抽象模式只是工具而已,我们没有必要排斥函数式编程,也不需要放弃面向对象,Kotlin也同时支持这两种方式,我们需要的是根据需要选用工具,用锤子,用扳手,或者两者都用。

要更深入地理解函数式编程,有一篇So You Want to be a Functional Programmer,写的非常好,在函数式编程里,我们需要用到纯函数、不变性、高阶函数、闭包等概念。

纯函数

开发者在学习编程之前,其实都学过数学,在数学的范畴里,函数的运算是不受干扰的,比如你算一个数字的平方根,只要参数确定,计算的过程永远是一致的,算出来的结果永远是一样的。

但是在学习编程(命令式编程)之后,函数就变了,变得“不纯洁”了,函数的运算会受到干扰,而且干扰无处不在,例如,我们可以在函数里使用一个会变化的全局变量,只要在任何位置/时间/线程里修改这个全局变量,函数就会输出不同的结果。


函数会受到干扰

如果这种变化是开发者故意设计的,开发者就把它称为业务逻辑;如果这种变化不符合开发者的预期,开发者就把它称为——bug,悲剧的是,在命令式编程里,有无数的对象、时间点、线程可能对函数造成干扰。

在函数式编程里,重心是函数组合和数据流,更加不允许有干扰,所以要求我们编写纯函数。

不过,纯函数就像是编码规范,Kotlin鼓励而不是强制写出函数,毕竟,编程是为了与真实世界交互的,有时候必须使用一些“不纯洁”的函数,所以我们不要求彻底的纯函数化,只要求尽量写出纯函数

不变性

函数式编程不仅要求纯函数,还要求保存不变性(Kotlin用val和集合表示不变性,是的,集合默认是不可变的)

还是先回到数学上,在数学里,不允许这样的表达(我在刚学编程时,看到这个式子也是颠覆三观的)

x = x + 1

在函数式编程里,这种表达也是非法的,也就是说,在函数式编程里,没有可变变量,一个变量一旦被赋值,就不可更改。

不变性有很多好处,这意味着程序运行的整个流程是固定可重现的,如果出了问题,只要跟着数据流走一遍就能找到出错点,再也不会有稀奇古怪的变化来为难我们。

可是,如果变量不可变,我们还要怎样去做业务逻辑呢,函数式编程给出的方式就是——用函数去返回一个复制的新对象,在这个新的对象里,改掉你想改的那个值。

更彻底地说,函数式编程里,没有变量,一切都是函数(就像面向对象编程里,一切都是对象),变量实际上被函数取代了


函数式编程里的变量也是函数

所以,函数式编程里只能新增变量,不能修改变量,所以函数式编程可能会非常耗内存(生成的变量太多了,而且业务不走完,变量不释放)

所以,在函数式编程里还有一个特点——没有循环,因为for(i: i<9;i++)是非法的(当然,在Kotlin里你还可以这样写,因为Kotlin既支持函数式编程,又支持面向对象)

高阶函数

既然变量已经被函数取代了,那么函数里的参数和返回值呢?这些对象是不是也可以被替换成为函数呢?

在面向函数编程里,有个重要的概念,叫做“函数是一等公民”,核心就是,函数拥有和数据一样的地位,都可以作为参数和返回值,相应的就出现了高阶函数的概念,简单理解,高阶函数就是参数为函数,或者返回值为函数的函数。


可以把函数作为输入输出

我们知道,在开发过程中,复用是非常重要的优化手段,说白了,能用1个函数就别用多个函数,不容易出错,出错也容易检查和修改

那么我们看下面这两个函数,要怎么优化?

fun getA(){

doA()

}

fun getB(){

doB()

}

在面向对象编程里,我们第一反应是用接口和类来解决问题,当然,那样就得好几个类和接口,然后层层嵌套

有了高阶函数的话,开头那段代码就可以这样优化了

fun getAB(doA()){

}

(在Kotlin里不能直接这么写,需要用Lambda表达式才行)

在Kotlin里,lambda还可以作为一种类型,可以被定义为val


一个lambda的类型

调用这个lambda类型的“对象”,与调用函数无异


调用

闭包

前面说过,函数式编程里的函数是第一等公民,所以,一个val可以是一段代码,这就是一个闭包


一个闭包

不过,闭包不是函数,闭包在逻辑上是封闭的,它使用自己内部的数据,用自己内部的逻辑进行处理,外部只能得到闭包的输出,无法输入,也无法干扰。

在系统资源上,闭包是持久使用的,它会一直在系统里,不像函数那样会被系统注销掉。

闭包在函数式编程里可以简化参数量、减少变量,会更加方便我们的开发。

其他

另外,函数式编程还有柯里化、inline、with、apply、let、run、it等概念,我们以后可以慢慢了解

接下来,我们看看Kotlin里支撑起函数式编程的Lambda表达式、流式API等特性。

Lambda表达式

为了写高阶函数和闭包,Kotlin支持我们使用Lambda表达式。

Lambda表达式也叫λ表达式,它看起来就是对匿名方法(如:回调、事件响应、Runnable等)的简化写法,目的是为了更贴近函数式编程把函数作为参数的思想。

Lambda表达式包括最外面的“{}”,用“()”来定义的参数列表,箭头->,以及一个表达式或语句块。

事件响应的简化:

textView.setOnClickListener(newOnClickListener(){

   @Override

   public void onClick(View view){//todo}

   }

);

简化为

textView.setOnClickListener{/*todo*/}

Runnable的简化:

executor.submit(

   newRunnable(){

     @Override

     public void run(){

         //todo

     }

  }

);

简化为:

executor.submit({//todo })

使用lambda表达式,我们就可以编写高阶函数,传递一个函数(或者一段代码)作为参数。

流式(Stream)API

前面提过,函数式编程以数据流为中心,通过组合函数来整理一个数据流,通过调整这个函数组合得出需要的数据。

要让数据流在组合函数里流动起来,就需要使用流式API,流式API使我们更容易把函数组合起来,而且使整个数据流动过程更加直观。

如果接触过Java8或者RxAndroid,应该很容易理解流式API,我以前写过RxAndroid使用初探—简洁、优雅、高效,感兴趣可以去读一下,流式API写出来的代码风格如下


流式API的代码风格

Kotlin的潜在问题

Kotlin也有一些潜在的问题是我们需要注意的,主要是开发时容易遇到的一些问题。

思维方式的问题

我们已经知道Kotlin的核心在于函数式编程,问题在于函数式编程的核心不是语法的问题,而是思维方式的问题,语法容易转变,思维却很难,所以没有函数式编程经验的话,切换到Kotlin其实会相当困难。

Kotlin和Java需要在module级别隔离

虽然Kotlin和Java的兼容性非常好,但毕竟是不同的编程语言,编译过程不同,所以同一个module里不能同时存在java和kotlin两种文件,编译器会告诉你Unable to read class file,也就是说如果你将某个module配置为kotlin模块,里面就不能有java文件,反之亦然。

所以,如果觉得Kotlin和Java兼容良好就开始向工程项目里添加Kotlin文件,是行不通的,你至少要新建一个module才行。

Kotlin->Java的转换

我们应该注意,AS中只提供了从Java文件转换为Kotlin文件的工具,并没有逆向转换的工具,就是说目前你还不能很轻松地把Kotlin代码转换为Java代码,一件事情如果不能回退,就必须小心谨慎。

团队开发的问题

一般来说,鉴于Kotlin和Java兼容良好,可以一边维持旧的Java代码,一边开发新的Kotlin代码和新的Java代码,但是团队开发不仅是兼容性的问题,Kotlin语法糖背后的很多思维方式也许会对团队造成冲击,例如,一旦某个模块采用了流式API的话,其他团队成员在调用这个模块时,也需要理解并且能够编写流式API才能完成工作衔接,这就可能带来额外的成本和意外的延期。

最后,简单介绍一下怎样开始在AS中使用Kotlin语言。

在AS中使用Kotlin语言

Android Studio对Kotlin的支持非常友好(毕竟算是同门),我们先简单地看一下怎样安装和使用Kotlin(AS版本2.2.3),再来体会Kotlin在编程上的优势。

1.安装


插件

打开settings-plugins-install JetBrains plugin...

点击“Install JetBrains Plugin...”,然后搜索kotlin。


搜索

搜索并安装kotlin

安装


下载

Kotlin安装中

重启AS


重启

重启AS

2.使用

创建项目:没有变化。

创建Activity:增加了Kotlin Activity的选项。


activity

增加了Kotlin Activity

创建类/文件:增加了Kotlin文件/类的选项,同上图。

Kotlin的文件类型在右下角都有个“K”字形的角标。


文件

Kotlin文件

初次创建时会提示需要进行配置,实际就是告诉编译器,这个module用kotlin编译还是用java编译。


配置

提示配置Kotlin

Kotlin和Java可以无缝兼容,但是需要你通过配置,说明哪些module是Kotlin的,哪些module是Java的。


选择编译语言

选择哪些module是Kotlin的

在project的gradule里增加了kotlinversion和dependencies的引用


gradule

project的gradule设置

在app的gradule里增加了关于Kotlin的app plugin和dependencies


app graduate

app的gradule设置

针对已经存在的Java文件,可以转换为Kotlin文件


convert

转换文件

Kotlin文件的后缀名不再是.java,而是.kt


后缀名

文件扩展名为kt(上图是为了对比,实际编译时不能在一个module里有两种文件)。

现在,我们可以编写Kotlin代码了。

参考

Kotlin官方文档

Using Project Kotlin for Android

Swift is like Kotlin

Kotlin相对于Java的优势比较

为什么我要改用Kotlin

用 Kotlin 写 Android ,难道只有环境搭建这么简单?

用 Kotlin 写 Android 02 说说 Anko

使用Kotlin&Anko, 扔掉XML开发Android应用

400% faster layouts with Anko

NullPointException 利器 Kotlin 可选型

Data Classes in Kotlin: save a good bunch of lines of code (KAD 10)

函数式编程扫盲篇

So You Want to be a Functional Programmer


查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. springsecurity忽视拦截静态资源

    springsecurity项目中,引入了css和js后,发现,都被拦截了。 然后去百度,发现好多博客都是相互抄袭的,,神tm都没说清楚。。我,心态崩了 要么就是根本不起作用,要么就是404错误。 最后的解决方法是。 在static中再新建一个目录。把所有的静态资源放在这个新建的目录中,再…...

    2024/3/31 22:28:54
  2. PHP一键比对更新MYSQL数据库的一些想法

    帮一个朋友维护CMS,具体的还要有一键远程匹配数据库的功能。当时给的需求是:1.能够一键比对远程服务器上的数据库的表和字段。2.比对完成后,如果发现某表或者某字段缺失,那么就自动生成sql语句,来重新生成一个“补丁”开始以为很简单,其实还蛮复杂的。一开始就要进更新服…...

    2024/4/16 22:35:51
  3. 企业开发专栏《物业管理系统》(一)

    自我介绍我是一名可怜的码农,我叫李森林(多亏这个五行缺木的名字,让很多人记得我),现在工作于佛山市的元海集团(可百度科普),喜欢专研新技术,喜欢java后端,移动端乃至前端的各种新花样的技术,追求灵活,高拓展,高可用,也是一名喜欢制造轮子,固执的追根究竟的人,认识我…...

    2024/4/25 1:47:50
  4. 2013/10/28重读VLC代码

    PreferenceManager和editor的使用mSettings = PreferenceManager.getDefaultSharedPreferences(this);/* Check if its the first run */ mFirstRun = mSettings.getInt(PREF_FIRST_RUN, -1) != mVersionNumber; if (mFirstRun) { Editor editor = mS…...

    2024/4/18 12:20:15
  5. SpringBoot-集成SpringSecurity+jwt详解+代码

    SpringSecurity是什么?简单而言是一套权限鉴定完整框架!印象最深是有它的一套拦截链实现拦截,权鉴等措施。看本文须知:忘掉最简单配置的SpringSecuritySpringSecurity为什么存在?不用自己去手写拦截了!简单!完整!思路描述:首先用户如果不登陆,就无法对特定的请求,页…...

    2024/4/18 14:29:47
  6. kotlin编写编译时注解

    1.定义注解 As里新建一个Java Library module,必须是Java Library Module此处命名为route-api 该module存放一些与纯java类相关的文件1. 定义一个注解 Route /** * @param name 路由用的跳转名字,该key与一个.Class关联,若不填写默认为Activity类名去掉“Activity”,如Main…...

    2024/4/16 22:35:39
  7. 據說很牛的英文歌曲(轉的。。)

    1. dont cry--guns n roses这首歌曾唱哭了千万人。总是能够触痛了心底最软的地方,心抽痛着,眼圈红了,却没有眼泪渗出,每多听一次就多一次的依恋... 2. fade to black--METAllic金属乐队也有很经典歌曲,相信国内有好多人都是听了这首歌的前奏才去学吉他的!METALLICA经…...

    2024/4/16 22:37:09
  8. 通过Linux Diff命令判断两个源代码是否相同

    看到这个博客标题,可能很多朋友会觉得太简单了,不就直接使用Diff就行了吗?但是对于如Java源代码的比较,有一些额外需要考虑的因素:多余的空行不能算差别、Java源代码中的注释也不能算差别。下面举两个例子来说明这种需求:test //command /*1 *11以及:test //command2 /*…...

    2024/4/16 22:35:45
  9. Spring Security 自带防火墙!你都不知道自己的系统有多安全!

    之前有小伙伴表示,看 Spring Security 这么麻烦,不如自己写一个 Filter 拦截请求,简单实用。 自己写当然也可以实现,但是大部分情况下,大家都不是专业的 Web 安全工程师,所以考虑问题也不过就是认证和授权,这两个问题处理好了,似乎系统就很安全了。 其实不是这样的! 各…...

    2024/4/18 17:26:03
  10. Kotlin入门:集合操作

    1. 介绍 作为Kotlin入门的第二课,不打算按照教程从基础数据类型开始,而是直接学习至关重要的集合部分。因为一般的应用开发都离不开数据,数据处理就要用到集合,而只有深入了解集合,包括概念及不同类型的集合分别实现了哪些方法,才能在需要的时候快速选出最合适的集合与对…...

    2024/4/4 21:55:28
  11. Linux必学的60个命令(6)-其他命令

    Linux必学的60个命令:其它命令在前面几讲中,我们把Linux命令按照在系统中的作用分成几个部分分别予以介绍。但是,还有一些命令不好划分,然而学习它们同样是比较重要的。 tar1.作用tar命令是Unix/Linux系统中备份文件的可靠方法,几乎可以工作于任何环境中,它的使用权限是所…...

    2024/4/19 16:55:37
  12. javascript的json比对插件

    在 http://www.ecjson.com/jsondiff 看到1款js的json比对插件,觉得挺好就拔了下来,仅供大家学习使用优点: json格式检测,高亮显示,json比对3种显示模式默认模式<script> $(function () {var JSON_PARAM = utils._getURLParameter(json);// this needs to be in a co…...

    2024/4/16 22:35:57
  13. Spring Security 中如何快速查看登录用户 IP 地址等信息?

    上篇文章跟大家聊了如何使用更加优雅的方式自定义 Spring Security 登录逻辑,更加优雅的方式可以有效避免掉自定义过滤器带来的低效,建议大家一定阅读一下,也可以顺便理解 Spring Security 中的认证逻辑。 本文将在上文的基础上,继续和大家探讨如何存储登录用户详细信息的问…...

    2024/4/16 22:35:39
  14. Kotlin VS Swift

    Kotlin是Android的最新开发语言;Swift是iOS的最新开发语言;二者语法很像, 下面就对比一下。Kotlin中文网站: https://www.kotlincn.net/docs/reference/basic-syntax.html按官方文档顺序说明:功能KotlinSwift说明定义包package com.*.* …...

    2024/4/16 22:35:57
  15. SpringSecurity | spring security oauth2.0 配置源码分析(一)

    微信公众号:吉姆餐厅ak 学习更多源码知识,欢迎关注。概述 在微服务发展迅速的今天,认证授权独立成微服务已是一种趋势,不仅承担着整个系统访问入口的认证和授权,还要易于扩展,能更好的接入第三方服务。而当今Oauth2协议在认证授权领域大行其道,算是功能比较完整的权限协…...

    2024/3/31 22:28:49
  16. Android配置文件操作模块封装,全互联网最简单好用的封装

    Android中虽然提供了SharedPreference类方便的对配置文件进行操作。但是好用吗?假如有成百上千的参数需要存储,这样一个个分散的写法累死个人啊。本来几分钟能搞定的活,你可能得几个钟头。效率能是一个等级?且到处分散的写法,也容易让人看晕,给维护造成困难。先来看结果:…...

    2024/4/18 10:57:29
  17. 使用工具Android Studio实现一个简单的Android版的新闻APP

    目的:这是我学完Android课程后所写的一个小的、简单版的新闻APP技术概要:用到了SQLite数据库,用它来存储每篇新闻下的评论新闻的来源是新浪新闻,我通过使用Fiddler来对新浪新闻APP进行分析,发现了它们传递新闻的接口,也就是得到了json数据,然后解析json数据就可以得到新…...

    2024/4/17 21:30:37
  18. WinMerge比对java文件设置

    因为我的svn目录和实际开发的代码目录是两个目录,所以需要每次从SVN更新代码之后,对两个目录做一个内容比较,同步新引入的代码文件。这样可以使用WM的名为“Exclude Source Control”过滤器,下面黑体字部分是我针对自己的Java项目的情况做了一些调整: ## This is a direct…...

    2024/4/16 22:36:45
  19. 开始迁移到 Kotlin | Kotlin 迁移指南 (中篇)

    今年五月份的 Google I/O 上,我们正式向全球宣布 Kotlin-first 的这一重要理念,Kotlin 将成为 Android 开发者的首选语言,十月份举办的 Android Dev Summit 2019 大会上,我们发布了使用 Kotlin API 开发的 Jetpack Compose 开发者预览版。我们于近期开始连载了关于 Kotlin …...

    2024/4/16 22:36:57
  20. android基础---背景音乐实现

    1.背景音乐在menu中设置: menu.xml <menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"tools:context="com.echo.sb.MainActivity" ><itemandroid:id="@+id/acti…...

    2024/4/18 18:57:12

最新文章

  1. STM32单片机wifi云平台+温度+烟雾+火焰+短信+蜂鸣器 源程序原理图

    目录 1. 整体设计 2. 液晶显示 3. Ds18b20温度传感器 4. Mq2烟雾传感器 5. 火焰传感器传感器 6. 蜂鸣器驱动控制 7. 按键 8. Gsm短信模块 9. Esp8266wifi模块 10、源代码 11、资料内容 资料下载地址&#xff1a;STM32单片机wi…...

    2024/5/4 14:24:17
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 策略模式图

    策略模式 小小的图解 主要的三个角色 Strategy—抽象策略角色ConcreateStrategy—具体策略角色Context—上下文角色 封装了对具体策略的调用可以使用set的依赖注入也可以使用构造方法 核心是上下文角色 只要调用上下文角色就行&#xff0c;实现解耦 策略 工厂 将上下文角…...

    2024/5/4 1:52:24
  4. 全自动封箱机的工作原理:科技与效率的完美结合

    随着科技的不断发展&#xff0c;越来越多的自动化设备走进了我们的日常生活和工业生产中。其中&#xff0c;全自动封箱机作为物流包装领域的重要一环&#xff0c;凭借其高效、精准的工作性能&#xff0c;正逐渐成为提升生产效率、降低劳动成本的得力助手。星派就来与大家深入探…...

    2024/5/1 13:53:51
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/3 23:10:03
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/4 2:59:34
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57