Java基础学习收尾,了解JDK版本的新特性
一、Lambda表达式
1.1 使用举例
1 |
|
1.2 Lambda表达式使用
- 1.Lambda格式:
Lambda形参列表 -> Lambda体
- “->”:lambda操作符 或 箭头操作符
- ->的左边:Lamdba形参列表(泛型可省略数据类型)(接口中的抽象方法的形参列表)
- ->的右边:Lambda体(重写的抽象方法的方法体)
- 2.Lambda表达式的本质:
- 作为函数式接口的实例
- 函数式接口:只声明了一个抽象方法,此接口就称为函数式接口
- 作为函数式接口的实例
- 3.Lambda表达式使用:
- (1)无参,无返回值:
1
2
3Runnable r1 = () -> {
System.out.println("无参,无返回值写法");
}; - (2)有参,无返回值
1
2
3Consumer<String> con = (String str) -> {
System.out.println(str);
}; - (3)参数有泛型可省略数据类型;参数只有一个可省略
"()"
;执行表达式只有一个可省略"{}"
1
Runnable r1 = () -> System.out.println("我爱广州!");
- (4)有参,有多条执行语句,且有返回值:
1
2
3
4
5Comparator<Integer> com2 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}; - (5)执行语句只有一个,且是return语句,可把
"{}"
和"return"
省略1
Comparator<Integer> com1 = (o1, o2) -> o1.compareTo(o2);
- (1)无参,无返回值:
二、函数式接口
2.1 定义和种类
- 函数式接口:只声明了一个抽象方法的接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> |
T | void | 对类型为T的对象应用操作,包含的方法:void accept(T t) |
Suppiler<T> |
无 | T | 返回类型为T的对象,包含方法为:T get() |
Fuction<T, R> |
T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate<T> |
T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值,包含方法:boolean test(T t) |
BiFunction<T, U, R> |
T, U | R | 对类型为T, U参数应用操作,返回R类型的结果。包含方法为:R apply(T t, U u) |
2.2 使用举例
1 |
|
三、引用
3.1 方法引用
- 1.当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
- 2.方法引用可以看做是Lambda表达式深层次的表达。
- 3.使用格式:
类(对象) :: 方法名
- 4.使用情况:
- (1)对象 :: 非静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14//情况一: 对象 :: 实例方法
//Consumer中的void accpect(T t)
//PrintStream中的void println(T t)
public void test1(){
//Lamvda表达式
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("Lambda表达式");
//方法引用
PrintStream ps = System.out;
Consumer<String> con2 = ps :: println;
con2.accept("方法引用");
} - (2)类 :: 静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13//情况二:类 :: 静态方法
//Comparator中的int compare(T t1, T t2)
//Integer中的int compare(T t1, T t2)
public void test2(){
//Lambda表达式
Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);
System.out.println(com1.compare(12, 43));
//方法引用
Comparator<Integer> com2 = Integer :: compare;
System.out.println(com2.compare(23, 21));
} - (3)类 :: 非静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14//情况三:类 :: 实例方法(有难度)
//Comparator的int compare(T t1, T t2);
//String中的int t1.compare(t2);
public void test3(){
//Lambda表达式
Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc", "abd"));
//方法引用
Comparator<String> com2 = String :: compareTo;
System.out.println(com1.compare("abc", "abd"));
//第一个方法的参数,作为第二方法对象的进行调用
}
- (1)对象 :: 非静态方法
- 5.方法引用使用的要求:要求接口中的 抽象方法的形参列表和返回值类型 与 方法引用的形参列表和返回值类型相同
3.2 构造器引用
- 1.和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致
- 2.抽象方法的返回值类型即为构造器所属的类的类型
1 | class Person{ |
- 3.使用情况
- (1)空参构造器
1
2
3
4
5
6
7
8
9
10
11
12//Supplier中的T get()
//Person的空参构造器:Employee()
public void test1(){
//Lambda表达式
Supplier<Person> sup1 = () -> new Person();
System.out.println(sup1.get());
//构造器引用
Supplier<Person> sup2 = Person :: new;//理解为:Person类的new构造器器
System.out.println(sup2.get());
} - (2)一个参数构造器
1
2
3
4
5
6
7
8
9
10
11//带一个参数的构造器
public void test2(){
//Lambda表达式
Function<String, Person> func1 = name -> new Person(name);
System.out.println(func1.apply("Lambda表达式"));
//构造器引用
Function<String, Person> func2 = Person :: new;
System.out.println(func2.apply("构造器引用"));
} - (3)两个参数构造器
1
2
3
4
5
6
7
8
9
10
11//带两个参数的构造器
public void test3(){
//Lambda表达式
BiFunction<String, Integer, Person> func1 = (name, age) -> new Person(name, age);
System.out.println(func1.apply("Lambda表达式", 1));
//构造器引用
BiFunction<String, Integer, Person> func2 = Person :: new;
System.out.println(func2.apply("构造器引用", 2));
}
- (1)空参构造器
3.3 数组引用
- 可以把数组理解为特殊的类,则使用方法和构造器引用没有区别
1 | //Lambda引用 |
四、Stream API
4.1 介绍
- 使用Stream API 对集合数据进行操作,就类似于使用SQL语句对数据库查询
- 使用理由:项目中多数数据源来自于MySQL,Oracle等。但现在数据源可以更多了,有MongDB,Radisson等,而这些NoSQL的数据就要需要Java层面去处理
- 与集合的区别:
- (1)Stream关注的是对数据的运算,与CPU打交道
- (2)集合关注的是数据的存储,与内存打交道
- (3)集合讲的是数据,Stream讲的是计算!
- 注意:
- (1)Stream自己不会存储元素
- (2)Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream
- (3)Stream操作时延迟执行的。这意味着他们会等到需要结构的时候才执行
- Stream操作:创建Stream -> 中间操作 -> 终止操作(终端操作)
- 说明:
- (1)一个中间操作链,对数据源的数据进行处理
- (2)一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
- 说明:
4.2 创建Stream
提供一个集合
1
2
3
4
5
6
7
8
9
10
11
12
13class CollectionTest{
private static String[] str = new String[]{"马云", "马化腾", "黄旭东", "咕料", "C酱","C酱", "C酱", "C酱"};
public CollectionTest(){}
public static String[] getArray(){
return str;
}
public static List<String> getStringList(){
return Arrays.asList(str);
}
}方法一:通过集合进行创建
1
2
3
4
5
6
7//(1)通过集合进行创建
public void test(){
List<String> list = CollectionTest.getStringList();
Stream<String> stream = list.stream();//顺序流
Stream<String> parallelStream = list.parallelStream();//并行流
}方法二:通过数组进行创建
1
2
3
4
5
public void test2(){
String[] array = CollectionTest.getArray();
Stream<String> stream = Arrays.stream(array);//类型通过泛型体现
}方法三:通过Stream的of()
public static<T> Stream<T> of(T... values)
1
2
3
4
public void test3(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8);
}方法四:创建无限流(用得少)
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
public static<T> Stream<T> generate(Supplier<? extends T> s)
1
2
3
4
5
6
7
8
9
10
public void test4(){
//迭代
//遍历前10个偶数
Stream.iterate(0, t -> t+2).limit(10).forEach(System.out :: println);
//生成
//生成10个随机数
Stream.generate(Math::random).limit(10).forEach(System.out :: println);
}
4.3 中间操作
- (1)筛选和切片
方法 | 功能 |
---|---|
filter(Predicate p) |
接受Lambda,从流中排序某些元素 |
distinct() |
筛选,通过流锁生成的hashCode 和equals() 去除重复元素 |
limit(Long maxSize) |
截断点,使其元素不超过给定的数量 |
skip(long n) |
跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n)互补 |
1 | //(1)筛选和切片 |
- (2)映射
方法 | 功能 |
---|---|
map(Function f) |
接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新元素 |
mapToDouble(ToDoubleFunction f) |
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream |
mapToint(TointFunction f) |
接收一个函数作为参数,该函数会别应用到每个元素上,产生一个新的intStream |
mapToLong(ToLongFunction f) |
接收一个函数作为参数,该函数会应用到每个元素上,产生一个新的LongStream |
flatMap(Function f) |
接收一个函数作为参数,将流中的每个值都缓存另一个流,然后把所有流连成一个流 |
1 | //将字符创中的多个字符构成结合转换成对应的Stream的实例 |
- (3)排序
方法 | 功能 |
---|---|
sorted() |
产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) |
产生一个新流,其中按比较器顺序排序 |
1 | //(3)排序 |
4.4 终止操作
- (1)匹配与查找
方法 | 功能 |
---|---|
allMatch(Predicate p) |
检查是否匹配所有元素 |
anyMatch(Predicate p) |
检查是否至少匹配一个元素 |
noneMatch(Predicate p) |
检查是否没有匹配所有元素 |
findFirst() |
返回第一个元素 |
findAny() |
返回当前流中的任意元素 |
count() |
返回流中元素总数 |
max(Comparator c) |
返回流中的最大值 |
min(Comparator c) |
返回流中的最小值 |
forEach(Consumer c) |
内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。相反,StreamAPI使用内部迭代–它帮你把迭代做了) |
1 |
|
- (2)归约
方法 | 功能 |
---|---|
reduce(T iden, BinaryOperator b) |
可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) |
可以将流中元素返回结合起来,得到一个值。返回Optional<T> |
1 |
|
- (3)收集
方法 | 功能 |
---|---|
collect(Collector c) |
将流转换成其他形式。接受一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
- Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map),另外,Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
方法 | 返回参数 | 功能 |
---|---|---|
toList | List<T> |
把流中元素收集到List中 |
toSet | Set<T> |
把流中元素收集到Set中 |
toCollection | Collection<T> |
把流中的元素收集到创建的集合中 |
1 | //收集 |
五、Optional类
5.1 介绍
Optional<T>类
是一个容器类,它可以保存类型T的值,代表之歌值存在。或仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好表达这个概念。并且可以避免空指针异常。
5.2 方法
- (1)创建Optional类对象
方法 | 功能 |
---|---|
Optional.of(T t) |
创建一个Optional实例,t必须非空 |
Optional.empty() |
创建一个空的Optional实例 |
Optional.ofNullable(T t) |
t可以为null |
- (2)获取Optional容器中是否包含对象
方法 | 功能 |
---|---|
boolean isPresent() |
判断是否包含对象 |
void ifPresent(Consumer<? super T> consumer) |
如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它 |
- (3)获取Optional容器的对象
方法 | 功能 |
---|---|
T get() |
如果调用对象包含值,返回该值,否则抛异常 |
T orElse(T other) |
如果有值则将其返回,否则返回指定的other对象 |
T orElseGet(Supplier<? extends T> other) |
如果有值则将其返回,否则返回有Supplier接口实现提供的对象 |
T orElseThrow(Supplier<? extends X> exceptionSupplier) |
如果有值则将其返回,否则抛出有Supplier皆苦实现提供的异常 |