函数式编程

Lamda表达式

  • 从JDK1.8开始为了简化使用者进行代码的开发,专门提供有Lamda表达式的支持,利用此操作形式可以实现函数式的编程,对于函数式编程比较著名的语言:haskell、Scala,利用函数式编程可以避免掉面向对象编程之中的一些繁琐的处理问题;
  • 面向对象在其长期发展的过程之中一直有一部分的反对者,这些反对者认为面向对象的设计过于复杂了,并且过于繁琐了,以一个简单的程序为例:
//观察传统开发中的问题
package demo;
interface IMessage {
  public abstract void send(String msg);
}
public class JavaDemo {
  public static void main(String [] args) {
    IMessage msg = new IMessage() {   //匿名内部类
      public void send(String msg) {
        System.out.println(msg);
      }
    };
    msg.send("这是一个消息");
  }
}
  • 在这样一个程序里面,实际上核心的功能只有一行语句“System.out.println(msg);”,但是为了这一行的核心语句依然需要按照完整的面向对象给出的设计结构进行开发,于是这些问题随着技术的不断发展也是越来越突出了;
//使用Lamda表达式实现与之前一样的功能
package demo;
interface IMessage {
  public abstract void send(String str);
}
public class JavaDemo {
  public static void main(String [] args) {
    IMessage msg = (str) -> {
      System.out.println(str);
    };
    msg.send("这是一个消息");
  }
}
  • 现在整个程序代码里面会发现真的只是编写了一行语句,于是利用这种形式就避免了复杂的面向对象结构化的要求;
  • Lamda表达式如果想要使用,有一个重要的实现要求:SAM(Single Abstract Method)只有一个抽象方法,以之前的IMessage接口为例,在这个接口里面发现只是提供有一个send()方法,除此之外没有任何的其他方法定义,所以这样的接口就被称为函数式接口,而只有函数式接口才可以被Lamda表达式所使用;
package demo;
@FunctionalInterface
interface IMessage {
  public abstract void send(String str);
}
public class JavaDemo {
  public static void main(String [] args) {
    IMessage msg = (str) -> {
      System.out.println(str);
    };
    msg.send("这是一个消息");
  }
}
  • 对于Lamda表达式而言,提供有如下几种格式:
    • 方法没有参数:() -> {};
    • 方法有参数:(参数, 参数) -> {};
    • 如果现在只有一行语句返回:(参数, 参数) -> 语句;
//定义没有参数的方法
package demo;
@FunctionalInterface
interface IMessage {
  public abstract void send();
}
public class JavaDemo {
  public static void main(String [] args) {
    IMessage msg = () -> {
      System.out.println("这是一个消息");
    };
    msg.send();
  }
}

//定义有参数的处理形式
package demo;
@FunctionalInterface
interface IMath {
  public abstract int add(int x, int y);
}
public class JavaDemo {
  public static void main(String [] args) {
    IMath math = (x, y) -> {
      return x + y;
    };
    System.out.println(math.add(10, 5));
  }
}

//简化Lamda操作
package demo;
@FunctionalInterface
interface IMath {
  public abstract int add(int x, int y);
}
public class JavaDemo {
  public static void main(String [] args) {
    IMath math = (x, y) -> x + y;;
    System.out.println(math.add(10, 5));
  }
}
  • 利用Lamda表达式的确摆脱了传统面向对象之中关于结构的限制,使得代码更加的简便;

方法引用

  • 引用数据类型最大的特点是可以进行内存的指向处理,在传统开发之中一直所使用的只是对象引用操作,而从JDK1.8之后也提供有方法的引用,即:不同的方法名称可以描述同一个方法,如果要进行 方法的引用在Java里面提供有如下的四种形式:
    • 引用静态方法:类名称 :: static 方法名称;
    • 引用某个实例对象的方法:实例化对象 :: 普通方法;
    • 引用特点类型的方法:特定类 :: 普通方法;
    • 引用构造方法:类名称 :: new;
//引用静态方法
//在String类里面提供有String.valueOf()方法,这个方法就是静态方法
//方法定义:public static String vauleOf(int i),该方法有参数,并且有返回值
package demo;
@FunctionalInterface
//P描述的是参数,R描述的是返回值
interface IFunction<P, R> {
  public abstract R change(P p);
}
public class JavaDemo {
  public static void main(String [] args) {
    IFunction<Integer, String> fun = String :: valueOf;
    String str = fun.change(100);
    System.out.println(str.length());
  }
}
  • 利用方法引用这一概念可以为一个方法定义多个名字,但是要求必须是函数式接口;
