并发模型整理(二)

整理自《七周七并发模型》
参考:https://www.runoob.com/java/java8-lambda-expressions.html
参考:https://www.runoob.com/java/java8-streams.html

函数式编程

1.SimpleDateFormat是线程不安全的,其内部隐藏可变状态,通过API无法判断。
2.

函数式编程关心数据的映射,命令式编程关心解决问题的步骤。

比如想要达到什么目的,命令式编程需要编写先做什么,后做什么,最后得到结果。而函数式编程不关注这些过程,只需要给定x,得到一定的f(x),就可以了,其实是入参和结果的映射。
3.Java8引入的stream和Lambda表达式使用了函数式编程。

  • Stream
    在java.util.stream包中。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream是一个来自数据源的元素队列并支持聚合操作。Java中的Stream并不会存储元素,而是按需计算

和以前的Collection操作不同, Stream操作还有两个基础的特征:

1.Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
2.内部迭代: 以前对集合遍历都是通过Iterator或者for-each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。访问者模式:不改变原来元素的情况下进行其他操作。

生成流:

stream() //为集合创建串行流。
parallelStream() //为集合创建并行流。

Collection接口有一个stream方法,所以其所有子类都都可以获取对应的Stream对象。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        List<String> list = Arrays.asList("abc", "", "bcc", "efg", "abcd","", "jkl","ajoiew","few");
        System.out.println("最开始" + list);

        //filter,过滤空字符串
        System.out.println("filter " + list.stream().filter(str->!str.isEmpty()).collect(Collectors.toList()));

        //map:映射
        System.out.println("map " + list.stream().map(str->str + "hello").collect(Collectors.toList()));

        //sort:排序
        System.out.println("sort " + list.stream().sorted().collect(Collectors.toList()));

        //forEach:遍历
        list.stream().limit(5).sorted().forEach(System.out::println);

    }
}

输出:
最开始[abc, , bcc, efg, abcd, , jkl, ajoiew, few]
filter [abc, bcc, efg, abcd, jkl, ajoiew, few]
map [abchello, hello, bcchello, efghello, abcdhello, hello, jklhello, ajoiewhello, fewhello]
sort [, , abc, abcd, ajoiew, bcc, efg, few, jkl]

abc
abcd
bcc
efg

使用串行流stream:
1.对于有顺序的源数据(如list,set),使用stream操作之后仍然会按照顺序排(线性操作)。
2.对于非固定顺序的数据源,则不保证其最后处理的顺序。
3.源的固定顺序对性能没有特别影响。
使用并行流parallelStream:
1.使用并行流,不强调顺序的话性能会更好。比如filter,distinct,groupingBy操作,非顺序操作效率更高。
如果数据本身是固定顺序,但并不要求是否按顺序处理,那么可以通过unordered()处理之后再操作,会提高某些有状态的并行操作和结束操作的效率。

关于stream更多内容,见:Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合

  • Lambda
    Lambda 表达式,也可称为闭包:是一个定义在函数内部的函数,闭包使得变量即使脱离了该函数的作用域范围也依然能被访问到。

函数式接口作为Lambda 表达式的目标类型。函数式接口(Functional Interface)是一个有且仅有一个抽象方法声明的接口。任意只包含一个抽象方法的接口,我们都可以用来做成Lambda表达式。比如Collections.sort()中比较参数,就可以不用new Comparator,而改用lambda表达式。

lambda 表达式的语法格式如下:

(parameters) -> expression
或
(parameters) ->{ statements; }

lambda表达式的重要特征:

1.可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
2.可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
3.可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
4.可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

Lambda表达式中的变量作用域:

1.lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
2.lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)。
3.不允许声明一个与局部变量同名的参数或者局部变量。

Clojure分离标识与状态

持久数据结构:数据结构被修改时总是保留其之前的版本。使用共享结构。
Java中CopyOnWriteArrayList就是持久数据结构。
标识(identity)与状态(state):比如汽车有多少油?这是一个标识,一个标识可能对应很多种状态,随着加油和开车消耗汽油,汽车的油量会一直变动。
cas:swap时调用函数计算出结果,结果还未赋值就已被其他线程改掉时,需要重试,取新的入参的值计算,只有当函数计算后,取到的参数值未改变,才赋值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值