复习
1.线程池
a.创建
ExecutorService service = Executors.newFixedThreadPool(int 个数);
b.使用
service.submit(Runnable r);
Future<T> future = service.submit(Callable<T> c);
T result = future.get();//可能会阻塞,直到线程任务执行完毕真的返回结果
2.死锁(了解)
a.多把锁
b.多个线程
c.锁的嵌套(反向嵌套)
3.线程六种状态
NEW-->RUNNABLE
BLOCKED-->RUNNABLE
RUNNABLE-->TERMINATED
TIMED_WAITING-->RUNNABLE
WAITING--BLOCKED-->RUNNABLE
4.Timer
四种任务
public void schedule(TimerTask task,long delay)
public void schedule(TimerTask task,long delay,long period);
public void schedule(TimerTask task,Date date)
public void schedule(TimerTask task,Date firstDate,long period);
今日:
2020年3月19日 10:10:10
Date d = new Date(120,2,19,10,10,10);
今日内容
- Lambda表达式(函数式编程)
- Stream流(Lambda的实际运行之一)
Lambda表达式
函数式编程思想
函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”
面向对象过分强调"必须通过对象的形式来做事情". 面向对象注重形式
函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。做什么,而不是怎么做.
冗余的Runnable代码
在new Thread(new Runnable(){run...})
中, 自己定义的和Runnable一样内容的接口也无法作为参数传递, 因为Thread要求的参数只能是Runnable类型.
本着“一切皆对象”的思想,这种做法是无可厚非的:首先创建一个 Runnable 接口的匿名内部类对象来指定任务内
容,再将其交给一个线程来启动。
Lambda的标准格式
- 标准格式:
Lambda省去面向对象的条条框框,格式由3个部分组成:
1.一些参数
2.一个箭头
3.一段代码
-Lambda表达式的标准格式为:
(参数类型 参数名称) -> { 代码语句;renturn 返回值; }
- 格式说明
1.(参数列表)小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
2.-> 是新引入的语法格式,代表指向动作,表示拿着前边的参数去做什么事情。
3.{}大括号内的语法与传统方法体要求基本一致,有返回值, 就return 返回值, 无返回值, 可以省略return。
Runnable 接口的匿名内部类写法可以通过更简单的Lambda表达式达到等效
public class Demo02LambdaRunnable {
public static void main(String[] args) {
new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
}
}
Lambda的参数和返回值
Lambda的省略格式
- 参数类型可以省略
- 如果参数只有一个这种情况下,那么小括号可以省略
- 如果{ }中的代码可以写成一句代码,那么 { },return关键字和分号可以同时省略(不能只能省略某个,必须三个同时省略).
- 省略格式代码如下
Arrays.sort(dogs, ((o1, o2) -> o2.getAge() - o1.getAge()));
Lambda的前提条件
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。 无论是JDK内置的 Runnable 、Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
- 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能
使用Lambda作为该接口的实例。
tips:备注:有且仅有一个抽象方法的接口,称为“函数式接口”。
Stream
传统的集合操作
public class Demo01ForEach {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
for (String name : list) {
System.out.println(name);
}
}
}
循环遍历的弊端
for循环的语法就是“怎么做”
for循环的循环体才是“做什么”
Lambda让我们可以更加专注于做什么(What),而不是怎么做(How)。
为了解决面向对象语法复杂形式, 引入新的技术: Stream 流式思想
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。循环是做事情的方式,而不是目的。另一方面,使用线性循环就意味着只能遍历一次。如果希望再次遍历,只能再使用另一个循环从头开始。
传统集合遍历和Stream流 写法比较
传统写法:
public class TestDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
ArrayList<String> zhangs = new ArrayList<>();
for (String name : list) {
if (name.startsWith("张")) {
zhangs.add(name);
}
}
ArrayList<String> three = new ArrayList<>();
for (String name : zhangs) {
if (name.length() == 3) {
three.add(name);
}
}
for (String name : three) {
System.out.println(name);
}
}
}
使用Steam流
public class Demo03StreamFilter {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(System.out::println);
}
}
获取流、过滤姓张、过滤长度为3、逐一打印
流式思想

