JDK1.8 新特性(部分讲解)
程序员文章站
2022-06-04 22:58:53
...
JDK1.8 新特性
1、Lambda表达式的初体验
Lambda表达式就是匿名内部类的简化方案,替代品,Lambda表达式是从JDK1.8开始才有的特性。
Lambda表达式直观上给人一种非常简洁的感觉。
/*
Lambda表达式就是为了替换匿名子类
*/
public class Demo01 {
public static void main(String[] args) {
//匿名子类的方式
new Thread(
new Runnable() {
@Override
public void run() {
System.out.println("匿名子类的方式");
}
}
).start();
//Lambda表达式
new Thread(() -> {
System.out.println("Lambda表达式方式");
}).start();
}
}
2. Lambda表达式的格式,及含有参数和返回值的Lambda写法
Lambda表达式的格式:参数列表,箭头,方法体
(参数列表) -> { 方法体 }
【代码实践】
含有参数和返回值的接口
public interface Calculate {
int cal(int a, int b);
}
其lambda表达式如下
Calculate c2 = (int a, int b)->{
return a+b;
};
System.out.println(c2.cal(10, 20));
【练习】
/*
定义Person类型,创建多个Person对象,放到集合中,让集合排序按照年龄的升序排序
排序后打印结果。
*/
public class Demo01 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person(18, "迪丽热巴"));
list.add(new Person(17, "古力娜扎"));
list.add(new Person(20, "马儿扎哈"));
//传统的匿名子类方式
//Collections.sort(list, new Comparator<Person>() {
// @Override
// public int compare(Person o1, Person o2) {
// return o1.getAge() - o2.getAge();
// }
//});
//Lambda 表达式
Collections.sort(list, (Person o1, Person o2) -> {
return o1.getAge() - o2.getAge();
});
System.out.println("list = " + list);
}
}
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
//此处省略:getter/setter方法
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Person{");
sb.append("age=").append(age);
sb.append(", name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}
3. Lambda表达式的省略格式
【参数列表】
- 参数列表的参数类型可以省略==【一省全省】==
- 只有一个参数,可以把小括号省略==【类型也要省略】==
- 如果参数列表中没有参数,括号不能省
public class Demo01 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person(18, "迪丽热巴"));
list.add(new Person(17, "古力娜扎"));
list.add(new Person(20, "马儿扎哈"));
//省略参数中的类型
Collections.sort(list, (o1, o2) -> {
return o1.getAge() - o2.getAge();
});
System.out.println("list = " + list);
//参数列表中只有一个参数:类型+括号 都可以省略
Printable p = str -> {
System.out.println(str);
};
p.print("Hello");
//如果参数列表中没有参数,括号不能省
Runnable r = () -> {
System.out.println("");
};
}
}
【方法体】
- 如果方法体中只有一个语句,那么大括号,return,分号==【一省全省】==
public class Demo01 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person(18, "迪丽热巴"));
list.add(new Person(17, "古力娜扎"));
list.add(new Person(20, "马儿扎哈"));
//省略参数中的类型
Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());
System.out.println("list = " + list);
//参数列表中只有一个参数:类型+括号 都可以省略
Printable p = str -> System.out.println(str);
p.print("Hello");
//如果参数列表中没有参数,括号不能省
Runnable r = () -> System.out.println("");
}
}
4. 函数式接口
-
什么接口称为函数式接口?
只有一个抽象方法的接口,就是一个函数式接口,只有函数式接口才可以写Lambda表达式。
注意:可以含有Object中equals抽象方法
boolean equals(Object obj)
可以有其他的默认方法,是私有方法,静态方法
-
如何自己定义函数式接口?
定义一个接口,只要保证只有一个抽象方法,就是函数式接口
-
注解
@FunctionalInterface
的作用?这个注解可写可不写【建议写上,有保障】
用来强制保证定义的接口就是函数式接口,如果一个接口被这个@FunctionalInterface注解了,那么意味着只能有一个抽象方法,否则报错。
/*
函数式接口就是能够写Lambda表达式的接口,【要求只能有一个抽象方法】
*/
public class Demo01 {
public static void main(String[] args) {
//Lambda表达式创建的Eatable的子类
Eatable e1 = food -> System.out.println("享用:" + food);
System.out.println("e1 = " + e1);
e1.eat("山珍海味");
e1.sleep();
}
}
@FunctionalInterface //为了告诉其他的程序员,我这个接口是函数式接口,别动
public interface Eatable {
void eat(String food);
default void sleep(){
System.out.println("边吃边睡!!");
};
//void fly();
}
5. 常用函数式接口:Consumer
Consumer
:是一个函数式接口,含有一个抽象方法
抽象方法:
void accept(T t); 这个方法接收一个参数,并把这个参数进行处理
特别常见的使用场景:集合遍历时
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "AA", "BB", "CC", "DD");
//匿名子类
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s+":");
}
});
//Lambda方式
list.forEach(e-> System.out.println(e));
/*
Consumer函数式接口,专门用来消费数据
抽象方法:
void accept(T t);
接收一个数据,进行消费
*/
public class Demo01 {
public static void main(String[] args) {
test("HelloWorld", s -> System.out.println(s));
test("Hello:World", str -> System.out.println(str.split(":")[0]));
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "AA", "BB", "CC", "DD");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s+":");
}
});
list.forEach(e-> System.out.println(e));
list.forEach(str-> System.out.println("【"+str+"】"));
}
public static void test(String str, Consumer<String> consumer) {
consumer.accept(str);
}
}
6. 常用的函数式接口:Predicate
抽象方法:
boolean test(T t)
【练习】
/*
Predicate用来判断某个数据是否符合要求
抽象方法:
boolean test(T t)
*/
public class Demo01 {
public static void main(String[] args) {
//要求密码只能6位
test("123456", t -> t.length() == 6);
test("123456789", t -> t.length() == 6);
test("abcdefg", t -> t.length() >3);
}
public static void test(String password, Predicate<String> predicate) {
boolean result = predicate.test(password);
System.out.println("result = " + result);
}
}
7.Stream流的使用
流式思想其实就根现实中的流水线作业相似
1. Stream流的获取
流的获取方式:
1)集合获取流
Collection集合中存在一个方法叫做:stream()可以直接将集合转化成流
Collection接口中存在一个默认方法:default Stream<T> stream()
2)数组获取流
Stream.of(T… values):这个方法是一个静态方法,可以直接传入数组【可变参数的底层就是数组】
/*
获取流的第一种方式:
Collection中有一个方法stream(),可以直接将所有的Collection集合转换为流。
获取流的第二种方式:
借助Stream中的静态方法,将单个的数据,散装的数据,数组直接转换为流对象
Stream s=Stream.of("Hello");
Stream s=Stream.of("Hello","World");
Map集合没有方法可以直接转换为流,可以先将Map的键或者值或者键值对对象转换为集合,通过集合转换为流对象
*/
public class Demo01 {
public static void main(String[] args) {
//获取流的第一种方式:
Collection<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//获取流的第二种方式:
Stream<String> steam2 = Stream.of("AAAA");
String[] arr = {"AAA", "BBB", "CCC"};
Stream<String> stream3 = Stream.of(arr);
//注意:Map没有直接的方法转换为流
Map<String, String> map = new HashMap<>();
// map.stream()
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream4 = entries.stream();
}
}
2.Stream流中常用的方法
注意:stream流对象只能使用一次
/*
终结方法:
public abstract void forEach(Consumer<? super String> action): 遍历Stream中的元素
public abstract long count():获取流中元素的个数
非终结方法:
public abstract Stream<String> filter(Predicate<? super String> predicate):筛选数据
public abstract Stream<String> limit(long maxSize):获取前几个数据
public abstract Stream<String> skip(long n):跳过前几个元素
public static <T>Stream<String> concat(Stream<? extends String> a, Stream<? extends String> b):拼接两个流
注意:stream流对象只能使用一次
stream has already been operated upon or closed
*/
public class Demo01 {
public static void main(String[] args) {
//Stream流对象创建
Stream<String> stream = Stream.of("AAA", "BB", "CCCC", "DDDDD", "EEE", "FFF");
//filter:过滤
stream = stream.filter(str->str.length()>=3);
//limit:获取前几个元素
stream =stream.limit(4);
//skip: 跳过前几个元素
stream = stream.skip(2);
//concat:拼接两个流为一个
Stream<String> stream1 = Stream.of("111", "222");
stream = Stream.concat(stream, stream1);
//forEach
stream.forEach(str-> System.out.println(str));
//count
//long count = stream.count();
//System.out.println("count = " + count);
}
}
8.Stream得综合案例
现在有两个ArrayList
集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以下若干操作步骤:
- 第一个队伍只要名字为3个字的成员姓名;
- 第一个队伍筛选之后只要前3个人;
- 第二个队伍只要姓张的成员姓名;
- 第二个队伍筛选之后不要前2个人;
- 将两个队伍合并为一个队伍;
- 打印整个队伍的姓名信息。
两个队伍(集合)的代码如下:
/*
使用流解决
传统得for遍历方式进行完成以下需求
*/
public class Demo02Stream {
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> stream1 = one.stream()
.filter(name -> name.length() == 3)
.limit(3);
//3. 第二个队伍只要姓张的成员姓名;
//4. 第二个队伍筛选之后不要前2个人;
Stream<String> stream2 = two.stream()
.filter(name -> name.startsWith("张"))
.skip(2);
//5. 将两个队伍合并为一个队伍;
//6. 打印整个队伍的姓名信息。
Stream.concat(stream1, stream2)
.forEach(name-> System.out.println("name = " + name));
}
}
/*
传统得for遍历方式进行完成以下需求
*/
public class Demo01 {
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个字的成员姓名;
List<String> one1 = new ArrayList<>();
for (String name : one) {
if (name.length() == 3) {
one1.add(name);
}
}
//2. 第一个队伍筛选之后只要前3个人;
List<String> one2 = new ArrayList<>();
for (int i = 0; i < 3; i++) {
one2.add(one1.get(i));
}
//3. 第二个队伍只要姓张的成员姓名;
List<String> two1 = new ArrayList<>();
for (String name : two) {
if (name.startsWith("张")) {
two1.add(name);
}
}
//4. 第二个队伍筛选之后不要前2个人;
List<String> two2 = new ArrayList<>();
for (int i = 2; i < two1.size(); i++) {
two2.add(two1.get(i));
}
//5. 将两个队伍合并为一个队伍;
for (String name : one2) {
two2.add(name);
}
//6. 打印整个队伍的姓名信息。
for (String name : two2) {
System.out.println("name = " + name);
}
}
}