lambda 函数式编程_Java 8 Lambda表达式的函数式编程– Monads

lambda 函数式编程

什么是monad ?: monad是一种设计模式概念,用于大多数功能编程语言(如lisp)或现代世界的Clojure或Scala中。 (实际上,我会从scala复制一些内容。)现在,为什么它在Java中变得很重要? 因为java从版本8获得了新的lambda功能。Lambda或闭包是一种功能编程功能。 它使您可以将代码块用作变量,并像这样传递代码块。 我在上一篇文章Java 8中的烹饪-项目Lambda中讨论了Java的“项目Lambda”。 现在,您可以在此处提供的JDK 8预览版中进行尝试。 现在我们可以在Java 8之前做monad吗? 当然,毕竟Java的lambda在语义上只是实现接口的另一种方式(实际上并不是因为编译器知道它的使用位置),而是太多混乱的代码,几乎可以杀死其实用程序。

现在,让我在Java中建立一个用例,就像没有monad一样,而不是向您描述一个抽象的,看似毫无意义的想法。

讨厌的null检查:如果您编写了任何非平凡的(例如Hello-World)java程序,则可能已经做了一些null检查。 它们就像编程必不可少的弊端,您不能没有它们,但是它们会使您的程序杂乱无章。 让我们以带有一组Java数据对象的以下示例为例。 注意,无论如何,我没有使用过反模式的getter或setter。

public static class Userdetails{public Address address;public Name name;}public static class Name{public String firstName;public String lastName;        
}public static class Address{public String houseNumber;public Street street;public City city;}public static class Street{public String name;        
}public static class City{public String name;        
}

现在说您想从UserDetails用户访问街道名称,并且任何属性都可能为null。 没有monad,您可能会编写如下代码。

if(user == null )return null;
else if(user.address == null)return null;
else if(user.address.street == null)return null;
elsereturn user.address.street.name;

理想情况下,它应该是单线的。 我们真正关心的代码周围杂乱无章。 现在让我们看看如何解决该问题。 让我们创建一个代表可选值的Option类。 然后让我们有一个map方法,该方法将在其包装后的值上运行lambda并返回另一个选项。 如果包装的值为null,它将返回一个包含null的Option而不处理lambda,从而避免使用null指针异常。 请注意,map方法实际上需要使用lambda作为参数,但是我们将需要创建一个接口SingleArgExpression来支持该方法。

SingleArgExpression.java

package com.geekyarticles.lambda;public interface SingleArgExpression<P, R> {public R function(P param);
}

Option.java

package com.geekyarticles.javamonads;import com.geekyarticles.lambda.public class Option<T> {T value;public Option(T value){this.value = value;}public <E> Option<E> map(SingleArgExpression<T,E> mapper){if(value == null){return new Option<E>(null);}else{return new Option<E>(mapper.function(value));}}    @Overridepublic boolean equals(Object rhs){if(rhs instanceof Option){Option o = (Option)rhs;if(value == null) return (o.value==null);else{return value.equals(o.value);}}else{return false;}}@Overridepublic int hashCode(){return value==null? 0 : value.hashCode();}public T get(){return value;}}

OptionExample.java

