day14【Lambda表达式、Stream流】
反馈和复习
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);
今日内容
JDK8的新特性
1.Lambda表达式(函数式编程)
2.Stream流(Lambda的实际运行之一)
今日的内容我们当做加薪的技术去学
第一章 Lambda表达式
1.1 函数式编程的思想
函数式编程思想: 以一种尽量简单的格式,简化面向对象中复杂的格式,
面向对象强调是以何种形式去做,
而函数式编程思想强调是拿什么东西做什么事情,而不强调以何种形式去做!
1.2 冗余的Runnable代码
public class TestRunnableDemo {
public static void main(String[] args) {
//1.我要使用实现的方式 创建一个线程对象
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了...");
}
}).start();
//分析: 传统Runnable实现方式的冗余代码
//a.我们为了避免创建一个新类,不得不(被逼的)去搞一个匿名内部类
//b.为了迎合面向对象的语法,我们只能(被逼的)使用Runnable的实现类
//c.重写时方法必须(被逼的)和接口中一模一样
//d.似乎我们真正需要的其实就是任务代码(心甘情愿写的)
}
}
1.3 函数式编程Lambda的体验
//体验一下Lambda表达式(函数式编程)优雅的写法
new Thread(()->{System.out.println("执行了...");}).start();
1.4 Lambda标准格式介绍【重点】
Lambda的标准格式:
(参数列表)->{方法体;return 返回值;}
详情介绍:
(参数列表) 相当于方法的参数,如果没有参数,那么只写小括号即可(小括号不能省略)
->: 固定用法,代码拿着前面的参数,去做什么事情
{}: 大括号中先写计算过程,如果有返回值return 返回值;,如果没有返回值return语句可以省略
//面向对象的格式
new Thread(new Runnable() {
public void run() {
System.out.println("执行了...");
}
}).start();
//Lambda的格式
new Thread(()->{System.out.println("执行了...");}).start();
1.5 Lambda的参数和返回值【重点】
public static void arraySort1(){
//1.数组
Integer[] nums = {4,5,61,7,8,9,34,56,345};
//2.对数组排序(默认升序)
//Arrays.sort(nums);
// Arrays.sort(nums, new Comparator<Integer>() {
// @Override
// public int compare(Integer o1, Integer o2) {
// //降序
// return o2-o1;
// }
// });
//使用Lambda表达式修改上面冗余的代码
Arrays.sort(nums,(Integer o1, Integer o2)->{return o2-o1;});
//3.输出
System.out.println(Arrays.toString(nums));
}
public static void main(String[] args) {
//1.数组
Dog[] dogs = new Dog[4];
dogs[0] = new Dog(4,"jack",4);
dogs[1] = new Dog(3,"mary",5);
dogs[2] = new Dog(2,"ady",6);
dogs[3] = new Dog(5,"hanmeimei",3);
//2.排序
// Arrays.sort(dogs, new Comparator<Dog>() {
// @Override
// public int compare(Dog o1, Dog o2) {
// //按照狗的年龄降序
// return o2.age-o1.age;
// }
// });
//使用Lambda表达式修改上面冗余的代码
Arrays.sort(dogs,(Dog o1, Dog o2)->{return o2.age-o1.age;});
//3.打印
for (Dog dog : dogs) {
System.out.println(dog);
}
}
1.6 Lambda的省略格式【重点】
a.参数类型可以省略
b.如果参数只有一个,那么小括号可以省略
c.如果{}中的代码可以写成一句代码.那么{},return关键字和分号可以同时省略(不能省略某个)
//体验一下Lambda表达式(函数式编程)优雅的写法
new Thread(()->{System.out.println("执行了...");}).start();
//省略格式
new Thread(()->System.out.println("执行了...")).start();
//使用Lambda表达式修改上面冗余的代码
Arrays.sort(nums,(Integer o1, Integer o2)->{return o2-o1;});
//省略格式
Arrays.sort(nums,(o1,o2)-> o2-o1);
//使用Lambda表达式修改上面冗余的代码
Arrays.sort(dogs,(Dog o1, Dog o2)->{return o2.age-o1.age;});
//省略格式
Arrays.sort(dogs,(o1,o2)->o2.age-o1.age);
1.7 强烈注意:Lambda的使用前提
a.Lambda只能用于替换 有且仅有一个抽象方法的接口的匿名内部类对象,这种接口称为函数式接口
b.Lambda具有上下文推断的功能, 所以我们才会出现Lambda的省略格式
第二章 Stream流
2.1 引入:传统的集合操作
public class TestDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//1. 首先筛选所有姓张的人;
ArrayList<String> zhangs = new ArrayList<String>();
for (String name : list) {
if (name.startsWith("张")){
zhangs.add(name);
}
}
//2. 然后筛选名字有三个字的人;
ArrayList<String> threes = new ArrayList<String>();
for (String zhang : zhangs) {
if (zhang.length() == 3) {
threes.add(zhang);
}
}
//3. 最后进行对结果进行打印输出。
for (String three : threes) {
System.out.println(three);
}
}
}
2.2 循环遍历的弊端分析
Lambda注重于做什么,传统的面向对象注重于怎么做??
for (String three : threes) { //这就是传统的面向对象注重怎么做,就是形式
System.out.println(three);//这里才是我们注重做什么
}
为了解决面向对象语法复杂形式,我们引入一种新的技术:Stream 流式思想
2.3 体验Stream的优雅写法
//4.体验一下Stream流的优雅代码
list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(s-> System.out.println(s));
2.4 流式思想的概述
2.5 两种获取流的方式【重点】
a.Collection集合获取流
Stream<E> s = 集合对象.stream();
b.Map集合不能直接获取流,但是可以间接获取流
map.keySet().stream(); 获取map的键流
map.values().stream(); 获取map的值流
map.entrySet().stream(); 获取Map的键值对流
c.数组获取流
Stream<数据中元素的类型> s = Stream.of(数据类型... 变量名);
public class StreamDemo01 {
public static void main(String[] args) {
//获取各种容器的流
//1.单列集合
ArrayList<String> arr = new ArrayList<String>();
//....添加数据
Stream<String> s1 = arr.stream();
//2.双列集合
HashMap<String, Integer> map = new HashMap<String, Integer>();
Stream<String> keyStream = map.keySet().stream(); //键流
Stream<Integer> valueStream = map.values().stream();//值流
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();//键值对流
//3.数组
Integer[] nums = {10,20,30,40};
Stream<Integer> s2 = Stream.of(nums);
Stream<Integer> s3 = Stream.of(11,22,33,44);
}
}
2.6 Stream流中的常用方法【重点】
-
逐个处理:forEach(代码演示)
//1.获取到一个流 Stream<String> s1 = Stream.of("jack", "tom", "rose", "lilei", "jerry"); //2.foreach 逐一处理 //使用匿名内部类 // 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));
-
b.统计个数:count(代码演示)
//3.count 统计个数 long count = s1.count(); System.out.println("流中有多少个元素:"+count);
-
过滤:filter(代码演示)
//4.filte 过滤方法 //匿名内部类 // Stream<String> s2 = s1.filter(new Predicate<String>() { // @Override // public boolean test(String s) { // //我们只想要 长度大于4的字符串 // return s.length() > 4; // } // }); //Lambda Stream<String> s2 = s1.filter(s -> s.length() > 4); System.out.println(s2.count());
-
取前几个:limit(代码演示)
//5.limit 取前几个 Stream<String> s3 = s1.limit(3); s3.forEach(s-> System.out.println(s));
-
跳过前几个:skip(代码演示)
//6.skip 跳过前几个 Stream<String> s4 = s1.skip(2); s4.forEach(s-> System.out.println(s));
-
映射方法:map(代码演示)
map方法是将流中每个元素,经过某种算法,变成另外一个元素 //7.map 映射 // Stream<Integer> s5 = s1.map(new Function<String, Integer>() { // @Override // public Integer apply(String s) { // return s.length(); // } // }); //Lambda改写 Stream<Integer> s5 = s1.map(s->s.length()); s5.forEach(s-> System.out.println(s));
-
静态方法合并流:concat(代码演示)
public static Stream<T> concat(Stream<T> s1,Stream<T> s2); //8.concat 静态方法,合并两个流 Stream<String> ss1 = Stream.of("jack","rose"); Stream<String> ss2 = Stream.of("tom","lucy"); //静态方法 Stream<String> sss = Stream.concat(ss1,ss2); sss.forEach(s-> System.out.println(s)); 注意: a.如果是两个以上流的合并,需要多次两两合并 b.如果两个流的泛型不一致也可以合并,合并之后新流的泛型是他们共同的父类(不知道其父类,写Object)
2.7 练习:集合元素的处理(Stream方式)【今天一天的目标就是他】
//使用传统集合遍历方式
public class StreamDemo04 {
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("张三");
//按照求操作集合(使用传统的for循环)
// 1. 第一个队伍只要名字为3个字的成员姓名;
ArrayList<String> one1 = new ArrayList<String>();
for (String name : one) {
if (name.length() == 3) {
one1.add(name);
}
}
// 2. 第一个队伍筛选之后只要前3个人;
ArrayList<String> one2 = new ArrayList<String>();
for (int i = 0; i < 3; i++) {
String name = one1.get(i);
one2.add(name);
}
// 3. 第二个队伍只要姓张的成员姓名;
ArrayList<String> two1 = new ArrayList<String>();
for (String name : two) {
if (name.startsWith("张")){
two1.add(name);
}
}
// 4. 第二个队伍筛选之后不要前2个人;
ArrayList<String> two2 = new ArrayList<String>();
for (int i = 2; i < two1.size(); i++) {
String name = two1.get(i);
two2.add(name);
}
// 5. 将两个队伍合并为一个队伍;
ArrayList<String> all = new ArrayList<String>();
// all.addAll(one2);
// all.addAll(two2);
for (String name : one2) {
all.add(name);
}
for (String name : two2) {
all.add(name);
}
// 6. 根据姓名创建 Person 对象;
ArrayList<Person> persons = new ArrayList<Person>();
for (String name : all) {
Person p = new Person(name);
persons.add(p);
}
// 7. 打印整个队伍的Person对象信息。
for (Person person : persons) {
System.out.println(person);
}
}
}
使用Stream流的方式
public class StreamDemo05 {
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 对象; string -- person
Stream<Person> ps = ss.map(s -> new Person(s));
// 7. 打印整个队伍的Person对象信息
ps.forEach(p-> System.out.println(p));
}
}
2.8 总结:函数拼接和终结方法
函数拼接方法: 由于这种方法返回的还是流对象,故支持链式编程
调用该方法之后,返回还是一个流对象
有:filter,limit,skip,map,concat
终结方法: 由于终结方法没有返回或者返回的不是流,那么不支持链式编程,并且当某个流调用终结方法之后,该流就关闭了,不能继续调用其他任何方法
调用该方法之后,返回值不是流或者无返回值
有:forEach,count
2.9 收集Stream的结果
可以把流收集到集合中,调用流的collect方法即可
可以把流收集到数组中,调用流的toArray方法即可
public class StreamDemo03 {
public static void main(String[] args) {
//收集流中的结果
Stream<Integer> s1 = Stream.of(1,2,3,4,5);
//....对流进行各种操作
//1.将流中的结果收集到集合中
List<Integer> list = s1.collect(Collectors.toList());
System.out.println(list);
Set<Integer> set = s1.collect(Collectors.toSet());
System.out.println(set);
//2.将流中的结果收集到数组中
Object[] objs = s1.toArray();
for (Object obj : objs) {
System.out.println(obj);
}
}
}
注意:
a.一个流只能收集一次(第二次收集会报错!!!)
b.如果收集到数组中某个收集到Object数组
总结
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.综合案例(处理两个集合数据) 【重点多练几遍】