Java基础——函数式编程

函数式编程

  • 将函数作为基本运算单元
  • 函数可以作为变量
  • 函数可以接收函数,可以返回函数
  • 研究函数式编程的理论是λ演算,所以将函数式编程的风格称为Lambda表达式
Arrays.sort(array, (s1,s2)->{	// 参数
	return s1.compareTo(s2);	// 函数体
})
  • 如上所示,可以简化语法(简化单抽象方法实现),类型自动推断
  • 只定义了单个抽象方法的接口可以被标注为@FunctionalInterface,单抽象方法接口也被称为函数式接口
  • 即函数式编程涉及到的接口均是这类函数式接口,例如interface Comparator<>

方法引用

  • 如果某个方法签名(参数类型和返回值)和接口恰好一致,就可以直接传入方法引用
  • 引用格式:类名::方法名
  • 静态方法引用:
    在这里插入图片描述

实现Comparator接口的类的对象的列表或数组可以用Array.sort()方法排序,这里的排序规则引用了自定义的静态方法

  • 实例方法引用:
    在这里插入图片描述

实例方法的调用必须传入一个隐藏的实例变量,例如这里的instance.compareToIgnoreCase(s)
就是说我们实例化的方法都存在一个隐藏的this变量,也是经常使用的

  • 构造方法引用
    在这里插入图片描述

.map()需要传入一个返回值为Person的方法,Person的构造方法返回this,正好符合

  • 可以认为这里所说的接口就是被操作对象(数据)所使用的接口或者类
import java.util.Arrays;

class SortedBy {
	static int name(String s1, String s2) {
		return s1.compareTo(s2);
	}
	static int nameIgnoreCase(String s1, String s2) {
		return s1.toLowerCase().compareTo(s2.toLowerCase());
	}
	static int length(String s1, String s2) {
		int n1 = s1.length();
		int n2 = s2.length();
		if (n1 == n2) {
			return s1.compareTo(s2);
		}
		return n1 < n2 ? -1 : 1;
	}
}

public class LambdaSort {
	public static void main(String[] args) throws Exception {
		String[] array = "Java Apple lambda functional OOP".split(" ");
		// 静态方法引用,方法签名正好符合Comparator接口
		Arrays.sort(array, SortedBy::name);		// SortedBy::nameIgnoreCase
		System.out.println(Arrays.toString(array));
	}
}

Stream

  • Java8引入的API,定义在java.util.stream
  • 对比:
    在这里插入图片描述
    在这里插入图片描述
  • 特点
  1. 可以存储有限个或无限个元素,这里的存储可以存在内存中或者实时计算产生
  2. 可以转换为另一个stream
  3. 惰性计算(通常发生在最后结果的获取)
    在这里插入图片描述
  • 创建stream
  1. 通过指定元素/现有数组/现有Collection创建
// 指定元素:Stream.of(...)
// 现有数组:
import java.util.Arrays;

public class StreamBasic {
	public static void main(String[] args) throws Exception {
		String[] array = "JDK Stream API supports functional-style operations".split(" ");
		// array -> stream:
		long n = Arrays.stream(array)	// 创建固定大小的stream
				// .filter((s) -> s.equals(s.toUpperCase()))	// 纯大写字符串
				.count();
		System.out.println("How many words? " + n);
	}
}
// 现有Collection:collection.stream()
  1. 通过传入Supplier创建无限序列
Stream<T> s = Stream.generate(Supplier<T> s);	// 通过传入supplier对象不断产生内容
// 这种对象保存的是算法
  1. 通过其他类的相关方法创建(Stream API)
    在这里插入图片描述

由于不能使用Stream<int> s这样的方式创建基本类型的stream,java提供了以下类型:
在这里插入图片描述

Stream.map

  • 将一个stream转换为另一个,两个是stream按照映射函数一一对应
import java.util.Arrays;
import java.util.stream.Stream;

public class StreamMapSample {
	public static void main(String[] args) throws Exception {
		String[] array = "Stream API supports functional-style operations".split(" ");
		Stream<String> stream = Arrays.stream(array);
		stream.map(String::toUpperCase).forEach(System.out::println);// 方法引用作为映射函数
	}
}
import java.util.Arrays;
import java.util.stream.Stream;

class Person {
	String name;
	char gender;
	public Person(String name, char gender) {
		this.name = name;
		this.gender = gender;
	}
	public String toString() {
		return "Person(" + name + ", " + gender + ")";
	}
}

public class StreamMapSample2 {
	public static void main(String[] args) throws Exception {
		String[] inputs = { "Bob,M", "Alice,F", "Time,M", "Lily,F" };
		Stream<String> names = Arrays.stream(inputs);
		Stream<Person> persons = names.map((s) -> {// 可以将一种元素类型转化为另一种元素类型
			int n = s.indexOf(',');
			String name = s.substring(0, n);
			char gender = s.charAt(n + 1);
			return new Person(name, gender);
		});
		persons.forEach(System.out::println);
	}
}

Stream.fliter

  • 排除不满足条件的元素
import java.util.function.Supplier;
import java.util.stream.Stream;

class NaturalSupplier implements Supplier<Long> {
	long x = 0;

	public Long get() {	// 默认调用get方法
		x++;
		return x;
	}

}

public class StreamFilterSample {
	public static void main(String[] args) throws Exception {
		Stream<Long> natural = Stream.generate(new NaturalSupplier());// 传入算法,得到无限序列
		Stream<Long> odd = natural.filter((n) -> n % 2 == 1);
		odd.limit(20).forEach(System.out::println);	// 限制只产生20个
	}
}

Stream.reduce

  • stream的聚合方法,把一个stream的所有元素聚合成一个结果
    在这里插入图片描述
  • acc和n分别被前两个元素初始化
  • acc是上一次计算的结果,n是stream中下一个值
    在这里插入图片描述
import java.util.stream.Stream;

public class StreamReduceSample {
	public static void main(String[] args) throws Exception {
		int r = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce((acc, x) -> acc * x).get();
		System.out.println(r);
	}
}
import java.util.Arrays;

public class StreamReduceSample2 {
	public static void main(String[] args) throws Exception {
		String[] array = "Stream API supports functional-style operations".split(" ");
		String result = Arrays.stream(array).map(String::toLowerCase).reduce((acc, s) -> acc + " ~ " + s).get();
		System.out.println(result);
	}
}
  • reduce方法会立刻对stream进行计算

其他常用操作

在这里插入图片描述

结语

对java基础的学习到这里告一段落,可以体会到Java生态的庞大,我们可以借助它轻松地完成很多工作,Java解决问题的思路有很多值得学习的地方,需要在实践中多加积累!
后面会学习记录一些Java较深层次的原理,路漫漫其修远兮…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章