Jdk8新特性(六):新增函数式编程

6. 新增函数式编程

6.1. 函数式编程简介

函数式编程(functional programming) 或称 函数程序设计,又称 泛函编程,是一种编程典范,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是λ演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。这是维基百科给出的定义。从这个我们知道函数式编程是相对于指令式编程的一种编程典范,并且对而言具有一些优点。

函数式编程具有以下三点特性:

 函数是"第一等公民"

什么是"第一等公民"?所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,它不仅拥有一切传统函数的使用方式(声明和调用),可以赋值给其他变量(赋值),也可以作为参数,传入另一个函数(传参),或者作为别的函数的返回值(返回)。函数可以作为参数进行传递,意味我们可以把行为"参数化",处理逻辑可以从外部传入,这样程序就可以设计得更灵活。

 没有"副作用"

所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。

 引用透明

引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。这里强调了一点"输入"不变则"输出"也不变,就像数学函数里面的f(x),只要输入的x一样那得到的结果也肯定定是一样的。

6.2. Java8内置核心函数式接口

 Function<T, R>

函数型接口:有入参,有返回值(表示接受一个参数并产生结果的函数)。
方法:R apply(T t);

 Consumer

消费型接口:有入参,无返回值(表示接受单个输入参数并且不返回结果的操作)。
方法:void accept(T t);

 Supplier

供给型接口:⽆入参,有返回值
方法:T get();

 Predicate

断⾔言型接口:有入参,有返回值,返回值类型确定是boolean。
方法:boolean test(T t);


6.3. 函数式编程Function

Function<T, R>接口源码:

package java.util.function;

import java.util.Objects;

/**
 * Represents a function that accepts one argument and produces a result.
* @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
* @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {
   /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
}

调用:

//Function<Float, Float> fun = (Float a)->a * 200;
Function<Float, Float> fun = a->a * 200;
Float res = fun.apply(10f);
System.out.println(res);//2000.0

6.4. 函数式编程BiFunction

BiFunction<T, U, R>接口源码:

package java.util.function;

import java.util.Objects;

/**
 * Represents a function that accepts two arguments and produces a result.
* @param <T> the type of the first argument to the function
 * @param <U> the type of the second argument to the function
 * @param <R> the type of the result of the function
 *
 * @see Function
 * @since 1.8
 */
@FunctionalInterface
public interface BiFunction<T, U, R> {

    /**
     * Applies this function to the given arguments.
     *
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
R apply(T t, U u);

//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
}

调用:

public static void main(String[] args) {
	// 第一种调用
	BiFunction<Double, Double, Double> biFunc = (a, b) -> a + b;
	Double res = biFunc.apply(10d, 20d);
	System.out.println(res);//30.0

	// 第二种调用
	Double op1 = operator(10d, 20d, (a, b) -> a + b);
	System.out.println(op1);//30.0
	Double op2 = operator(10d, 20d, (a, b) -> a / b);
	System.out.println(op2);//0.5
}

public static Double operator(Double a, Double b, BiFunction<Double, Double, Double> bf) {
	return bf.apply(a, b);
}

6.5. 函数式编程Consumer

Consumer只有入参,没有返回值,常用于打印、发送短信等消费动作。

Consumer接口源码:

package java.util.function;

import java.util.Objects;

/**
 * Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, {@code Consumer} is expected to operate via side-effects.
* @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
void accept(T t);

//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
}

应用:

//1.
Consumer<String> consumer = a -> System.out.println(a);
consumer.accept("s");//s

//2.
Consumer<String> consumer2 = a -> {
	System.out.println("=======");
	System.out.println(a);//abc
};
consumer2.accept("abc");

6.6. 函数式编程Supplier

Supplier没有入参,有返回值,常用于无参工厂方法,即工厂设计模式创建对象。

Supplier接口源码:

package java.util.function;

/**
 * Represents a supplier of results.
* @param <T> the type of results supplied by this supplier
* @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     * @return a result
     */
T get();

//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
}

应用(工厂创建对象):

import java.util.function.Supplier;

public class MySupplier {

	public static void main(String[] args) {
		Student stu = createStudent();
		System.out.println(stu.getName());//默认姓名
	}
	
	public static Student createStudent() {
		Supplier<Student> supplier = () -> {
			Student stu = new Student();
			stu.setName("默认姓名");
			return stu;
		};
		return supplier.get();
	}
	
}

class Student {
	
	private String name;
	
	public Student() {
		
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

6.7. 函数式编程Predicate

Predicate断言型接口,有入参,有返回值,返回值类型为boolean类型。

Predicate接口源码:

package java.util.function;

import java.util.Objects;

/**
 * Represents a predicate (boolean-valued function) of one argument.
* @param <T> the type of the input to the predicate
* @since 1.8
 */
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
}

应用(过滤数据):

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class MyPredicate {

	public static void main(String[] args) {
		
		List<String> list = Arrays.asList("apple","banana","orage","strawberry");
		List<String> myList1 = myFilter(list, a -> a.startsWith("b"));
		System.out.println(myList1);//[banana]
		
		List<String> myList2 = myFilter(list, a -> a.startsWith("b") || a.startsWith("s"));
		System.out.println(myList2);//[banana, strawberry]
		
		List<String> myList3 = myFilter(list, a -> {
			if(a.length() <= 5){
				return true;
			}
			return false;
		});
		System.out.println(myList3);//[apple, orage]
		
	}

	public static List<String> myFilter(List<String> list, Predicate<String> predicate) {
		List<String> results = new ArrayList<>();
		for (String str : list) {
			if (predicate.test(str)) {
				results.add(str);
			}
		}
		return results;
	}

}

6.8. 方法与构造函数引用

方法引用 是一种更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类或者实例已存在的方法或构造方法。

语法:
左边是容器(可以是类名,实例名),中间是" :: ",右边是相应的方法名。

 调用静态方法
ClassName::methodName

 调用实例方法
Instance::methodName

 调用构造函数
类名::new

单个参数的构造函数:

Function<入参1, 返回类型> func = 类名::new;
func.apply(入参);

两个参数的构造函数:

BiFunction<入参1,入参2, 返回类型> func = 类名::new;
func.apply(入参1,入参2);

示例:

import java.util.function.BiFunction;
import java.util.function.Function;

public class Jdk8ApplyConstructor {

	public static void main(String[] args) {

		// 调用静态方法
		Function<String, Integer> func1 = Integer::parseInt;
		Integer res1 = func1.apply("12");
		System.out.println(res1);// 12

		// 调用非静态方法
		Function<Integer, String> func2 = "abc"::substring;
		String res2 = func2.apply(1);
		System.out.println(res2);// bc

		// 调用构造函数(单参)
		Function<String, User> fun = User::new;
		User user1 = fun.apply("张三");
		System.out.println(user1.getName());// 张三

		// 调用构造函数(多参)
		BiFunction<String, Integer, User> bFun = User::new;
		User user2 = bFun.apply("王五", 56);
		System.out.println(user2.getName() + "," + user2.getAge());// 王五,56
		
		// 函数引用作方法参数
		String result = sayHello(String::toUpperCase, "abc");
		System.out.println(result);//ABC
		
	}

	public static String sayHello(Function<String, String> func, String param) {
		String res = func.apply(param);
		return res;
	}

}

class User {

	private String name;
	private Integer age;

	public User() {

	}

	public User(String name) {
		this.name = name;
	}

	public User(String name, Integer age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值