-
java基础有哪些_java基础都有那些?
2021-03-01 06:06:35展开全部java语法基础1,关键字:其实就是某种语言赋予了特殊含义的单词。e5a48de588b662616964757a686964616f31333365633837保留字:其实就是还没有赋予特殊含义,但是准备日后要使用过的单词。2,标示符:其实就是...展开全部
java语法基础
1,关键字:其实就是某种语言赋予了特殊含义的单词。e5a48de588b662616964757a686964616f31333365633837
保留字:其实就是还没有赋予特殊含义,但是准备日后要使用过的单词。
2,标示符:其实就是在程序中自定义的名词。比如类名,变量名,函数名。包含 0-9、a-z、$、_ ;
注意:
1),数字不可以开头。
2),不可以使用关键字。
3,常量:是在程序中的不会变化的数据。
4,变量:其实就是内存中的一个存储空间,用于存储常量数据。
作用:方便于运算。因为有些数据不确定。所以确定该数据的名词和存储空间。
特点:变量空间可以重复使用。
什么时候定义变量?只要是数据不确定的时候,就定义变量。
变量空间的开辟需要什么要素呢?
1,这个空间要存储什么数据?数据类型。
2,这个空间叫什么名字啊?变量名称。
3,这个空间的第一次的数据是什么? 变量的初始化值。
变量的作用域和生存期:
变量的作用域:
作用域从变量定义的位置开始,到该变量所在的那对大括号结束;
生命周期:
变量从定义的位置开始就在内存中活了;
变量到达它所在的作用域的时候就在内存中消失了;
数据类型:
1):基本数据类型:byte、short、int、long、float、double、char、boolean
2):引用数据类型: 数组、类、接口。
级别从低到高为:byte,char,short(这三个平级)-->int-->float-->long-->double
自动类型转换:从低级别到高级别,系统自动转的;
强制类型转换:什么情况下使用?把一个高级别的数赋给一个别该数的级别低的变量;
运算符号:
1)、算术运算符。
+ - * / % %:任何整数模2不是0就是1,所以只要改变被模数就可以实现开关运算。
+:连接符。
++,--
2)、赋值运算符。
= += -= *= /= %=
3)、比较运算符。
特点:该运算符的特点是:运算完的结果,要么是true,要么是false。
4)、逻辑运算符。
& | ^ ! && ||
逻辑运算符除了! 外都是用于连接两个boolean类型表达式。
&: 只有两边都为true结果是true。否则就是false。
|:只要两边都为false结果是false,否则就是true
^:异或:和或有点不一样。
两边结果一样,就为false。
两边结果不一样,就为true.
& 和 &&区别: & :无论左边结果是什么,右边都参与运算。
&&:短路与,如果左边为false,那么右边不参数与运算。
| 和|| 区别:|:两边都运算。
||:短路或,如果左边为true,那么右边不参与运算。
5)、位运算符:用于操作二进制位的运算符。
& | ^
<< >> >>>(无符号右移)
练习:对两个变量的数据进行互换。不需要第三方变量。
int a = 3,b = 5;-->b = 3,a = 5;
a = a + b; a =8;
b = a - b; b =3;c
a = a - b; a =5;
a = a ^ b;//
b = a ^ b;//b= a ^ b ^ b = a
a = a ^ b;//a= a ^ b ^ a = b;
练习:高效的算出 2*8 ------------------> 位移运算的考验,java基础面试中它的曝光率不低哦
5,语句。
If switch do while while for
这些语句什么时候用?
1)、当判断固定个数的值的时候,可以使用if,也可以使用switch。
但是建议使用switch,效率相对较高。
switch(变量){
case 值:要执行的语句;break;
…
default:要执行的语句;
}
工作原理:用小括号中的变量的值依次和case后面的值进行对比,和哪个case后面的值相同了
就执行哪个case后面的语句,如果没有相同的则执行default后面的语句;
细节:1):break是可以省略的,如果省略了就一直执行到遇到break为止;
2):switch 后面的小括号中的变量应该是byte,char,short,int四种类型中的一种;
3):default可以写在switch结构中的任意位置;如果将default语句放在了第一行,则不管expression与case中的value是否匹配,程序会从default开始执行直到第一个break出现。
2)、当判断数据范围,获取判断运算结果boolean类型时,需要使用if。
3)、当某些语句需要执行很多次时,就用循环结构。
while和for可以进行互换。
区别在于:如果需要定义变量控制循环次数。建议使用for。因为for循环完毕,变量在内存中释放。
break:作用于switch ,和循环语句,用于跳出,或者称为结束。
break语句单独存在时,下面不要定义其他语句,因为执行不到,编译会失败。当循环嵌套时,break只跳出当前所在循环。要跳出嵌套中的外部循环,只要给循环起名字即可,这个名字称之为标号。
代码片段:
z: //for循环标号
for(int x=0;x<3;x++){
for(int y=0;y<2;y++){
//不带标号的就是结束整个循环体的作用,在那个循环内部就结束哪个循环
if(x==1)break;
//带标号跳过break后面的语句,回到标号位置的循环,继续该循环下次的条件判断,
//已决定是否执行该循环体
if(x==2&&y==1)break z;
}
}
continue:只作用于循环结构,继续循环用的。
作用:结束本次循环,继续下次循环。该语句单独存在时,下面不可以定义语句,执行不到。
6,函 数:为了提高代码的复用性,可以将其定义成一个单独的功能,该功能的体现就是java中的函数。函数就是体现之一。
java中的函数的定义格式:
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数1,…){
执行语句;
return 返回值;
}
当函数没有具体的返回值时,返回的返回值类型用void关键字表示。
如果函数的返回值类型是void时,return语句可以省略不写的,系统会帮你自动加上。
return的作用:结束函数。结束功能。
如何定义一个函数?
函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:
1)、明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。
2)、在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参数列表(参数类型&参数个数)。
函数的作用:
1)、用于定义功能。
2)、用于封装代码提高代码的复用性。
注意:函数中只能调用函数,不能定义函数。
主函数:
1)、保证该类的独立运行。
2)、因为它是程序的入口。
3)、因为它在被jvm调用。
函数定义名称是为什么呢?
答:1)、为了对该功能进行标示,方便于调用。
2)、为了通过名称就可以明确函数的功能,为了增加代码的阅读性。
重载的定义是:在一个类中,如果出现了两个或者两个以上的同名函数,只要它们的参数的个数,或者参数的类型不同,即可称之为该函数重载了。
如何区分重载:当函数同名时,只看参数列表。和返回值类型没关系。
7,数 组:用于存储同一类型数据的一个容器。好处:可以对该容器中的数据进行编号,从0开始。数组用于封装数据,就是一个具体的实体。
如何在java中表现一个数组呢?两种表现形式。
1)、元素类型[] 变量名 = new 元素类型[元素的个数];
2)、元素类型[] 变量名 = {元素1,元素2...};
元素类型[] 变量名 = new 元素类型[]{元素1,元素2...};
---------------------------------------------------------
//二分查找法。必须有前提:数组中的元素要有序。
public static inthalfSeach_2(int[] arr,int key){
int min,max,mid;//定义最小,最大,中间数
min = 0;//最小为0
max =arr.length-1;// 最大为数组的长度-1
mid =(max+min)>>1; //(max+min)/2;//中间数为最大加最小除以2
while(arr[mid]!=key){//如果数组中间值不等于key
if(key>arr[mid]){//如果key>中间值
min = mid+ 1;
}
elseif(key
max = mid- 1;
if(max
return -1;
mid =(max+min)>>1;
}
return mid;
}
知识拓展:
java内存。
1:寄存器。2:本地方法区。3:方法区。4:栈。5:堆。
栈:存储的都是局部变量 ( 函数中定义的变量,函数上的参数,语句中的变量 );
只要数据运算完成所在的区域结束,该数据就会被释放。
堆:用于存储数组和对象,也就是实体。啥是实体呢?就是用于封装多个数据的。
1:每一个实体都有内存首地址值。
2:堆内存中的变量都有默认初始化值。因为数据类型不同,值也不一样。
3:垃圾回收机制。
已赞过
已踩过<
你对这个回答的评价是?
评论
收起
-
java类的无参构造函数_java中所有类都默认有一个无参构造函数吗?
2021-03-07 23:45:28当没有定义构造方法时每个类里都有一个默认的无参的构造方法,此时该类就只有一个构造方法;而当你显示定义类的构造方法时,那就没有那个默认的构造方法了,该类所以的构造方法就是定义了的那些构造方法。相关推荐:...当没有定义构造方法时每个类里都有一个默认的无参的构造方法,此时该类就只有一个构造方法;而当你显示定义类的构造方法时,那就没有那个默认的构造方法了,该类所以的构造方法就是定义了的那些构造方法。
相关推荐:《Java视频教程》
构造方法,顾名思义,就是在你new一个对象的时候就被调用的。当没有定义构造方法时每个类里都有一个默认的无参的构造方法,此时该类就只有一个构造方法;而当你显示定义类的构造方法时,那就没有那个默认的构造方法了,该类所以的构造方法就是定义了的那些构造方法;例如:定义一个Student类:class Student1{
//不定义构造方法,此时默认的构造方法是Student1();new
//一个对象时只能这样构造,Student1 s=new Studnet1();
}
另外再写一个有定义构造方法的类:
class Student2{
Student(String name);
Student(String name,int age);
}
Student2有两个构造方法,默认的构造方法就没有了
创建Student2对象时只能用两个构造方法Student2 s2=new Student2("xiaoming");
Student2 s2=new Student2("xiaoqiang",12);
还可以提供更多的构造方法,参数可以任意个,构造对象的时,就根据你定义的构造方法来构造。
-
java 匿名函数_函数式编程很难懂?其实真心很简单
2020-11-20 01:17:15话不多说,开始今天的学习:现在直播一直都很火,今天我们就用Java代码简单地模拟一个直播案例,以此来一步步说明什么叫函数式编程。不要看这个名字好像挺难懂的样子,其实很简单,两分钟时间即可看完。一、直播间...今天是我自学Java的第35天。
感谢你的观看,谢谢你。
话不多说,开始今天的学习:
现在直播一直都很火,今天我们就用Java代码简单地模拟一个直播案例,以此来一步步说明什么叫函数式编程。
不要看这个名字好像挺难懂的样子,其实很简单,两分钟时间即可看完。
一、直播间案例
现在有一个直播平台,它如何管理那些想直播的人?很简单,制定规则就好了,在Java里面接口的作用就是制定规则。
①有一个接口叫LiveRoom,就是直播间。
你想要直播?很简单,实现直播间接口就好了,实现了你就能开个直播间直播了。
②LiveRoom接口里有一个抽象方法叫live()
表示的就是直播间直播的什么内容?
你播游戏也行,播唱歌也行,播吃饭,播睡觉都可以,所以我用一个抽象方法表示直播的内容,你具体播什么我不清楚,都可以。
你实现我这个接口了,必须要重写live方法。
简单地理解就是,你必须得告诉我你直播什么,我才能让你直播,不然你不能有直播间。
规则制定完毕,好,现在有一个直播间,在玩游戏,一看直播间名字,哦,叫刘小爱。
这个用Java代码如何表现出来?
1.最常规代码
①创建一个刘小爱类
实现LiveRoom接口,刘小爱既然能直播,肯定是实现了直播接口的。
②重写接口里的live方法
刘小爱直播的是啥?哦,原来是魔兽rpg游戏。
③创建刘小爱对象
将刘小爱对象作为参数传入method方法。
④method方法
直播间会调用live方法,输出正在直播什么内容。
所以运行代码,控制台就会输出:“玩魔兽rpg游戏”。
现在问题来了,代码能不能简化?
可以的,使用匿名内部类就好了。
2.匿名内部类
我既然是看直播,直播间名字叫啥重要么?
直播间叫刘小爱也好,叫刘大爱也罢,哪怕是叫刘老爱都无关紧要,我是要看直播的内容,那我完全可以不用创建刘小爱类。
代码如下:
⑤匿名内部类
既然名字不重要,直播间没有名字了,那就直接用父接口LiveRoom的名字代替就好了。
new LiveRoom(){},这表示的就是LiveRoom的子类(实现类)对象,也就相当于是常规方法中的刘小爱对象。
匿名内部类省略了类名,不用创建一个实现类,所以更简单。
那还能不能再简化?
可以的,也就是今天的重点,函数式编程。
二、函数式编程
函数,这个概念我们在数学里面我们就接触过。
y=f(x)(y=x+1)这就是函数的格式,其中f是函数名,x是变量,y是函数值,还有定义域,值域什么的。
你发现没有,Java中的方法其实就是一个函数:
方法名不就是函数名么?参数也就是函数中的变量,返回值也就是函数值?它们本质上是一样的的,只不过叫法不一样,并且在有的编程语言中方法也就叫函数。
前面无论是最常规代码还是匿名内部类,它们都有一个重点:LiveRoom接口中的live方法,也就是重写后的方法。
函数式编程就是依据这个方法来的:
⑥Lambda表达式
lambda,中文翻译过来就是拉姆达,还记得数学中:λ这个字符么?说的就是它。
lambda表达式表示的是什么?本质上就是LiveRoom接口中的live方法。
- 没有参数,就用一个()表示;
- 有参数的话,就将参数写在()里面;
- 输出的内容为重写后的方法体;
- 如果有返回值,就用return返回;
- 如果没有返回值,return可以省略。
什么叫函数式编程?
就可以理解成用什么参数执行了一件什么事情,这就是函数式编程,它是匿名内部类进一步的简化,可以让代码更加的简洁。
但它有一个使用的前提,接口得是函数式接口。
什么叫函数式接口?
有且仅有一个抽象方法需要被重写的接口。
这个怎么理解?很简单,函数式编程和匿名内部类相比,它省略了啥?
它省略了接口中的方法名,为什么可以省略?
因为就只有一个方法,那就算省略了方法名字,也知道是用的那个方法。
这就好比你是家里的独生子,那你爸妈回来叫你宝贝,叫你甜心,叫你小兔崽子,别人都知道你爸妈是在叫你。
但如果你还有个弟弟,你爸妈再这么叫你,别人就搞不清楚你爸妈到底是在叫你,还是在叫你弟弟了。
关于函数式编程暂时就先介绍到这,以后有经典的笔试题会用代码再次演示,毕竟实战才是王道 。
总结:
-
java副函数_纯Java中的函数式编程:Functor和Monad示例
2021-03-08 09:44:45绝大多数程序员,特别是那些没有功能编程背景的程序员,都倾向于认为monad是某种神秘的计算机科学概念,因此从理论上讲,它对他们的编程事业没有帮助。这种消极的观点可以归因于数十篇文章或博客文章过于抽象或过于...绝大多数程序员,特别是那些没有功能编程背景的程序员,都倾向于认为monad是某种神秘的计算机科学概念,因此从理论上讲,它对他们的编程事业没有帮助。这种消极的观点可以归因于数十篇文章或博客文章过于抽象或过于狭窄。但是事实证明,即使在标准Java库中,monad也无处不在,尤其是从Java Development Kit(JDK)8开始(以后会有更多介绍)。绝对妙不可言的是,一旦您第一次了解monad,突然之间就会有几个完全不相同的目的无关的类和抽象变得熟悉。
Monad概括了各种看似独立的概念,因此学习Monad的另一种化身只需很少的时间。例如,您不必学习CompletableFuture在Java 8中的工作方式-一旦意识到它是monad,就可以精确地知道它的工作方式,以及从其语义中可以期待什么。然后您会听说RxJava听起来有很大不同,但是由于Observable是monad,因此没有太多要添加的内容。您已经不知不觉中已经遇到过许多其他的Monads示例。因此,即使您实际上没有使用RxJava,本节也将是有用的复习。
Functors
在解释什么是monad之前,让我们研究一个称为functor的简单结构。Functors是封装某些值的类型化数据结构。从语法的角度来看,Functors是具有以下API的容器:
import java.util.function.Function;
interface Functor {
Functor map(Function f);
}
但是仅语法是不足以了解什么是Functors。functor提供的唯一操作是带有函数f的map()。此函数接收框内的任何内容,对其进行转换并将结果按原样包装到另一个Functors中。请仔细阅读。Functor 始终是一个不可变的容器,因此map不会使执行该操作的原始对象发生突变。相反,它将返回包装在全新Functors中的结果(或结果-请耐心等待),Functors可能是类型R。另外,Functors在应用标识函数(即map(x-> x))时不应执行任何操作。这种模式应始终返回相同的Functors或相等的实例。
通常将Functor 与保存T的实例进行比较,其中与该值交互的唯一方法是对其进行转换。但是,没有从Functors解开或逃逸的惯用方法。值始终位于Functors的上下文内。Functors为什么有用?它们使用一个统一的,适用于所有集合的API概括了集合,promise,Optionals等多个常见习语。让我介绍几个Functors,以使您更流畅地使用此API:
interface Functor> {
F map(Function f);
}
class Identity implements Functor> {
private final T value;
Identity(T value) { this.value = value; }
public Identity map(Function f) {
final R result = f.apply(value);
return new Identity<>(result);
}
}
需要额外的F类型参数来进行Identity编译。在前面的示例中,您看到的是最简单的Functors,仅包含一个值。您只能在map方法内部对其进行转换,但是无法提取它。这被认为超出了纯Functors的范围。与Functors进行交互的唯一方法是应用类型安全的转换序列:
Identity idString = new Identity<>("abc");
Identity idInt = idString.map(String::length);
或流利地,就像您编写函数一样:
Identity idBytes = new Identity<>(customer)
.map(Customer::getAddress)
.map(Address::street)
.map((String s) -> s.substring(0, 3))
.map(String::toLowerCase)
.map(String::getBytes);
从这个角度来看,在Functors上的映射与调用链式函数没有太大不同:
byte[] bytes = customer
.getAddress()
.street()
.substring(0, 3)
.toLowerCase()
.getBytes();
您为什么还要打扰这样冗长的包装,不仅不提供任何附加值,而且也不能将内容提取回去?好了,事实证明您可以使用此原始Functors抽象对其他几个概念建模。例如,从Java 8开始,可选的是带有map()方法的Functors。让我们从头开始实现它:
class FOptional implements Functor> {
private final T valueOrNull;
private FOptional(T valueOrNull) {
this.valueOrNull = valueOrNull;
}
public FOptional map(Function f) {
if (valueOrNull == null)
return empty();
else
return of(f.apply(valueOrNull));
}
public static FOptional of(T a) {
return new FOptional(a);
}
public static FOptional empty() {
return new FOptional(null);
}
}
现在变得有趣了。一个FOptional仿函数可以持有价值,但同样也可能是空的。这是一种类型安全的编码方式null。有两种构造方法FOptional-通过提供值或创建 empty()实例。在这两种情况下,就像with一样Identity,FOptional都是不可变的,我们只能与内部的值进行交互。不同之处FOptional在于,如果转换函数f为空,则可能不会将其应用于任何值。这意味着Functors可能未必必须完全封装type的一个值T。它也可以包装任意数量的值,就像List... functor:
import com.google.common.collect.ImmutableList;
class FList implements Functor> {
private final ImmutableList list;
FList(Iterable value) {
this.list = ImmutableList.copyOf(value);
}
@Override
public FList> map(Function f) {
ArrayList result = new ArrayList(list.size());
for (T t : list) {
result.add(f.apply(t));
}
return new FList<>(result);
}
}
API保持不变:您可以在转换中使用Functors-但行为却大不相同。现在,我们对FList中的每个项目进行转换,以声明方式转换整个列表。因此,如果您有客户列表,并且想要他们的街道列表,则非常简单:
import static java.util.Arrays.asList;
FList customers = new FList<>(asList(cust1, cust2));
FList streets = customers
.map(Customer::getAddress)
.map(Address::street);
这不再像说那么简单customers.getAddress().street(),您不能getAddress()在一个客户集合上调用,您必须getAddress()在每个单独的客户上调用,然后将其放回一个集合中。顺便说一句,Groovy发现这种模式是如此普遍,以至于实际上它有一个语法糖:customer*.getAddress()*.street()。该运算符称为散点,实际上是一种map伪装。也许您想知道为什么我要在list内部手动迭代map而不是使用StreamJava 8中的s list.stream().map(f).collect(toList())?这会响吗?如果我java.util.stream.Stream用Java 告诉您也是Functors怎么办?顺便说一句,一个Monads?
现在,您应该看到Functors的第一个好处-它们抽象了内部表示形式,并为各种数据结构提供了一致且易于使用的API。作为最后一个示例,让我介绍类似于的 promise函数Future。Promise“承诺”有一天将提供一个值。它尚未出现,可能是因为产生了一些后台计算,或者我们正在等待外部事件。但是它将在将来的某个时间出现。完成a Promise的机制并不有趣,但是Functors的性质是:
Promise customer = //...
Promise bytes = customer
.map(Customer::getAddress)
.map(Address::street)
.map((String s) -> s.substring(0, 3))
.map(String::toLowerCase)
.map(String::getBytes);
看起来很熟悉?这就是我想说的!
Functors的实现超出了本文的范围,甚至不重要。不用说,我们非常接近从Java 8实现CompletableFuture,并且几乎从RxJava中发现了Observable。但是回到Functors。Promise 尚未持有客户的值。它有望在将来具有这种价值。但是,我们仍然可以像使用FOptional和FList一样映射此类Functors-语法和语义完全相同。行为遵循Functors表示的内容。调用customer.map(Customer :: getAddress)会产生Promise
,这意味着地图是非阻塞的。customer.map()将客户承诺完成。相反,它将返回另一个不同类型的promise。当上游承诺完成后,下游承诺应用传递给map()的函数并将结果传递给下游。突然,我们的Functors使我们能够以非阻塞方式流水线进行异步计算。但是您不必了解或学习-因为Promise是Functors,所以它必须遵循语法和法则。Functors还有许多其他很好的例子,例如以组合方式表示值或错误。但是现在是时候看看Monads了。
从 Functors到Monads
我假设您了解Functors是如何工作的,为什么它们是有用的抽象。但是Functors并不像人们期望的那样普遍。如果您的转换函数(作为map()的一个参数传递)返回Functors实例而不是简单值,会发生什么情况?好吧,Functors也是一个值,因此不会发生任何不良情况。将返回的所有内容放回Functors中,以便所有行为都保持一致。但是,假设您有以下方便的方法来解析字符串:
FOptional tryParse(String s) {
try {
final int i = Integer.parseInt(s);
return FOptional.of(i);
} catch (NumberFormatException e) {
return FOptional.empty();
}
}
例外是会影响类型系统和功能纯度的副作用。在纯函数式语言中,没有例外的地方。毕竟,我们从未听说过在数学课上抛出异常,对吗?错误和非法条件使用值和包装器明确表示。例如,tryParse()接受一个String,而不是简单地返回一个int或在运行时静默引发异常。通过类型系统,我们明确地告诉了tryParse()可能失败,字符串格式错误没有任何异常或错误。此半故障由可选结果表示。有趣的是,Java已经检查了必须声明和处理的异常,因此从某种意义上讲,Java在这方面更纯净,它没有隐藏副作用。但是对于Java中通常不建议检查的异常情况,因此,让我们回到tryParse()。用已经包装在FOptional中的String组成tryParse似乎很有用:
FOptional str = FOptional.of("42");
FOptional> num = str.map(this::tryParse);
这不足为奇。如果tryParse()返回a,int您将得到FOptional num,但是由于map()函数FOptional本身返回,因此将其包装两次成尴尬FOptional>。请仔细查看类型,您必须了解为什么我们在这里得到这种双重包装。除了看上去很恐怖之外,在Functors中放一个Functors会破坏构图和流畅的链接:
FOptional num1 = //...
FOptional> num2 = //...
FOptional date1 = num1.map(t -> new Date(t));
//doesn't compile!
FOptional date2 = num2.map(t -> new Date(t));
在这里,我们尝试FOptional通过转换int为+ Date + 映射内容。有了int -> Date我们可以轻松地从转换Functor为的功能Functor,我们知道它是如何工作的。但是在 num2 情况变得复杂的情况下。什么num2.map()接收输入的不再是一个int,但一个FOoption显然java.util.Date不具备这样的构造。我们通过双重包裹打破了Functors。但是,拥有返回Functors而不是简单值的函数非常普遍(如tryParse()),我们不能简单地忽略这种要求。一种方法是引入一种特殊的无参数join()方法,以“展平”嵌套Functors:
FOptional num3 = num2.join()
它可以工作,但是因为这种模式太普遍了,所以flatMap()引入了名为的特殊方法。flatMap()与以下内容非常相似,map但希望作为参数接收的函数返回Functors-或准确地说是monad:
interface Monad> extends Functor {
M flatMap(Function f);
}
我们简单地得出结论,这flatMap只是一种语法糖,可以使成分更好。但是flatMap方法(通常称为Haskell bind或>>=从Haskell 调用)具有所有不同,因为它允许以纯净的功能样式构成复杂的转换。如果FOptional是monad的实例,则解析突然可以按预期进行:
FOptional num = FOptional.of("42");
FOptional answer = num.flatMap(this::tryParse);
Monads不需要实现map,它可以flatMap()很容易地实现。事实上flatMap,必不可少的运算符可实现全新的转换领域。显然,就像Functors一样,句法顺从性不足以将某类称为Monads,flatMap()操作员必须遵守Monads法则,但是它们非常直观,就像flatMap()与身份的结合一样。后者要求m(x).flatMap(f)与f(x)持有值x和函数的任何monad 相同f。我们不会深入研究monad理论,而让我们关注实际含义。例如,当单声道内部结构不重要时,它们会发光Promise未来将具有价值的monad。您可以从类型系统中猜出Promise在以下程序中将如何运行吗?首先,所有可能花费一些时间才能完成的方法都返回a Promise:
import java.time.DayOfWeek;
Promise loadCustomer(int id) {
//...
}
Promise readBasket(Customer customer) {
//...
}
Promise calculateDiscount(Basket basket, DayOfWeek dow) {
//...
}
现在,我们可以像使用monadic运算符一样阻止所有这些函数的方式编写这些函数:
Promise discount =
loadCustomer(42)
.flatMap(this::readBasket)
.flatMap(b -> calculateDiscount(b, DayOfWeek.FRIDAY));
这变得很有趣。flatMap()必须保留Monads类型,因此所有中间对象均为Promises。这不仅仅是保持类型有序-前一个程序突然完全异步!loadCustomer()返回一个,Promise因此它不会阻塞。readBasket()接受Promise具有(将具有)的任何东西,并应用返回另一个函数的函数Promise,依此类推。基本上,我们建立了一个异步计算管道,其中后台完成一个步骤会自动触发下一步。
探索 flatMap()
有两个Monads并将它们包含的值组合在一起是很常见的。但是,Functors和monad都不允许直接访问其内部,这是不纯的。相反,我们必须谨慎地应用转换,而不能逃脱monad。假设您有两个Monads,并且想要将它们合并:
import java.time.LocalDate;
import java.time.Month;
Monad month = //...
Monad dayOfMonth = //...
Monad date = month.flatMap((Month m) ->
dayOfMonth
.map((int d) -> LocalDate.of(2016, m, d)));
请花点时间研究前面的伪代码。我不使用任何真正的monad实现方式,Promise也不List强调核心概念。我们有两个独立的Monads,一个是type Month,另一个是type Integer。为了构建LocalDate它们,我们必须构建一个嵌套的转换,该转换可以访问两个monad的内部。仔细研究这些类型,尤其要确保您了解为什么我们flatMap在一个地方和另一个地方使用map()。想想如果您也有三分之一的话,将如何构造该代码Monad。应用的两个参数的函数(的这种模式m,并d在我们的例子)是很常见的,在Haskell有一个名为特殊辅助函数liftM2正是在map和之上实现的转换flatMap。在Java伪语法中,它看起来像这样:
Monad liftM2(Monad t1, Monad t2, BiFunction fun) {
return t1.flatMap((T1 tv1) ->
t2.map((T2 tv2) -> fun.apply(tv1, tv2))
);
}
您不必为每个monad都实现此方法,这flatMap()已经足够了,而且,它对所有monad都一致地起作用。liftM2当您考虑如何将其与各种monad结合使用时,它非常有用。例如,listM2(list1, list2, function)将应用于和(笛卡尔积)function上的所有可能的项目对。另一方面,对于可选选项,仅当两个可选选项均为非空时,它将应用功能。更好的是,对于 monad,当两个都完成时,函数将异步执行。这意味着我们只是发明了一个简单的同步机制(在fork-join算法中),该机制包含两个异步步骤。list1list2Promise Promisejoin()
我们可以轻松构建的另一个有用的运算符flatMap()是filter(Predicate),它接受monad中的所有内容,如果不符合某些谓词,则将其完全丢弃。在某种程度上,它类似于map1-to-1映射,而不是1-to-1映射。同样filter(),每个monad具有相同的语义,但取决于我们实际使用的monad,其功能却非常出色。显然,它允许从列表中过滤掉某些元素:
FList vips =
customers.filter(c -> c.totalOrders > 1_000);
但是它也可以很好地工作,例如对于可选项目。在这种情况下,如果可选内容不符合某些条件,我们可以将非空可选转换为空。空的可选部分保持不变。
从Monads列表到Monads列表
源自flatMap()的另一个有用的运算符是sequence()。您只需查看类型签名即可轻松猜测其作用:
Monad> sequence(Iterable> monads)
通常,我们有一堆相同类型的monad,而我们想要一个具有该类型列表的monad。这对您来说可能听起来很抽象,但却非常有用。想象一下,您想通过ID同时从数据库中加载一些客户,因此您loadCustomer(id)多次对不同的ID 使用方法,每次调用都返回Promise。现在,您有一个的列表,Promise但您真正想要的是一个客户列表,例如要在Web浏览器中显示的客户列表。将 sequence()(在RxJava sequence()被称为concat()或merge()根据使用情况)运算符刚建成为:
FList> custPromises = FList
.of(1, 2, 3)
.map(database::loadCustomer);
Promise> customers = custPromises.sequence();
customers.map((FList c) -> ...);
通过调用每个ID,FList我们拥有一个具有代表性的客户ID map(您知道它对FList仿函数有何帮助?)database.loadCustomer(id)。这导致Promises的列表非常不便。sequence()节省了一天的时间,但这再次不仅仅是语法糖。前面的代码是完全非阻塞的。对于不同种类的Monadssequence()还是有意义的,但是在不同的计算环境中。例如,它可以更改FList>为FOptional>。顺便说一句,您可以在之上实现sequence()(就像map())flatMap()。
flatMap()一般而言,这只是冰山一角。尽管源于晦涩的类别理论,但即使在Java等面向对象的编程语言中,monad也被证明是极其有用的抽象。能够组成返回Monads函数的函数非常有用,以至于数十个无关的类遵循Monads行为。
而且,一旦将数据封装在monad中,通常很难显式地将其取出。这种操作不是monad行为的一部分,并且经常导致非惯用语代码。例如,Promise.get()on Promise可以从技术上返回T,但只能通过阻塞返回,而所有基于的运算符flatMap()都是非阻塞的。另一个示例是FOptional.get(),但是可能失败,因为FOptional可能为空。即使FList.get(idx)从列表中偷看特定元素也听起来很尴尬,因为您可以经常替换for循环map()。
我希望您现在了解为什么现在这些Monads如此流行。即使在像Java这样的面向对象的语言中,它们也是非常有用的抽象。
最后,开发这么多年我也总结了一套学习Java的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。
-
linux c 调用 java_Linux平台下Java调用C函数
2021-03-03 15:59:38Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序无疑是一个 福音。使用JNI也是有代价。大家都知道JAVA程序是运行在JVM之上的,可以做到平台无关。但是如果Java程序通过JNI调用了原生的代码... -
Java中的函数(方法)
2020-02-11 14:32:56每个语言里面基本上都有函数,不过现在好多语言里面已经慢慢的修改了它的名称,不叫函数了,而是叫做方法。为了方便起见,下面我还是以“函数”这个名称来说。我们一直在用函数,但是如果突然问你,为什么会有函数的... -
java 目标跟踪_java里面跟踪函数调用可以用什么
2021-03-08 20:23:15展开全部的执32313133353236313431303231363533e78988e69d...当然,我们完全有理由认为会出现适用于更多流行平台的纯固有编译器,但假若没有那些编译器,由于速度的限制,必须有些问题是Java不能解决的。(2) 和C... -
java 通常在函数内部创建对象还是在外部创建对象_100道Java基础面试题
2021-03-09 08:08:471.什么是B/S架构?...HTTP:超文本传输协议FTP:文件传输协议SMPT:简单邮件协议TELNET:远程终端协议POP3:邮件读取协议3.Java都有那些开发平台?JAVA SE:主要用在客户端开发JAVA EE:主要用在web应... -
java事_Java的那些事情
2021-03-04 00:34:22和面向对象的java相比,javaBean的可以重复使用比函数的重复使用更有优势。学过Asp基础,代码都放在页面中了。页面之间的跳转本质就是"按逻辑思路的一路写下去"。JavaEE官方是给出了两种模型jsp+javaBean和jsp+servlet... -
Linux平台下Java调用C函数
2015-06-25 18:37:00Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序无疑是一个 福音。 使用JNI也是有代价。大家都知道JAVA程序是运行在JVM之上的,可以做到平台无关。但是如果Java程序通过JNI调用了原生的代码... -
java递归函数返回值_如何使用在java中具有返回类型void的递归方法?
2021-03-03 13:02:54当那些/那些参数满足某个条件时,你的函数不再调用它自己,并且所有待处理的操作都被解决了。我不完全了解你正在尝试做的,但这里的任务是向后将一个字符串递归函数的一个例子。我使用希望不言自明的名称使用PSEU... -
java是脚本语言吗_脚本语言和c语言,c++,java 那些语言有啥区别?
2021-02-12 10:48:08用一些简单的词代替二进制代码C语言,在汇编语言的基础上,进一步抽像与体系化,开始有各种库、调用方式、函数之类的高级语言特性,同时需要根据不同的CPU等硬件平台特征编译后运行,从C开始的语言都被称之为高级... -
java虚函数的作用_C++中虚函数的作用是什么?它应该怎么用呢?
2021-03-03 10:59:43一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始)简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多... -
Java基础知识之构造函数与构造代码块
2014-01-14 17:06:41我们都知道构造函数是为了创建对象时给对象的一些特性属性进行初始化用的,有了构造函数,我们在创建对象时,构造函数就会运行,对象的一些属性就会被初始化了;构造函数不同,创建对象时就会根据对象的不同进行不同... -
java虚拟机 函数表_【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.3.函数调用与执行...
2021-02-26 21:17:03这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、 硬件、 指令集和操作系统层面上的,而虚拟机的执行引擎则是由自己实现的,因此可以自行制定指令集与执行引擎的结构体系,并且能够执行... -
纯Java中的函数式编程:Functor和Monad示例
2020-02-13 14:22:35绝大多数程序员,特别是那些没有功能编程背景的程序员,都倾向于认为monad是某种神秘的计算机科学概念,因此从理论上讲,它对他们的编程事业没有帮助。这种消极的观点可以归因于数十篇文章或博客文章过于抽象或过于... -
java min 函数的使用方法_【Python】Java程序员学习Python(五)— 函数的定义和使用...
2021-02-28 06:22:03函数的定义和使用放在最前边还是有原因的,现在语言趋于通用,基本类型基本都是那些,重点还是学习对象的使用方法,而最根本的还是方法的使用,因此优先介绍,方法的目的还是重用和封装一、方法的定义方法的定义使用... -
java里怎么通过方法写入函数_下面JAVA程序中,怎么样使用函数或者类的调用,让它简化?...
2021-03-14 12:09:38当然,我们完全有理由认为会出现适用于更多流行平台的纯固有编译器,但假若没有那些编译器,由于速度的限制,必须有些问题是Java不能解决的。(2) 和C++一样,Java也提供了两种类型的注释。(3) 所有东西都必须置入一... -
arrays中copyof_纯Java中的函数式编程:Functor和Monad示例
2020-11-29 09:15:44绝大多数程序员,特别是那些没有功能编程背景的程序员,都倾向于认为monad是某种神秘的计算机科学概念,因此从理论上讲,它对他们的编程事业没有帮助。这种消极的观点可以归因于数十篇文章或博客文章过于抽象或过于... -
那些年,我们追过的java8
2017-08-31 17:47:00我们都知道java与c++,c不同是一个为面向对象而生的语言,面向对象思想贯彻了java发展的大部分时间直到java8,java8的出现为java引进了新的思想(虽然这个思想在别的语言里早就有了)--函数式... -
java源码中那些精妙的代码_JAVA程序员的必杀技:8个经典算法题,过程精妙,代码精炼...
2021-03-18 12:15:26总有一些题,超越了岁月,即便是经过了新框架的层层迭代,它依然散发着令人回味无穷的味道。下面的几个笔试题目,是JAVA面试中经常遇见的,大家一定要牢记于心,可别复习到了到时候又说不出来。我就吃过这种亏,不说... -
java默认无参构造方法(函数)
2013-12-19 17:43:09当没有定义构造方法时每个类里都有一个默认的无参的构造方法,此时该类就只有一个构造方法;而当你显示定义类的构造方法时,那就没有那个默认的构造方法了,该类所以的构造方法就是定义了的那些构造方法;例如:定义... -
epoll监听文件_【原创】万字长文浅析:Epoll与Java Nio的那些事儿
2021-01-03 10:00:23在linux2.5.44首次引入epoll,它设计的目的旨在取代既有的select、poll系统函数,让需要大量操作文件描述符的程序得以发挥更优异的性能(wikipedia example: 旧有的系统函数所花费的时间复杂度为O(n), epoll的时间... -
epoll边缘触发_【原创】万字长文浅析:Epoll与Java Nio的那些事儿
2020-11-28 10:14:24在linux2.5.44首次引入epoll,它设计的目的旨在取代既有的select、poll系统函数,让需要大量操作文件描述符的程序得以发挥更优异的性能(wikipedia example: 旧有的系统函数所花费的时间复杂度为O(n), epoll的时间... -
java调用子系统代码_【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.3.函数调用与执行...
2021-03-13 23:06:10这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、 硬件、 指令集和操作系统层面上的,而虚拟机的执行引擎则是由自己实现的,因此可以自行制定指令集与执行引擎的结构体系,并且能够执行... -
Java性能优化(2):使用私有构造函数强化singleton属性
2015-08-20 09:13:00singleton是指这样的类,它只能...这两种方法都要把构造函数保持为私有的,并且提供一个静态成员,以便允许客户能够访问该类唯一的实例:在第一种方法中,公有静态成员是一个final域: public class Elvis { ... -
【Python】Java程序员学习Python(五)— 函数的定义和使用
2017-06-14 10:41:00函数的定义和使用放在最前边还是有原因的,现在语言趋于通用,基本类型基本都是那些,重点还是学习对象的使用方法,而最根本的还是方法的使用,因此优先介绍,方法的目的还是重用和封装 一、方法的定义 方法的...