2021-5-4

一、cpu密集型和IO密集型

CPU密集型也是指计算密集型,大部分时间用来做计算逻辑判断等CPU动作的程序称为CPU密集型任务。该类型的任务需要进行大量的计算,主要消耗CPU资源。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。

IO密集型任务指任务需要执行大量的IO操作,涉及到网络、磁盘IO操作,对CPU消耗较少。
配置
1.如果是io密集型的任务,线程池最大线程数配置为任务数量的两倍,大多数web应用都是io密集型
2.如果是cpu密集型的任务,线程池最大线程数配置为任务数量+1即可。

二、函数式接口

函数型接口Function<T,R>
1.接受T类型的参数,返回R类型的结果
2.andThen(Function<T,R>),返回传入的Function<T,R>,如果f1.andThen(f2).apply(str),那么效果就是先执行f1对str的操作,然后f1执行的结果作为f2的入参,再执行f2的操作。
注意:如果使用该方法,f2的入参类型要和f1的出参类型一致
代码如下:

Function<String,String> function= str ->str+"456";
        Function<String,Integer> function1=str->Integer.parseInt(str);
        System.out.println(function.andThen(function1).apply("123"));

断定型接口Predicate< T>
1.接收T类型的参数,返回对它的判断结果
2.negate(),返回调用的Predicate< T>,并对判断后的结果取反
3.and(Predicate< T>),如果p1.and(p2).test(str),那么效果就是先执行p1对str的判断,然后执行p2对str的判断,然后把p1和p2的判断结果进行与操作
4.or(Predicate< T>),如果p1.or(p2).test(str),那么效果就是先执行p1对str的判断,然后执行p2对str的判断,然后把p1和p2的判断结果进行或操作
代码如下:

Predicate<String> predicate=str->str.isEmpty();
        Predicate<String> p=1=str->str.contains("a");
        Predicate<String> p2=str->str.endsWith("c");
        System.out.println(p.and(p1).or(p2).negate().test("abc"));

本例中,p的结果为false,p1的结果为true,与操作结果为false。p2的结果为true,与false进行或操作,结果为true,最后对true取反,返回false。

消费型接口Consumer< T>
1.接受T类型的参数,执行一个对它的操作
2.andThen(Consumer< T>),如果con1.andThen(con2).accept(str),那么效果就是先执行con1对str的操作,再执行con2对str的操作,两个操作互不干扰。
代码如下:

Consumer<String> con=str->System.out.println(str+"789");
Consumer<String> con1=str->System.out.println(Integer.parseInt(str+"456"));
con.andThen(con1).accept("123");

供给型接口Supplier< T>
1.调用其get()方法会返回一个定义好的T类型参数
代码如下:

Supplier<String> s1=()->"cfy";
        System.out.println(s1.get());

三。lambda表达式

1.当一个接口的匿名实现只需要实现一个方法时,就可以将该实现改写为lambda表达式。
2.注意“改写”,这就是lambda表达式的本质,其实它还是接口的匿名实现。
格式
形参列表->重写后的方法体
总结-形参列表格式
1.由于函数式接口基本支持泛型,基于类型推断,形参列表的参数类型可以省略
2.如果形参列表只有一个参数,形参列表的括号可以省略
总结-方法体格式
如果方法体只有一条语句,可以省略大括号,如果这条语句是return语句,那么return关键字也要省略,{}和return必须同时省略

四。stream流

1.stream不保存数据,也不改变源数据,而是返回计算后的数据副本
2.在执行终止操作之前,中间操作不会被执行。执行终止操作后,stream流不能被再次使用。
操作步骤
获取流->过滤、映射等中间操作->遍历等终止操作
实例化
1.通过集合对象得到,比如list.stream() 2.通过数组对象得到
3.通过Stream().of()得到
中间操作-筛选与切片
1.filter(Predicate< T> p),排除流中不满足断定型接口条件的数据
2.distinct(),根据流中元素的hashCode()和equals()方法的结果去掉重复元素
3.limit(long n),限制流中的数据不超过n个
4.skip(long n),丢弃流中前n个元素,如果流中不足n个,则返回空流
中间操作-映射
1.map(Function<T,R> f),根据函数型接口的操作,将流中每个元素改变为操作后的值,即将原值映射为经过操作后的新值。
2.flatMap(Function<T,Stream> f),根据函数型接口的操作,将流中每个元素改变为操作后的值,注意函数型接口的返回值也要是Stream类型,然后将所有元素拆分再连接起来,得到一个新流
flatmap进一步说明:假设Persons类中有属性person集合,现在要将所有persons类中的person集合中的每个person对象放到一个新的List< person>中。如果用map只能做到目前的集合中是[[p1,p2],[p3,p4],[p5,p6]]。但是flatmap会拆分,再连接到一起,得到[p1,p2,p3,p4,p5,p6]
3.map还有几种重载,mapToInt、mapToLong、mapToDouble,这几种重载只能转换得到固定的基本类型数据,而map可以得到自定义类型数据。
中间操作-排序
1.sorted(),对流中的元素使用自然排序,要求元素实现Comparable接口并实现compareTo方法
2.sorted(Comparator c),传入Comparator的匿名实现–支持lambda表达式,对流中的元素使用定制排序
终止操作-匹配与查找
1.allMatch(Predicate< T> p),检查流中的所有元素是否都满足断定型接口p的条件,返回boolean值
2.anyMatch(Predicate< T> p),检查流中是否至少有一个满足断定型接口p的条件,返回boolean值
3.noneMatch(Predicate< T> p),检查流中是否没有一个满足断定型接口p的条件,返回boolean值
4.findFirst(),返回流中的第一个元素
5.findAny(),返回流中的任意一个元素
6.count(),返回流中元素的个数
7.max(Comparator c),根据定制排序的规则,返回流中的最大元素
6.min(Comparator c),根据定制排序的规则,返回流中的最小元素
7.forEach(Consumer c),对流中每个元素执行消费型接口的操作,最常用的就是forEach(System::println),即输出每个元素。
终止操作-归约
1.reduce(BinaryOperator b),顺序地,将流中的每个元素两两结合得到结果,结果会作为下次运算的左值。假设现在有[1,2,3],需要元素相加,写为reduce((a,b)->a+b),那么就是1+2的结果再+3,得6
2.reduce(T t,BinaryOperator b),基本与上一个重载一样,只是第一次运算的左值是T,也即我们可以指定初始值t
3.reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator combiner)

前两种重载的返回值类型会与流中元素的类型一致。但这个重载通过第二个参数可以将运算后的结果转换为指定的类型。第三个参数的作用是,当你获取的是并行流并执行了归约操作,那么会按这个参数指定的表达式合并多个线程计算的结果,如果获取的是顺序流则无所谓。
终止操作-收集
1.collector(Collection c),传入一个Collection集合,将元素放到这个集合中,比如放到list或者set中,然后返回传入的集合。