package com.geekyarticles.javamonads.examples;import com.geekyarticles.javamonads.public class OptionExample{public static class Userdetails{public Option<Address> address = new Option<>(null);public Option<Name> name = new Option<>(null);}public static class Name{public Option<String> firstName = new Option<String>(null);public Option<String> lastName = new Option<String>(null);        }public static class Address{public Option<String> houseNumber;public Option<Street> street;public Option<City> city;}public static class Street{public Option<String> name;        }public static class City{public Option<String> name;        }public static void main(String [] args){Option<Userdetails> userOpt =  new Option<>(new Userdetails());//And look how simple it is nowString streetName = userOpt.flatMap(user -> user.address).map(address -> address.street).map(street -> street.name).get();System.out.println(streetName);}}

所以现在,基本上的想法是,只要方法有机会返回null,就返回Option。 将确保该方法的使用者了解该值可以为null,并且还使该使用者隐式地移过null检查,如图所示。 现在,我们从可能必须返回null的所有方法中返回Option,那么映射内的表达式也可能会将Option作为返回类型。 为了避免每次都调用get(),我们可以有一个与map类似的方法flatMap,除了它接受Option用作传递给它的lambda的返回类型。

public <E> Option<E> flatMap(SingleArgExpression<T, Option<E>> mapper){if(value == null){return new Option<E>(null);}return  mapper.function(value);}

我要说的最后一种方法是过滤器。 它将让我们在映射链中放置一个if条件,以便仅当条件为true时才获得一个值。 请注意,这也是null安全的。 在此特定的monad中,filter的用法并不明显,但稍后我们将看到其用法。 以下是一个示例,其中所有可为空的字段均已升级为Option,因此将flatMap用于地图的读取。

Option.java

package com.geekyarticles.javamonads;import com.geekyarticles.lambda.public class Option<T> {T value;public Option(T value){this.value = value;}public <E> Option<E> map(SingleArgExpression<T,E> mapper){if(value == null){return new Option<E>(null);}else{return new Option<E>(mapper.function(value));}}public <E> Option<E> flatMap(SingleArgExpression<T, Option<E>> mapper){if(value == null){return new Option<E>(null);}return  mapper.function(value);}public Option<T> filter(SingleArgExpression<T, Boolean> filter){if(value == null){return new Option<T>(null);}else if(filter.function(value)){return this;}else{return new Option<T>(null);}}@Overridepublic boolean equals(Object rhs){if(rhs instanceof Option){Option o = (Option)rhs;if(value == null) return (o.value==null);else{return value.equals(o.value);}}else{return false;}}@Overridepublic int hashCode(){return value==null? 0 : value.hashCode();}public T get(){return value;}}

OptionExample.java

package com.geekyarticles.javamonads.examples;import com.geekyarticles.javamonads.public class OptionExample{public static class Userdetails{public Option<Address> address = new Option<>(null);public Option<Name> name = new Option<>(null);}public static class Name{public Option<String> firstName = new Option<String>(null);public Option<String> lastName = new Option<String>(null);        }public static class Address{public Option<String> houseNumber;public Option<Street> street;public Option<City> city;}public static class Street{public Option<String> name;        }public static class City{public Option<String> name;        }public static void main(String [] args){//This part is just the setup code for the example to workOption<Userdetails> userOpt =  new Option<>(new Userdetails());userOpt.get().address = new Option<>(new Address());userOpt.get().address.get().street=new Option<>(new Street());userOpt.get().address.get().street.get().name = new Option<>("H. Street");//And look how simple it is nowString streetName = userOpt.flatMap(user -> user.address).flatMap(address -> address.street).flatMap(street -> street.name).get();System.out.println(streetName);}}

集合和Monad: Monad对集合框架也很有用。 尽管最好的方法是让每个收集类自己成为单子,以获得最佳性能(将来可能会成为单子),但目前我们可以将它们包装起来。 这也带来了必须破坏类型检查系统的问题,因为我们事先不知道构建器的通用返回类型。

NoArgExpression.java

package com.geekyarticles.lambda;public interface NoArgExpression<R> {public R function();
}

SingleArgExpression.java

package com.geekyarticles.lambda;public interface SingleArgExpression<P, R> {public R function(P param);
}

CollectionMonad.java

package com.geekyarticles.javamonads;import com.geekyarticles.lambda.
import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;public class CollectionMonad<T> {Collection<T> value;NoArgExpression<Collection> builder;public CollectionMonad(Collection<T> value, NoArgExpression<Collection> builder){this.value = value;this.builder = builder;}public CollectionMonad(T[] elements){this.value = new ArrayList<T>(elements.length);this.value.addAll(Arrays.asList(elements));this.builder = () -> new ArrayList();}@SuppressWarnings("unchecked")public <E> CollectionMonad<E> map(SingleArgExpression<T,E> mapper){Collection<E> result = (Collection<E>)builder.function();        for(T item:value){result.add(mapper.function(item));}    return new CollectionMonad<E>(result, builder);        }//What flatMap does is to flatten out the CollectionMonad returned by the lambda that is provided//It really shrinks a nested loop.@SuppressWarnings("unchecked")public <E> CollectionMonad<E> flatMap(SingleArgExpression<T, CollectionMonad<E>> mapper){Collection<E> result = (Collection<E>)builder.function();        for(T item:value){CollectionMonad<E> forItem = mapper.function(item);for(E e : forItem.get()){result.add(e);}}return new CollectionMonad<E>(result, builder);}@SuppressWarnings("unchecked")public CollectionMonad<T> filter(SingleArgExpression<T, Boolean> filter){Collection<T> result = (Collection<T>)builder.function();        for(T item:value){if(filter.function(item)){result.add(item);}}                return new CollectionMonad<T>(result, builder);            }public Collection<T> get(){return value;}@Overridepublic String toString(){        return value.toString();}}

ListMonadTest.java

package com.geekyarticles.javamonads.examples;import com.geekyarticles.javamonads.
import java.util.public class ListMonadTest {public static void main(String [] args){mapExample();flatMapExample();filterExample();}public static void mapExample(){List<Integer> list = new ArrayList<>();list.add(10);list.add(1);list.add(210);list.add(130);list.add(2);CollectionMonad<Integer> c = new CollectionMonad<>(list, () -> new ArrayList());//Use of mapSystem.out.println(c.map(v -> v.toString()).map(v -> v.charAt(0)));System.out.println();}public static void flatMapExample(){List<Integer> list = new ArrayList<>();list.add(10);list.add(1);list.add(210);list.add(130);list.add(2);CollectionMonad<Integer> c = new CollectionMonad<>(list, () -> new ArrayList());//Use of flatMapSystem.out.println(c.flatMap(v -> new CollectionMonad<Integer>(Collections.nCopies(v,v), () -> new ArrayList())));System.out.println();}public static void filterExample(){List<Integer> list = new ArrayList<>();list.add(10);list.add(1);list.add(210);list.add(130);list.add(2);CollectionMonad<Integer> c = new CollectionMonad<>(list, () -> new ArrayList());//Use of flatMap and filterSystem.out.println(c.flatMap(v -> new CollectionMonad<Integer>(Collections.nCopies(v,v), () -> new ArrayList())).filter(v -> v<=100));System.out.println();}}

乍一看,在这里使用flatmap似乎很麻烦,因为我们需要从lambda创建一个CollectionMonad。 但是,如果考虑使用嵌套的for循环的等效代码,它仍然非常简洁。

流和Monad:在这一点上,您可能正在考虑InputStream,但是我们将讨论比这更笼统的内容。 流基本上是可能是无限的序列。 例如,可以使用公式或实际上是InputStream来创建它。 就像Iterator一样,我们将拥有具有hasNext()和next()方法的流。 实际上,我们将使用Iterator接口,以便可以使用增强的for循环。 但是,我们还将使流变为单声道。 这种情况特别有趣,因为流可能是无限的,因此映射必须返回延迟处理lambda的流。 在我们的示例中,我们将创建具有特定分布的专用随机数生成器。 通常,所有值都是同等概率的。 但是我们可以通过映射来改变它。 让我们看一下示例以更好地理解。

让我们创建一个可以包装任意Iterator的通用Stream。 这样,我们也可以使用它现有的收集框架。

Stream.java

package com.geekyarticles.javamonads;import java.util.Iterator;
import com.geekyarticles.lambda.
import java.util.NoSuchElementException;public class Stream<T> implements Iterable<Option<T>>, Iterator<Option<T>>{//Provides a map on the underlying streamprivate class MapperStream<T,R> extends Stream<R>{private Stream<T> input;private SingleArgExpression<T, R> mapper;public MapperStream(Stream<T> input, SingleArgExpression<T, R> mapper){this.input = input;this.mapper = mapper;}@Overridepublic Option<R> next(){if(!hasNext()){//This is to conform to Iterator documentationthrow new NoSuchElementException();}return input.next().map(mapper);}@Overridepublic boolean hasNext(){return input.hasNext();}}//Provides a flatMap on the underlying streamprivate class FlatMapperStream<T,R> extends Stream<R>{private Stream<T> input;private SingleArgExpression<T, Stream<R>>  mapper;private Option<Stream<R>> currentStream = new Option<>(null);public FlatMapperStream(Stream<T> input, SingleArgExpression<T, Stream<R>> mapper){this.input = input;this.mapper = mapper;}@Overridepublic Option<R> next(){if(hasNext()){return currentStream.flatMap(stream -> stream.next());}else{//This is to conform to Iterator documentationthrow new NoSuchElementException();}}@Overridepublic boolean hasNext(){if(currentStream.map(s -> s.hasNext()) //Now Option(false) and Option(null) should be treated same.equals(new Option<Boolean>(Boolean.TRUE))){return true;}else if(input.hasNext()){currentStream=input.next().map(mapper);return hasNext();}else{return false;}}}//Puts a filter on the underlying streamprivate class FilterStream<T> extends Stream<T>{private Stream<T> input;private SingleArgExpression<T, Boolean> filter;private Option<T> next = new Option<>(null);public FilterStream(Stream<T> input, SingleArgExpression<T, Boolean> filter){this.input = input;this.filter = filter;updateNext();}public boolean hasNext(){return next != null;            }//We always keep one element calculated in advance.private void updateNext(){next = input.hasNext()? input.next(): new Option<T>(null);if(!next.map(filter).equals(new Option<Boolean>(Boolean.TRUE))){if(input.hasNext()){updateNext();                    }else{next = null;                    }}}public Option<T> next(){Option<T> res = next;updateNext();        if(res == null){throw new NoSuchElementException();}    return res;}}protected Iterator<T> input;public Stream(Iterator<T> input){this.input=input;}//Dummy constructor for the use of subclassesprotected Stream(){}@Overridepublic boolean hasNext(){return input.hasNext();}@Overridepublic Option<T> next(){return new Option<>(input.next());}@Overridepublic void remove(){throw new UnsupportedOperationException();}public <R> Stream<R> map(SingleArgExpression<T,R> mapper){return new MapperStream<T, R>(this, mapper);}public <R> Stream<R> flatMap(SingleArgExpression<T, Stream<R>> mapper){return new FlatMapperStream<T, R>(this, mapper);}public Stream<T> filter(SingleArgExpression<T, Boolean> filter){        return new FilterStream<T>(this, filter);}public Iterator<Option<T>> iterator(){return this;}}

StreamExample.java

package com.geekyarticles.javamonads.examples;import com.geekyarticles.javamonads.
import java.util.public class StreamExample{public static void main(String [] args){iteratorExample();infiniteExample();}static void iteratorExample(){System.out.println("iteratorExample");List<Integer> l = new ArrayList<>();l.addAll(Arrays.asList(new Integer[]{1,2,5,20,4,51,7,30,4,5,2,2,1,30,9,2,1,3}));Stream<Integer> stream = new Stream<>(l.iterator());//Stacking up operations//Multiply each element by 10 and only select if less than 70//Then take the remainder after dividing by 13for(Option<Integer> i : stream.map(i -> i*10).filter(i ->  i < 70).map(i -> i%13)){System.out.println(i.get());}System.out.println();}static void infiniteExample(){System.out.println("infiniteExample");Iterator<Double> randomGenerator = new Iterator<Double>(){@Overridepublic Double next(){return Math.random();}@Overridepublic boolean hasNext(){//Infinite iteratorreturn true;}public void remove(){throw new UnsupportedOperationException();}};Stream<Double> randomStream = new Stream<>(randomGenerator);//Now generate a 2 digit integer every second, for ever.for(Option<Integer> val:randomStream.map(v -> (int)(v*100))){System.out.println(val.get());try{Thread.sleep(1000);}catch(InterruptedException ex){ex.printStackTrace();}}}}

这个例子很复杂,所以花一些时间阅读一下。 但是,Stream类仅需要创建一次。 一旦到达,它就可以包装任何Iterator,它将为您免费提供所有monadic功能。

在我的下一篇文章中,我将解释更多单子。

参考: Java 8 Lambda表达式的函数式编程–来自GCG 伙伴 Jbas 合作伙伴 Debasish Ray Chawdhuri的Monad,来自Geeky Articles博客。

翻译自: https://www.javacodegeeks.com/2014/03/functional-programming-with-java-8-lambda-expressions-monads.html

lambda 函数式编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/342288.shtml

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

相关文章

轻松读懂三极管,原来它是这样工作的

一&#xff1a;三极管的介绍 三极管&#xff0c;也就是半导体三极管&#xff0c;是一种控制电流的半导体器件&#xff0c;其作用就是吧微弱信号放大成幅度值较大的电信号&#xff0c;也用作于无触点开关。通常&#xff0c;三极管具有电流放大的作用&#xff0c;它的结构是在一…

飞畅科技-工业以太网的应用现状及前景展望

由于以太网无可争议的优势&#xff0c;将以太网应用于工业自动化领域正成为人们关注的热点。那么&#xff0c;以太网用于工业领域需要要解决哪些问题&#xff0c;其发展前景怎么样呢&#xff1f;接下来我们就来详细的介绍下工业以太网的应用现状及发展前景。感兴趣的朋友就一起…

Modbus RTU通讯协议详解与实例演示

Modbus通讯协议详解 Modbus RTU通讯协议在数据通讯上采用主从应答的方式进行。只能由主机&#xff08;PC&#xff0c;HMI等&#xff09;通过唯一从机地址发起请求&#xff0c;从机&#xff08;终端设备&#xff09;根据主机请求进行响应&#xff0c;即半双工通讯。该协议只允许…

Spring Boot –如何跳过缓存thyemeleaf模板,js,css等以每次绕过重启服务器

Spring Boot自动配置为ThyemeLeaf注册的默认模板解析器是基于类路径的&#xff0c;这意味着它从编译的资源/ target / classes / **加载模板和其他静态资源。 要加载对资源&#xff08;HTML&#xff0c;js&#xff0c;CSS等&#xff09;的更改&#xff0c;我们可以 每次都重新…

「低功耗蓝牙模块」主从一体 蓝牙嗅探-助力智能门锁

一、BLE蓝牙的具体优势&#xff1a; 1、BLE蓝牙模块的待机时间超长 市面上的蓝牙智能锁基本都是使用干电池供电&#xff0c;而BLE低功耗蓝牙模块在广播、传输、待机和睡眠模式下均拥有超低的功耗&#xff0c;比如E104-2G4U04A模块&#xff0c;最大发射功率仅为2.5mW。 2、可以使…

工业以太网的优点有哪些?

以太网支持的传输介质为粗同轴电缆、细同轴电缆、双绞线、光纤等&#xff0c;其最大优点是简单&#xff0c;经济实用&#xff0c;易为人们所掌握&#xff0c;所以深受广大用户欢迎。那么&#xff0c;工业以太网具有哪些优势呢&#xff1f;接下来我们就跟随飞畅科技的小编一起来…

[渝粤教育] 南阳师范学院 英美文学选读 参考 资料

教育 -英美文学选读-章节资料考试资料-南阳师范学院【】 随堂测试 1、【单选题】 is the oldest surviving poem in the English language, and is generally regarded as the national epic of the English people. A、Ecclesiastical History of the English People B、Beowu…

蓝牙模块的5大应用场景

蓝牙模块&#xff0c;作为集成蓝牙无线技术功能的PCBA板&#xff0c;主要用于短距离无线通讯&#xff0c;已经作为物联网无线传输发展的中坚力量。那么蓝牙模块在实际生活中有哪些应用呢&#xff1f;跟亿佰特小编一起来看看吧 一、智慧医疗 当前的健康医疗设备通常是可穿戴产品…

飞畅科技-工业以太网交换机的差异性

通过之前对工业交换机的认知&#xff0c;我们了解到工业以太网交换机采用存储转换的交换方式&#xff0c;同时提高了以太网通信速度&#xff0c;并且内置智能报警设计监控网络运行状况&#xff0c;使得在恶劣危险的工业环境中保证以太网可靠稳定的运行。那么&#xff0c;工业以…

rs485通信OSI模型网络层

网络层处理发生在RS485总线上的设备之间的实际通信。由于RS485接口主要是一种电气规范&#xff0c;因此对话可以到此结束&#xff0c;但由于它支持多点&#xff0c;因此需要在 OSI 模型中解决它。 没有针对网络层寻址的固定规范&#xff0c;但RS485总线必须由主机正确管理以避…

HackTheBox - Medium - Linux - Jupiter

Jupiter Jupiter 是一台中等难度的 Linux 机器&#xff0c;它有一个使用 PostgreSQL 数据库的 Grafana 实例&#xff0c;该数据库在权限上过度扩展&#xff0c;容易受到 SQL 注入的影响&#xff0c;因此容易受到远程代码执行的影响。一旦站稳脚跟&#xff0c;就会注意到一个名…

[渝粤教育] 四川农业大学 管理学原理 参考 资料

教育 -管理学原理-章节资料考试资料-四川农业大学【】 第一章 小测试 1、【单选题】地区经理、项目主管和事业部经理都可以称为&#xff08; &#xff09;。 A、基层管理者 B、非管理者 C、中层管理者 D、非管理雇员 参考资料【 】 2、【单选题】&#xff08; &#xff09;可被…

工业以太网交换机的冗余功能及发展历程介绍

由于工业环境对工业控制网络可靠性能的超高要求&#xff0c;工业以太网的冗余功能应运而生。从快速生成树冗余(RSTP)、环网冗余&#xff08;RapidRing&#xff09;到主干冗余&#xff08;Trunking&#xff09;&#xff0c;都有各自不同的优势和特点。报警、串口使用、主干&…

常用电源符号含义分享

电源符号&#xff0c;你是否还傻傻分不清楚&#xff1f;常用电源符号附上&#xff01; 在电路设计中&#xff0c;总会出现各式各样的电源符号&#xff0c;经常会把人弄懵逼&#xff0c;今天小编整理了二十多个比较常用的电源符号分享给大家&#xff0c;快收藏呀。 1.VBB&#…

activemq网络桥接_ActiveMQ –经纪人网络解释–第5部分

activemq网络桥接在前面的第4部分中&#xff0c;我们已经看到了如何使用网络连接器在队列中平衡远程使用者的负载。 在第5部分中&#xff0c;如果主题上同时存在多个远程持久订阅者&#xff0c;我们将看到相同的配置如何工作。 考虑以下配置…。 图1&#xff1a;经纪人网络–…

模拟量、数字量与开关量的区别

我们常说模拟量、数字量、开关量&#xff0c;从字面意思大概也能明白部分意思&#xff0c;但它们到底是什么&#xff0c;有什么特点和区别呢&#xff1f;今天我们就专门来讲一讲&#xff0c;模拟量、数字量以及开关量的概念和区别。 模拟量 模拟量是指变量在一定范围内连续变…

[渝粤教育] 四川工程职业技术学院 焊条电弧焊技术与操作 参考 资料

教育 -焊条电弧焊技术与操作-章节资料考试资料-四川工程职业技术学院【】 第一周单元作业 第一周单元测验 1、【单选题】焊条电弧焊属于 A、熔焊 B、压焊 C、钎焊 D、爆炸焊 参考资料【 】 2、【单选题】焊条电弧焊的保护方式是 A、气体保护 B、熔渣保护 C、真空保护 D、气渣联…

工业以太网交换机的优势以及注意事项介绍

工业交换机的应用十分广泛&#xff0c;具有电信级性能特征&#xff0c;可耐受严苛的工作环境&#xff0c;在行业应用方面&#xff0c;主要应用于&#xff1a;煤矿安全、轨道交通、工厂自动化、水处理系统、城市安防等。接下来杭州飞畅的小编就来为大家详细介绍下工业以太网交换…

重命名Jakarta EE的Java EE规范

现在该更改规范名称了…… 当我们首先将Java EE规范的API和TCK移到Jakarta EE旗帜下的Eclipse Foundation时 &#xff0c;我们保留了规范的现有名称&#xff0c;并为保存其工件的开源项目采用了占位符名称。 当我们准备从事实际的规范工作&#xff08;涉及实际的规范文档&…

LoRa Basics无线通信技术和应用案例详解

什么是LoRa Basics技术 LoRa Basics就是Semtech Corporation基于LoRaWAN协议推出软件构建模块。LoRa Basics提取常用的LoRaWAN功能&#xff0c;即所有终端设备、网关或基于LoRaWAN解决方案的开发人员都必须实现的功能&#xff0c;并提供一组与规范兼容的、免费的、可提供支持的…