欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Lambda表达式的基本使用方法

程序员文章站 2022-05-11 08:08:12
...


​ 从JDK1.8开始为了简化使用者进行代码的开发,专门提供有Lambda表达式的支持,利用此操作可以实现函数式的编程,对于函数式编程比较著名的语言有:Haskell、Scala,利用函数式的编程可以避免掉面向对象编程之中一些繁琐的处理问题。

范例:观察传统开发中的问题

package org.demo.innerclass;

interface IMessage {
    public void send(String str);
}

public class JavaDemo {
    public static void main(String[] args) {
        IMessage i = new IMessage() {
            public void send(String str) { 
                System.out.println(str);
            }
        };
        i.send("www.baidu.com");
    }
}

在这样的程序里,实际上核心的功能只有一行语句System.out.println(str),但是为了这一行的核心语句,我们仍然需要按照完整的面向对象给出的结构进行开发。于是这些问题随着技术的发展也是越来越突出了。

范例:使用Lambda表达式实现与之前完全一样的功能

package org.demo.innerclass;

interface IMessage {
    public void send(String str);
}

public class JavaDemo {
    public static void main(String[] args) {
        IMessage i = (str) -> {
            System.out.println(str);
        };
        i.send("www.baidu.com");
    }
}

现在在代码中就十分简洁了,只写了关键语句**System.out.println(str)** ,于是利用这种形式就避免了面向对象复杂的结构化要求。这便是Lambda表达式的基本处理形式。

Lambda表达式如果要想使用,那么必须要有一个重要的实现要求:SAM(Single Abstract Method),只有一个抽象方法,以IMessage接口为例,这个接口里面只是提供有一个send()方法,除此之外没有任何其他方法定义,所以这样的接口就被称为函数式接口,而只有函数式接口才能被Lambda表达式所使用。

范例:错误的定义

package org.demo.innerclass;

interface IMessage {
    public void send(String str);
    public void say();
}

public class JavaDemo {
    public static void main(String[] args) {
        IMessage i = (str) -> {
            System.out.println(str);
        };
        i.send("www.baidu.com");
    }
}

Lambda表达式的基本使用方法

所以很多时候为了明确的标注出你是一个函数式接口,往往会在接口上面增加一行注释@functionalInterface。但是,默认方法和静态方法不会破坏函数式接口的定义。

所以说,之所以在JDK1.8之后提供有默认和静态方法,也都是为函数式开发做准备。

Lambda表达式的几种格式

​ · 方法没有参数: ()->{};

​ ·方法有参数::(参数,参数···)->{};

​ ·如果只有一行语句返回:(参数可有可无)->语句;

下面看几个例子:

使用Lambda表达式(无参)

package org.demo.innerclass;
@FunctionalInterface
interface IMessage {
    public void send();
}

public class JavaDemo {
    public static void main(String[] args) {
        IMessage i = () -> {
            System.out.println("www.baidu.com");
        };
        i.send();
    }
}

使用Lambda表达式(有参)

package org.demo.innerclass;

@FunctionalInterface
interface IMath {
    public int add(int x, int y);
}

public class JavaDemo {
    public static void main(String[] args) {
        IMath math = (t1, t2) -> { // t1,t2是形参名,随便取
            return t1 + t2;
        };
        System.out.println(math.add(20, 30));
    }
}

以上的表达式之中你会发现只有一行语句“ return t1 + t2;”,这时候可以进一步简化。

使用Lambda表达式简化(再度简化Lambda表达式,把return语句也省略)

@FunctionalInterface
interface IMath{
	public int add(int x , int y);
}
public class Demo01 {
		IMath math = (n1,n2)-> n1 + n2;
		System.out.println(math.add(10,20));
	}
	
}

利用Lambda表达式确实可以使得代码更加简便。

方法引用

​ 引用数据类型最大的一个特点是可以进行内存的指向处理,但是传统的开发之中一直所使用的只是对象引用操作,而从JDK1.8之后也提供有方法的引用,即不同的方法名称可以描述同一个方法。如果要进行方法的引用在Java里面提供有如下形式:

引用静态方法

语法格式: 类名称::static方法名称

在String类里面提供有String.valueOf()方法,这方法就属于静态方法。

public static String valueOf(int i) 该方法有参数,还有返回值,参数的类型有很多种。

