这些博客将帮助您以简单有效的方式学习Java编程和概念。 如果您没有Java的先验知识,那么您将不会遇到任何困难。 如果您是经验丰富的Java开发人员,那么此博客将帮助您重温这些概念。
如果您只是登陆此页面,那么这里是上一个链接:
Java入门指南:第3部分(共4部分)
这些博客将帮助您以简单有效的方式学习Java编程和概念。 如果您之前没有…
medium.com
函数式编程是围绕纯函数的面向对象编程的替代方法。 功能应用程序避免了共享状态,并且比使用面向对象代码的应用程序更简洁和可预测。 在纯数学意义上,纯函数是:
- 完全无状态,没有存储状态或值的变量,没有全局变量
- 没有记忆,也没有记忆或副作用
- 执行并行评估,无需同步,因此比多线程简单得多。
使用这种函数式编程样式可以产生更清晰,可读性更高的OO代码,而带来的问题更少。 那么,我们如何利用Java的函数式编程,又增加了什么呢?
在Java 8中,引入了java.util.Function 接口。 它可以存储一个带有一个参数并返回一个对象的函数。 泛型T是参数的类型,R是您返回的对象的类型。 例如:
公共静态整数计算(Function function,Integer value){
返回function.apply(value);
}
功能接口与单一抽象方法接口。 他们只能展示一种功能。 从Java 8开始,lambda表达式可用于表示功能接口的实例。 Runnable , Comparator和Comparable是功能接口的一些示例。
课堂测试
{
公共静态void main(String args [])
{
新线程(新Runnable()
{
@Override
公共无效run()
{
System.out.println(“ Hello”);
}
})。开始();
}
}
使用lambda表达式到功能接口:
课堂测试
{
公共静态void main(String args [])
{
新线程(()->
{System.out.println(“ Hello lambda”);})。start();
}
}
我们将在稍后详细讨论lambda。
接口始终具有公共静态final字段,从Java 8开始,它们可以具有默认方法。 在Java 8之前,我们必须创建匿名内部类对象或实现这些接口。 默认方法的基本思想是:它是具有默认实现的接口方法,而派生类可以提供更具体的实现。
那么为什么不继续使用Abstract类呢?
抽象类仍然是引入状态或实现核心Object方法(与状态耦合)的一种方法。 接口中的默认方法用于纯行为 。
默认方法的一个示例是Comparator接口中的nullLast方法。
Comparator newComparator = Comparator.nullLast(oldComparator);
随着Lambda表达式的引入。 在现有集合接口中添加对lambda表达式的支持非常困难。 为了增加对Lambda表达式的支持,他们需要重写集合框架的所有接口,该接口在接口中引入了默认方法的概念。
因此,支持功能编程,接口是无状态的,并且可以具有多个静态默认方法。
同步是控制多个线程对共享资源的访问的功能。 同步静态方法在“ Class”类上具有锁,因此当线程进入同步静态方法时,该类本身将被线程监视器锁定,并且其他线程无法在该类上输入任何静态同步方法。 这与实例方法不同,因为多个线程可以为不同的实例同时访问“相同的同步实例方法”。
例如,可以同步可运行类的运行方法,如果使运行方法同步,则在执行运行方法之前,将占用对可运行对象的锁定。
同步与锁定有关。 锁定是关于协调对可变状态的共享访问。 每个对象都应具有一个同步策略,该策略可以确定哪些锁可以保护哪些状态变量。 许多对象使用Java Monitor Pattern作为其同步策略,在Java Monitor Pattern中,对象的状态由其内部锁定来保护。
但是接口并不拥有混合对象的状态。子类可能会覆盖在超类中声明为已同步的方法,从而有效地消除了同步。 这会使您产生错误的信心,即您已对线程安全做了某些事情,并且没有错误消息告诉您您假设错误的同步策略。
我们都讨厌null和null检查。 令人遗憾的是,对于每个参数,我们都必须检查它是否为空。
在Java 8中,引入了java.util.Optional 来处理可能不存在的对象。 它是一个容器对象,可以容纳另一个对象。 通用T是要包含的对象的类型。
整数i = 5;
Optional optionalInteger = Optional.of(i);
Optional类没有任何公共构造函数。 若要创建可选对象 ,请使用Optional.of(object)(如果该对象永远不会为null)或Optional.ofNullable(object)用于可为空的对象。
Lambda表达式是对列表或集合的处理进行编码的可读和表达方式。 这是一种没有声明的方法,即访问修饰符,返回值声明和名称。 它省去了为包含的类声明和编写单独的方法的工作。
Lambda通常是:
- 作为参数传递给高阶函数
- 用于构造需要返回函数的高阶函数的结果
- 作为参数传递(常用)
它们使您可以将功能视为方法参数,或将代码视为数据。
MathOperation加法=(int a,int b)-> a + b; addition(a,b);
流是一种处理数据收集的绝佳新方法。 几乎每个Stream方法都会再次返回Stream,因此开发人员可以继续使用它。 流在遍历时具有过滤,映射和缩小的能力。
流也是不可变的,并且是一次性使用的对象。 一旦遍历了它,就不能再次遍历它。 每次开发人员操纵它时,他们都会创建一个新的Stream。 它支持功能编程的方式是,如果开发人员将数据结构转换为Stream并对其进行处理,则原始数据结构将不会更改。 所以没有记忆又没有副作用!
查看示例以了解各种流的利用:
简单流
公共无效convertObjects(){
Stream objectStream = Stream.of(“ Hello”,“ World”);
}
流数组
公共无效convertStuff(){
String [] array = {“ hello”,“ world”};
Stream arrayStream = Arrays.stream(array);
}
将多个列表连接到流中
公共无效concatList(){
List list1 = Arrays.asList(1、2、3);
List list2 = Arrays.asList(4,5,6);
Stream.of(list1,list2)//流<List >
.flatMap(List :: stream)// Stream
.forEach(System.out :: println); // 1 2 3 4 5 6
}
在流中使用过滤条件
公共无效filterNull(){
Stream.of(2,1,null,3).filter(Objects :: nonNull).map(num-> num)
//没有过滤器,您将获得一个NullPointerExeception
.forEach(System.out :: println);
}
使用收集器将流转换为列表
公共无效的showCollect(){
List 已过滤= Stream.of(0,1,2,3).filter(num-> num).collect(Collectors.toList());
}
执行减少任务
公共无效的showReduceSum(){
int [] array = {23,43,56,97,32};
Arrays.stream(array).reduce((x,y)-> x + y).ifPresent(s-> System.out.println(s));
}
在流中排序数据
公共无效的showSort(){
Stream.of(3,2,4,0).sorted((c1,c2)-> c1 — c2).forEach(System.out :: println); // 0 2 3 4
}
除了正确利用上述所有支持以编写更简洁,可读的功能编程代码外,几乎没有什么小事情,例如避免在函数中使用全局变量,保留最终变量,将函数用作参数以及编写仅取决于其参数的函数。
响应式编程完全与数据流有关。 一个组件发出的数据流将传播到另一组件。 事件总线,单击事件,Twitter提要是类似的异步事件流或数据流。 可观察类和观察者接口是反应式范例的一个很好的例子。 总而言之,反应式编程就是要创建支持以下内容的体系结构:事件驱动或消息驱动(异步),可伸缩,响应式和响应式。
Java 9引入了用于响应式编程的Flow API和通用接口,从而逐步实现了响应式编程。 Flow API涵盖了通信方面(请求,减慢,丢弃,阻止等),使我们能够采用反应式编程,而无需其他库,例如RxJava或Project Reactor。 流具有四个嵌套接口:
- Flow.Processor →如果要转换传入消息并将其进一步传递给下一个订阅服务器,则需要实现Processor接口。 用于将项目从发布者转换为订阅者的链式转换之类的操作。
公共静态接口Processor 扩展了Subscriber ,Publisher {
}
- Flow.Publisher →生成/发布项目和控制信号。
@FunctionalInterface
公共静态接口Publisher {
public void订阅(Subscriber 订阅者);
}
- Flow.Subscriber →消息的接收者需要实现Subscriber 接口,以接收那些消息和信号。
公共静态接口Subscriber {
公共无效onSubscribe(订阅订阅);
public void onNext(T item);
公共无效onError(Throwable throwable);
public void onComplete();
}
- Flow.Subscription →链接发布者和订阅者。
公共静态接口订阅{
公共无效请求(long n);
公共无效cancel();
}
- java.util.concurrent.SubmissionPublisher →因此,Flow API仅具有一个实现Flow.Publisher 的Publisher的实现类,并且它是项的生产者,符合Reactive Streams倡议。
下面的示例将清楚地说明流程和各种接口方法及其用法。
在一个简单的反应流中,我们有一个发布者来发布消息,一个简单的订阅者在消息到达时(在一次到达时)消耗消息。发布者发布了订阅者异步订阅的数据流。
检查示例, SubmissionPublisher类实现Publisher,该Publisher具有一个方法subscription(),供订阅者接收由其发布的事件,而SubmissionPublisher的Submit方法生成该项目。
公共类FlowMain {公共静态void main(String [] args){SubmissionPublisher Publisher = new SubmissionPublisher ();
MySubscriber Subscriber1 =新的MySubscriber (“一个”);
MySubscriber Subscriber2 =新的MySubscriber (“ Two”);
Publisher.subscribe(subscriber1);
Publisher.subscribe(subscriber2);
Publisher.submit(“ Hello”);
Publisher.submit(“ Universe”);尝试{
Thread.sleep(1000);
} catch(InterruptedException e){
e.printStackTrace();
}
Publisher.close();
}
}
让我们讨论订户的接口方法:
- onSubscribe(subcription) →获取新的订阅服务器时,发布服务器将调用此方法。 通常,我们将保存订阅,因为稍后将使用该订阅将信号发送给发布者:请求更多项目,或者取消订阅。 就像我们在这里一样,立即使用它来请求第一项也是很常见的。
- onNext(item) →每当接收到新项目时,将调用此方法。 通常,在这种方法中,我们处理该项目,记录并请求一个新项目。
- onError(throwable) →发布者调用此方法,以通知订阅者某些地方出了问题。 此外,在发布者删除项目时记录消息。
- onComplete() →当发布者没有更多要发送的项目时,将调用此项目,因此订阅已完成。
因此,让我们看一下订户的实现:
公共类MySubscriber 实现Subscriber {私有订阅;
私人字串名称;公共MySubscriber(字串名称){
this.name =名称;
} @Override
公共无效onComplete(){
System.out.println(name +“:Completed”);
} @Override
公共无效onError(Throwable t){
System.out.println(name +“:很奇怪,它是一个错误”);
t.printStackTrace();
} @Override
公共无效onNext(T msg){
System.out.println(name +“:” + msg.toString()+“收到消息”);
subscription.request(1);
} @Override
公共无效onSubscribe(订阅订阅){
System.out.println(name +“:onSubscribe”);
this.subscription =订阅;
subscription.request(1);
}
}
可能会引起问题,我们已经在Java中有了Observable Class和Observer Interace。 那么,为什么要引入它,又有什么不同呢?
主要区别之一是在发布者-订阅者模式中,发布者和订阅者彼此不了解,通信是通过队列或代理进行的。 因此,它们是松散耦合的 。 在观察者模式中,观察者知道所有主题。 Publisher / Subscriber模式主要以异步方式实现,并且可以跨多个应用程序或微服务使用,而观察者模式则非常同步。