01 28Java中级之函数式编程

1 Lamda表达式

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

面向对象在其长期发展的过程之中一直有一部分反对者,这些反对者认为面向对象的设计过于繁杂了,过于繁琐了,以一个最简单程序为例。
范例:观察传统开发中的问题

interface IMessage{
	public abstract void fun();
}

public class JavaDemo{

	public static void main(String[] args){
		IMessage msg = new IMessage(){
			public void fun(){
				System.out.println("hhy");
			}
		};
		msg.fun();
	}
}

在这样的一个程序里面,实际上核心功能只有一行语句,但是我们依然要按完整的面向对象给出的设计结构进行开发。于是这些问题随着技术的发展,也是越来越突出了。
范例:使用Lambda表达式实现与之前完全一样的功能

interface IMessage{
	public abstract void fun();
}

public class JavaDemo{

	public static void main(String[] args){
		IMessage msg = ()->{
				System.out.println("hhy");
		};
		msg.fun();
	}
}

利用这种形式就避免了复杂的面向对象结构化的要求。
Lambda表达式如果要想使用,那么必须满足一个重要的要求:SAM(Single Abstract Method),只有一个抽象方法。只有一个方法的接口称为函数式接口,而只有函数式接口才可以被Lambda表达式所使用。为了明确表明一个接口为函数式接口,需使用Annotation注解(@FunctionalInterface)。
范例:使用函数式接口注解

@FunctionalInterface
interface IMessage{
	public abstract void fun();
}

public class JavaDemo{

	public static void main(String[] args){
		IMessage msg = ()->{
				System.out.println("hhy");
		};
		msg.fun();
	}
}

对于lambda表达式而言,提供有如下几种格式:
(1)方法没有参数:()->{};
(2)方法有参数:(参数,参数)->{};
(3)如果现在只有一行语句返回:(参数,参数)->语句;
范例:定义没有参数的方法。

@FunctionalInterface
interface IMessage{
	public abstract void fun();
}

public class JavaDemo{

	public static void main(String[] args){
		IMessage msg = ()->{
				System.out.println("hhy");
		};
		msg.fun();
	}
}

范例:定义有参数的方法

@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, 3));
	}
}

一行语句可以进一步简化
范例:简化代码

@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, 3));
	}
}

利用Lmbda表达式的确可以摆脱传统面向对象之中关于结构的限制,使得代码更加的简便。

2 方法引用

引用数据类型最大的特点就是可以进行内存的指向处理,但是在传统的开发之中,一直使用的是对象引用操作,而从JDK 1.8之后,也提供有方法的引用。,即:不同的方法名称可以描述同一个方法。如果要进行方法的引用在Java里面提供有四种形式:
(1)引用静态方法:类名称::static方法名称;
(2)引用某个实例对象的方法:实例对象::普通方法;
(3)引用特定类型的方法:特定类::普通方法;
(4)引用构造方法:类名称::new。
范例:引用静态方法
String中静态方法:public static String valueOf​(int i)

@FunctionalInterface
interface IFunction<T, U>{
	public abstract T fun(U n);
}

public class JavaDemo{

	public static void main(String[] args){
		IFunction<String, Integer> f = String::valueOf;
		System.out.println(String.valueOf(12));
		System.out.println(f.fun(12));
	}
}

利用方法引用可以为一个方法定义多个名字,但是要求必须是函数式接口。
范例:引用实例化对象中方法

@FunctionalInterface
interface IFunction<T>{
	public abstract T fun();
}

public class JavaDemo{

	public static void main(String[] args){
		IFunction<String> f = "hhy"::toUpperCase;
		System.out.println(f.fun());
	}
}

在进行方法引用的时候也可以引用特定类中的一些操作方法。
范例:引用指定类中的方法

@FunctionalInterface
interface IFunction<T, U>{
	public abstract T fun(U s1, U s2);
}

public class JavaDemo{

	public static void main(String[] args){
		IFunction<Integer, String> f = String::compareTo;
		System.out.println(f.fun("A", "a"));
	}
}

范例:引用构造方法

@FunctionalInterface
interface IFunction<T>{
	public abstract T fun(String s1, int s2);
}

class Person{
	private String name;
	private int age;

	public Person(){}

	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}

	public String toString(){
		return name + "  " + age;
	}
}

public class JavaDemo{

	public static void main(String[] args){
		IFunction<Person> f = Person::new;
		System.out.println(f.fun("lks", 23));
	}
}

提供方法引用的概念更多的情况下也只是弥补了对于引用的支持功能。

3 内建函数接口

在JDK 1.8之中提供有Lambda表达式也提供有方法引用,但是你会发现现在如果由开发者自己定义函数式接口,往往需要使用“@FunctionalInterface”注解来大量声明,于是很多的情况下如果为了方便可以直接引用系统中提供的函数式接口。

在系统之中专门提供有一个java.util.function的开发包,里面可以直接使用函数式接口,在这个包下面一共有如下几个核心接口:
1、功能型函数式接口
接口定义:

@FunctionalInterface
public interface Function<T,R>{
    public R apply​(T t);
}

接口使用:
String有一个方法:public boolean startsWith(String str);

import java.util.function.*;
public class JavaDemo{

	public static void main(String[] args){
		Function<String, Boolean> fun = "**hello"::startsWith;
		System.out.println(fun.apply("**"));
	}
}

2、消费型函数式接口:只能进行数据处理操作,而没有任何返回。
在进行系统数据输出的时候使用的是:System.out…println();
接口定义:

@FunctionalInterface
public interface Consumer<T>{
    public void accept​(T t);
}

接口使用:

import java.util.function.*;
public class JavaDemo{

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

3、供给型函数式接口
在String类中提供有转小写方法toLowerCase(),这个方法没有接收值,但是有返回值
接口定义:

@FunctionalInterface
public interface Supplier<T>{
    public T get();
}

接口使用:

import java.util.function.*;
public class JavaDemo{

	public static void main(String[] args){
		Supplier<String> sup = "HHY LOVE" :: toLowerCase;
		System.out.println(sup.get());
	}
}

4、断言型函数式接口:进行判断处理
在String类中有一个equalsIngoreCase()方法。
接口定义:

@FunctionalInterface
public interface Predicate<T>{
    public boolean test​(T t);
}

接口使用:

import java.util.function.*;
public class JavaDemo{

	public static void main(String[] args){
		Predicate<String> pre = "hhy" :: equalsIgnoreCase;
		System.out.println(pre.test("HHY"));
	}
}

以后对于实际项目开发之中,如果JDK本身提供的函数式接口可以被我们所使用,那么就没有必要进行重新定义了。

发布了77 篇原创文章 · 获赞 11 · 访问量 2637

猜你喜欢

转载自blog.csdn.net/weixin_43762330/article/details/104564486