@FunctionalInterface
//P描述的参数类型,R描述的是返回值
interface IFunction<P,R>{
	public R change(P p);//这里的方法名可以使用中文定义!但是一般不这么用
}
public class Demo01 {
	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();必须有实例化对象才能调用

@FunctionalInterface //函数时接口
//R描述的是返回值
interface IFunction<R>{
	public R upper();
}
public class Demo01 {
	public static void main(String[] args) {
			IFunction<String> fun = "www.baidu.com" :: toUpperCase;
        //“www.baidu.com”相当于实例化对象,然后引用toUpperCase
			System.out.println(fun.upper());
		}
}

在进行方法应用的时候也可以引用特定类中的一些操作方法,比如在String类中提供有一个字符创大小关系的比较:public int compareTo(String anotherString);这是一个普通方法,如果要引用普通方法,往往需要实例化对象,但是如果你现在不想给出对象,只想引用方法,则就可以使用特定类来进行引用处理。

引用特定类型的方法

语法格式: 特定类::普通方法

package org.demo.innerclass;

@FunctionalInterface
//P描述的参数类型,R描述的是返回值
interface IFunction<P>{
    public int compare(P p,P p2);
}

public class JavaDemo {
    public static void main(String[] args) {
        IFunction<String> fun  = String::compareTo;
        //没有实例化对象,直接通过String来引用
        System.out.println(fun.compare("A","a"));
    }
}

引用构造方法

语法格式: 类名称::new

class Person{
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return this.name ;
	}
	public int getAge() {
		return this.age;
	}	
	public String toString() {
		return "姓名:"+ this.name +"、年龄"+ this.age;
	}  
}

@FunctionalInterface //函数时接口
//R描述的是返回值
interface IFunction<R>{
	public R creat(String s, int a );//根据构造方法引入create方法
     //传入两个参数
}

public class Demo01 {
	public static void main(String[] args) {
			IFunction<Person> fun = Person :: new;
			System.out.println(fun.creat("张三",18));
		}
}

内建函数式接口

在JDK1.8之中,提供有Lambda表达式和方法引用,但是你会发现如果由开发者自己定义函数式的接口,往往都需要使用"@FunctionalInterface"来进行大量的声明,于是很多的情况下如果为了方便则可以引用系统中提供的函数式接口。

在系统之中专门提供有一个java.util.functional的开发包,里面可以直接使用函数式接口,在这个包下面一共有如下几个核心的接口供我们使用。

功能型函数式接口

​ ·在String类中有一个方法判断是否以指定的字符串开头:public boolean startsWith(String str);

接口定义: 接口使用:
@FunctionalInterface
public interface Function<T,R>{
public R apply(T t);
}
如下所示
package org.demo.innerclass;

import java.util.function.*;
/*
  @FunctionalInterface
  T是参数类型
  R是返回类型
  public interface Function<T,R>{
  	public R apply(T t);
  }
 */
public class JavaDemo {
    public static void main(String[] args) {
        //这样就不用自己去建函数式接口了
        Function<String,Boolean> fun = "**Hello" :: startsWith;//这个Function是基础接口
        //引用实例化对象的方法
        System.out.println(fun.apply("**"));
    }
}

消费型函数式接口

消费性函数式接口,只能进行数据的处理操作,而没有返回值

​ · 在进行系统输出的时候使用的是:System.out.println();这个操作只是进行数据的输出和消费,而不能返回,这就是消费性接口。

接口定义 接口使用
@FunctionalInterface
public interface Consumer{
public void accept(T t){

}
}
如下
import java.util.function.*;

public class Demo01 {
	public static void main(String[] args) {
		Consumer<String> con = System.out :: println;
		con.accept("www.baidu.com");
	}
}

供给型函数式接口

​ ·在String类中提供有转小写方法,这个方法没有接收参数,但是有返回值 public String toLowerCase();

接口定义 接口使用
@FunctionalInterface
public interface Supplier{
public T get();
}
如下
import java.util.function.*;
public class Demo01 {
	public static void main(String[] args) {
		Supplier <String> sup = "WWW.BAIDU.COM" :: toLowerCase;
		System.out.println(sup.get());
	}
}

断言型函数处理:进行判断处理

接口定义 接口使用
@FunctionalInterface
public interface Predicate{
public boolean test(T t);
}
如下

在String类中有一个cequalsIgnoreCase()方法

    import java.util.function.*;
    public class Demo01 {
        //断言型函数式接口
        public static void main(String[] args) {
            Predicate <String> pre = "baidu" :: equalsIgnoreCase;
            System.out.println(pre.test("BAIDU"));
        }
    }

如果JDK本身提供的函数式接口可以被我们所使用,那么就没必要重新去定义了。