《软件架构基础》函数式编程
特点
- 函数作为一等公民
$("button").click(function(){ $("li").each(function(){
alert($(this).text())
});
});
无副作用
- 函数的副作用指的是函数在调用过程中,除了给出了返回值外,还修改了函数外部的状态,比如,函数在调用过程中,修改了某一个全局状态。函数式编程认为,函数的副用作应该被尽量避免。
- 函数做了除了约定之外的其它事情
引用透明
- 引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或“状态”,只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。
申明式的(Declarative)
相对于命令式(imperative)而言,命令式的程序设计喜欢大量使用可变对象和指令
申明式的编程:申明你的用意
public static void imperative(){
int[] iArr={1,3,4,5,6,9,8,7,4,2};
for(int i=0;i<iArr.length;i++){
System.out.println(iArr[i]);
}
}
public static void declarative(){
int[] iArr={1,3,4,5,6,9,8,7,4,2};
Arrays.stream(iArr).forEach(System.out::println);
}
不变模式
static int[] arr={1,3,4,5,6,7,8,9,10};
Arrays.stream(arr).map((x)->x=x+1).forEach(System.out::println);
System.out.println();
Arrays.stream(arr).forEach(System.out::println);
易于并行
- 不变模式天生是并行的
- 引用透明
更少的代码
- 属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用
- 如 (1 + 2) * 3 - 4
subtract(multiply(add(1,2), 3), 4)
- 变形后
add(1,2).multiply(3).subtract(4)
易于阅读的
为什么使用
- 易于并行
- 易于进行数据处理
- 更好的模块化
- 高效的(可工作的软件 重于 详尽的文档)
- 回归简单
java8
@FunctionalInterfacce
lambda表达式
- lambda表达式即匿名函数,它是一段没有函数名的函数体
- 可以作为参数
- lambda中访问外部变量视为final
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
numbers.forEach((Integer value) -> System.out.println(value));
final int num = 2;
Function<Integer, Integer> stringConverter = (from) -> from * num;
System.out.println(stringConverter.apply(3));
方法引用
- 静态方法引用:ClassName::methodName
- 实例上的实例方法引用:instanceReference::methodName
- 超类上的实例方法引用:super::methodName
- 类型上的实例方法引用:ClassName::methodName
- 构造方法引用:Class::new
- 数组构造方法引用:TypeName[]::new
java8函数式编程基础
- Stream 一组待处理的数据
- Predicate 谓词 ,返回是或不是
- Function 将一个对象映射成另一个元素
- BiFunction 将两个对象映射成一个对象
- Consumer 消费者, 放在终结操作,即最后对元素做什么
- BiConsumer消费两个对象,,产生某种行为
- Supplier有返回值的Runable
基于Stream的操作
- forEach
- filter
- map
- reduce
- collect
- peek
操作分类
中间函数与惰性求值
- 中间函数返回一个流,程序中可以多次地、串接地调用流的操作,因为中间操作如映射map、过滤filter函数返回一个流对象。这类操作具有惰性。虽然代码写出了对它们 的调用,但是并没有真正执行。
结尾函数
- 结尾函数返回一个值或void函数产生一个副作用/side effect。
foreach
结尾函数
Arrays.stream(new int[]{1,2,3,5}).forEach(x->System.out.println(x));
filter
接收一个谓词操作,如果谓词返回true,那么当前元素就会被处理,如果谓词返回false,那么元素就会被简单的丢弃
static int[] arr={1,3,4,5,6,7,8,9,10};
public static void main(String[] args) {
Arrays.stream(arr).filter((x)->x%2==0).forEach(System.out::println);
}
map
对元素进行映射
static int[] arr={1,3,4,5,6,7,8,9,10};
public static void main(String[] args) {
Arrays.stream(arr).map((x)->x*x).forEach(System.out::println);
}
reduce
对元素进行汇聚
collect
将元素转为集合
peek
- 监视,调试
Optional
- 一个用于处理NULL的对象
- 用于传递可能为NULL的意图
- 避免NULL打断程序流,使程序流更顺创
Optional的核心API-1
public boolean isPresent()
- 判断当前值是否存在。相当于null检查。
public void ifPresent(Consumer<? super T> consumer)
- 相对于进行null的判断,如果值有意义,则进行consumer操作。
public static <T> Optional<T> of(T value)
- 这是一个工厂方法,构造一个包装了value的Optional。
public static <T> Optional<T> ofNullable(T value)
- 工厂方法,如果value为null,则返回empty对象。否则等同于of()函数。
Optional的核心API-2
public T get()
- 返回Optional内的包装对象。如果为null,则抛出一个异常。
public Optional<T> filter(Predicate<? super T> predicate)
- 判断当前值是否满足predicate条件。如果不满足,则返回一个empty。
public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
- 通过mapper,对当前的值做一个转换。
public T orElse(T other)
- 如果当前值为空,则给一个默认的other作为值。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
- 如果值为空,则抛出一个异常。
stus.stream()
.forEach(
(x)->Arrays.stream(x.getScores())
.average()
.ifPresent(System.out::println)
);
Optional经验分享
- 尽量不要直接使用get(),isPresent()方法
- 尽量依赖map() orElse() 等等
- Optional和异常不兼容
数据流上统计操作
IntStream对数据流提供了便捷的统计操作
average()
count()
sum()
max()
static Comparator<Student> aveScore=(u1,u2)->ave(u1)>ave(u2)?1:-1;
public static double ave(Student stu){
return Arrays.stream(stu.getScores()).average().orElse(0);
}
public static void main(String[] args) {
//取得平均分最高的同学
stus.stream().max(aveScore).ifPresent(System.out::println);
}
min()
Collector接口
对流中的元素进行收集和汇聚操作
元素收集到一个集合中
字符串拼接
统计计算 max min sum
- 创建结果容器
- 将新元素加入容器
- 合并两个容器
- 执行最终转换操作得到结果(可选)
以上是 《软件架构基础》函数式编程 的全部内容, 来源链接: utcz.com/z/513089.html