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 函数式编程

lambda 函数式编程_Java 8 Lambda表达式的函数式编程– Monads相关推荐

  1. java基于http协议编程_Java中基于HTTP协议网络编程

    java中为我们的网络支持提供了java.net包,能够使我们以编程的方式来访问Web服务功能,这篇博客,就跟大家分享一下,Java中的网络编程的知识,主要是学习下该java.net包下的API. U ...

  2. java函数式编程_Java 函数式编程和 lambda 表达式详解

    作者:DemonsI my.oschina.net/demons99/blog/2223079 为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要 ...

  3. Python lambda表达式与函数式编程

    Python学习笔记(十二):lambda表达式与函数式编程 原创  2013年07月22日 21:57:47 标签:

  4. java里函数式表达式_Java8函数式编程 (一) 数据流和lambda表达式

    JDK 1.8中引入了函数式编程(functional programming,FP),如果您已习惯OOP,一定会感到困惑:什么是函数式编程?这样的编程模式有什么好处? 本文将通过简单的实例令读者对函 ...

  5. 【Java10】lambda表达式(函数式编程),Stream流,File类,字节/字符流,乱码,缓冲/转换/序列化/打印流,Properties

    文章目录 1.lambda表达式标准语法:()->{} 2.lambda表达式简略语法:可推导即可省略 3.lambda表达式原理:lambda效率比匿名内部类高 4.两个函数式接口:Consu ...

  6. Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法...

    1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...

  7. Java 8 Lambda表达式的函数式编程– Monads

    什么是monad ?: monad是一种设计模式概念,用于大多数功能编程语言(如Lisp)或现代世界的Clojure或Scala中. (实际上,我会从scala复制一些内容.)现在,为什么它在Java ...

  8. java8新特性lambda表达式、函数式编程、方法引用和接口默认方法以及内部类访问外部变量

    一提到java是一种什么语言? 大多数人肯定异口同声的说是一门面向对象的语言,这种观点从我们开始学java就已经根深蒂固了,但是学到java8新特性函数式编程的时候,我才知道java并不是纯面向对象的 ...

  9. lambda函数if_Python3中lambda表达式与函数式编程讲解

    今天小编就为大家分享一篇关于Python3中lambda表达式与函数式编程讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧 简单来说,编程中提到的 lam ...

最新文章

  1. 谈谈 Java 中自定义注解及使用场景
  2. Go --- 设计模式(工厂模式)
  3. BAT 招聘岗位 100%都考的知识,你精通了吗?
  4. aspose.words 操作word插入空白页_让 “空白页”无处可逃,消除你的烦恼
  5. 使用 webpack 4 和 Babel 构建 React 应用(2018)
  6. php array in array,浅谈PHP array_search 和 in_array 函数效率问题
  7. jsp:setProperty
  8. github网页链接
  9. 数据库视图作用?什么时候用视图?
  10. Python-Pandas基础
  11. 学校计算机教室用多大线径电缆,施工要用多大的电线电缆?本文教你怎么算
  12. 【文学与历史】浅谈戏说华夏历史
  13. 2.cycloneIII系列FPGA下载模式的配置
  14. 微分方程模型_MIT—微分方程笔记03 一阶线性常微分方程解法
  15. 【mysql】查询过滤器ON,WHERE,HAVING
  16. 使用ADF Faces 之二:数据可视化组件 Thematic Map
  17. 面向对象程序设计——埃拉托色尼筛法(C++)(已更新)
  18. iOS为什么获取不到设备的DeviceToken
  19. DeepStream5.0系列之yolov5使用
  20. 弱网测试工具-qnet

热门文章

  1. vijos1056-图形面积【离散化】
  2. 【模板】KMP算法、fail树
  3. 各种模板(数学数论字符串)
  4. Flowable学习笔记(二、BPMN 2.0-基础 )
  5. 如何快速开发一个 Dubbo 应用
  6. BufferedInputStream与ImageInputStream
  7. Java工程师必备技能
  8. C++描述杭电OJ 2009.求数列的和 ||
  9. ArrayList如何对某个对象的日期属性排序?
  10. 《四世同堂》金句摘抄(二)