//引用实例化对象中的方法
//String类里面有一个转大写的方法:public String toUpperCase()
//这个对象必须在有实例化对象提供的情况下才可以调用
package demo;
@FunctionalInterface
//R描述的是返回值
interface IFunction<R> {
  public abstract R upper();
}
public class JavaDemo {
  public static void main(String [] args) {
    IFunction<String> fun = "www.baidu.com" :: toUpperCase;
    System.out.println(fun.upper());
  }
}
  • 在进行方法应用的时候也可以引用特定类中的一些操作方法,在String类里面提供有一个字符串大小关系的比较:
    • 比较大小:public int compareTo(String anotherString);
    • 这是一个普通方法,如果要引用普通方法,往往需要实例化对象,但是现在不想给出实例化对象,只是想引用这个方法,则就可以使用特定类来进行引用处理;
//引用指定类中的方法
package demo;
@FunctionalInterface
interface IFunction<P> {
  public abstract int compare(P p1, P p2);
}
public class JavaDemo {
  public static void main(String [] args) {
    IFunction<String> fun = String :: compareTo;
    System.out.println(fun.compare("A", "a"));
  }
}
  • 在方法引用里面最具有杀伤力的就是构造方法的引用;
//引用构造方法
package demo;
class Person {
  private String name;
  private int age;
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  public String toString() {
    return "姓名:" + this.name + "、年龄:" + this.age;
  }
}
@FunctionalInterface
interface IFunction<R> {
  public abstract R create(String s, int a);
}
public class JavaDemo {
  public static void main(String [] args) {
    IFunction<Person> fun = Person :: new;
    System.out.println(fun.create("张三", 20));
  }
}
  • 提供方法引用的概念更多的情况下也只是弥补了对于引用的支持功能;

内建函数式接口

  • 在JDK1.8之中提供有Lamda表达式也提供有方法引用,但是你会发现现在如果由开发者自己定义函数式接口,往往都需要使用“@FunctionalInterface”注解来进行大量声明,于是很多情况下如果为了方便则可以直接引用系统中提供的函数式接口;
  • 在系统之中专门提供有一个java.util.function的开发包,里面可以直接使用函数式接口,在这个包下面一共有如下的几个核心接口供使用:
  • 功能型函数式接口:
/**
  接口定义:
  @FunctionalInterface
  public interface Function<T, R> {
    public R apply(T t)
  }
*/
//在String类中有一个方法判断是否以指定的字符串开头:public boolean startsWith(String str);
//接口使用
package demo;
import java.util.function.*;
public class JavaDemo {
  public static void main(String [] args) {
    Function<String, Boolean> fun = "**Hello" :: startsWith;
    System.out.println(fun.apply("**"));
  }
}
  • 消费型函数式接口:只能进行数据的处理操作,而没有任何的返回;
/**
  接口定义:
  @FunctionalInterface
  public interface Consumer<T> {
    public void accept(T t);
  }
*/
//System.out.println();
//接口使用
package demo;
import java.util.function.*;
public class JavaDemo {
  public static void main(String [] args) {
    Consumer<String> con = System.out :: println;
    con.accept("www.baidu.com");
  }
}
  • 供给型函数式接口;
/**
  接口定义:
  @FunctionalInterface
  public interface Supplier<T> {
    public T get();
  }
*/
//在String类中提供有转小写方法,这个方法没有接收参数,但是有返回值:public String toLowerCase();
//接口使用
package demo;
import java.util.function.*;
public class JavaDemo {
  public static void main(String [] args) {
    Supplier<String> sup = "www.BAIDU.com" :: toLowerCase;
    System.out.println(sup.get());
  }
}
  • 断言型函数式接口:进行判断处理;
/**
  接口定义:
  @FunctionalInterface
  public interface Predicate<T> {
    public boolean test(T t)
  }
*/
//在String类有一个equalsIgnoreCase()方法;
//接口使用
package demo;
import java.util.function.*;
public class JavaDemo {
  public static void main(String [] args) {
    Predicate<String> pre = "baidu" :: equalsIgnoreCase;
    System.out.println(pre.test("BAIDU"));
  }
}
  • 开发之中,如果JDK本身提供的函数式接口可以被我们所使用,那么就没有必要进行重新定义;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容