这张图中展示了过滤、映射、跳过、计数等多步操作,这是一种集合元素的处理方案,而方案就是一种“函数模型”。图中的每一个方框都是个“流”,调用指定的方法,可以从一个流模型转换为另一个流模型。而最右侧的数字3是最终结果。
tips:“Stream流”其实是一个集合元素的函数模型,它并不是集合,也不是数据结构,其本身并不存储任何元素(或其地址值)。
获取流方式
要想获取流, 首先要不就是个集合, 要不就是个数组
-
Collection (单列) 集合获取流
Stream<E> s = 集合对象.stream();
-
Map (双列) 集合获取流
java.util.Map 接口不是 Collection 的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流需要分key、value或entry等情况(先获取键或者值的set集合,再用单列集合的获取流方法):
Stream<E> keys =map.keySet().stream()
Stream<E> valueStream =map.values().stream();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
-
数组获取流
Stream<String> stream = Stream.of(array);
获取流的代码演示
public static void main(String[] args) {
//单列集合
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "544");
Stream<String> s1 = list.stream();
//双列集合
HashMap<String, Integer> map = new HashMap<>();
map.put("1",22);
map.put("2",22);
map.put("3",22);
Stream<String> s2 = map.keySet().stream();
Stream<Integer> s3 = map.values().stream();
Stream<Map.Entry<String, Integer>> s4 = map.entrySet().stream();
//数组
Integer[] nums = {10, 20, 30, 40};
Stream<Integer> nums1 = Stream.of(nums);
}
Stream流的常用方法
- 逐一处理方法:forEach()
public static void main(String[] args) {
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
/* s1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//lambda使用
//s1.forEach((String s) -> {System.out.println(s);});
//lambda简略格式
s1.forEach(s -> System.out.println(s));
}
- 统计个数:count()方法
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
//count统计个数方法
long count = s1.count();
System.out.println(count);
- 过滤方法:filter()方法
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
//filte 过滤方法传统写法
/* Stream<String> stringStream = s1.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
//只想要长度大于3的字符串
if (s.length() > 3) {
return true;
}
return false;
}
});
System.out.println(stringStream.count());*/
//filter的Lambda形式
Stream<String> stringStream1 = s1.filter(s -> s.length() > 3);
System.out.println(stringStream1.count());
- 取前几个:limit()方法
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
//limit 取前几个方法
Stream<String> limit = s1.limit(3);
limit.forEach(s -> System.out.println(s));
- 跳过前几个: skip()方法
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
//skip 跳过前几个方法
Stream<String> skip = s1.skip(2);
skip.forEach(s -> System.out.println(s));
- 映射: map()方法
如果需要将流中的元素映射到另一个流中,可以使用 map 方法。方法签名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
//映射 map()方法
Stream<Integer> mapStream = s1.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});
Stream<Integer> mapStream1 = s1.map((s) -> s.length());
mapStream.forEach(s -> System.out.println(s));
- 静态方法合并流: concat()
如果是两个以上合并,多次进行两两合并即可
就算不是一种类型, 也可以使用泛型为其父类接收
Stream<String> s1 = Stream.of("java", "php", "C", "Go");
Stream<String> s2 = Stream.of("A", "B", "C", "D");
//合并流方法 concat
Stream<String> concatStream = Stream.concat(s1, s2);
concatStream.forEach(s -> System.out.print(s+" "));
总结Stream流分为两类
- 函数拼接方法: 由于这种方法返回的是流对象,可以进行链式编程
调用该方法后返回的还是一个流对象
filter,limit,skip,map,concat - 终结方法:由于这类方法返回值不是流, 该流就关闭了, 无法在进行调用其他方法
调用该方法后,返回值不是流或者无返回值
forEach,count
收集Stream流的结果
- 收集到集合中
调用流的 collect()方法
```java
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
}
- 收集到数组中
调用流的toArray()方法
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
Object[] objArray = stream.toArray();
}
collector 和 collectors
Collector是专门用来作为Stream的collect方法的参数的。而Collectors是作为生产具体Collector的工具类。
注意
一个流只能收集一次
如果收集到数组中,默认收集到Object数组
Stream流的代码演示
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
// 1. 第一个队伍只要名字为3个字的成员姓名;
// 2. 第一个队伍筛选之后只要前3个人;
Stream<String> s1 = one.stream().filter(s -> s.length() == 3).limit(3);
// 3. 第二个队伍只要姓张的成员姓名;
// 4. 第二个队伍筛选之后不要前2个人;
Stream<String> s2 = two.stream().filter(s -> s.startsWith("张")).skip(2);
// 5. 将两个队伍合并为一个队伍;
Stream<String> ss = Stream.concat(s1, s2);
// 6. 根据姓名创建 Person 对象;
Stream<Person> ps = ss.map(s -> new Person(s));
// 7. 打印整个队伍的Person对象信息。
ps.forEach(person -> System.out.println(person));
}
今日小结
-
Stream流处理方式
Stream.of(1,2,3,4,5).filter().map().forEach()
如上代码, 是先有元素1 进入filter, 再进入map,再进入forEach结束后,再有元素2, 依次进入 -
Lambda配合函数式接口使用小结, 只要判断函数式接口的参数和返回值能对上, 就可以使用
Supplier 提供器 () -> 有返回值, 无参
Consumer 消费器 (x) -> void 有一个参数, 没有返回值
Function 转换器 (x) ->y , 有一个参数 ,有返回值
Predicate 判断器 (x) -> boolean, 有一个参数, 返回boolean值
Comparator 比较器 (a,b)->int , 有两个参数, 返回一个 int值,如果a<b, 返回负数
1.Lambda【重点】
标准格式: (参数列表)->{方法体;return 返回值;}
省略格式:
a.参数的类型可省略
b.如果只有一个参数,小括号可省略
c.如果{}中只有一句代码,那么{}和;和return关键字可以同时省略
2.Stream流 【重点】
a。集合或者数组获取流的方法
Stream<E> s = 集合.stream();//单列集合
Stream<E> s = Stream.of(数组/可变参数); //数组获取流
b.调用流的各种方式
filter limit skip map count foreach concat
3.综合案例(处理两个集合数据) 【重点多练几遍】
网友评论