Java8新特性
- Lambda表达式
Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中) - 方法引用:
可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。 - 默认方法 :默认方法就是一个在接口里面有了一个实现的方法。
- Stream API
−新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。 - Optional 类
Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。 - Date Time API − 加强对日期与时间的处理。
删除线格式
下面正片开始
1. Java Lambda 表达式:**
语法如下
(parameters) -> expression
或者
(parameters) ->{ statements; }
当主体有一个语句时,就不需要使用大括号
public class demo1 {
public static void main(String[] args) {
demo1 tester = new demo1();
//声明类型
MathOperation addition = (int a, int b) -> a + b;
//不声明类型
MathOperation subraction = (a, b) -> a - b;
//大括号中的返回值
MathOperation multiplication = (int a, int b) -> {
return a * b;
};
//没有大括号及返回值
MathOperation divsion = (int a, int b) -> a / b;
System.out.println("10+5"+tester.operate(10,5,addition));
System.out.println("10-5"+tester.operate(10,5,subraction));
System.out.println("10*5"+tester.operate(10,5,multiplication));
System.out.println("10/5"+tester.operate(10,5,divsion));
//不用括号
GreetingService greetingService1 = (message) ->
System.out.println("hello1"+message);
GreetingService greetingService2 = message ->
System.out.println("hello2"+message);
greetingService1.sayMessage("学习");
greetingService2.sayMessage("或者开摆");
}
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
}
Lambda 表达式主要用来定义行内执行的方法类型接口
例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
我们也可以直接在 lambda 表达式中访问外层的局部变量
public class demo02 {
public static void main(String[] args) {
final int num = 1;
Converter<Integer,String> s = (param)-> System.out.println(String.valueOf(param+num));
s.convert(2);//结果为3
}
public interface Converter<T1,T2>{
void convert(int i);
}
}
2、方法引用
方法引用通过方法的名字来指向一个方法。
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 ::
package com.runoob.main;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
class Car {
//Supplier是jdk1.8的接口,这里和lamda一起使用了
public static Car create(final Supplier<Car> supplier) {
return supplier.get();
}
public static void collide(final Car car) {
System.out.println("Collided " + car.toString());
}
public void follow(final Car another) {
System.out.println("Following the " + another.toString());
}
public void repair() {
System.out.println("Repaired " + this.toString());
}
}
构造器引用:
它的语法是Class::new,或者更一般的Class< T >::new实例如下:
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
静态方法引用:
它的语法是Class::static_method,实例如下:
cars.forEach( Car::collide );
特定类的任意对象的方法引用:
它的语法是Class::method实例如下:
cars.forEach( Car::repair );
特定对象的方法引用:
它的语法是instance::method实例如下:
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
方法引用实例
import java.util.List;
import java.util.ArrayList;
public class Java8Tester {
public static void main(String args[]){
List<String> names = new ArrayList();
names.add("Google");
names.add("Runoob");
names.add("Taobao");
names.add("Baidu");
names.add("Sina");
names.forEach(System.out::println);
/*输出结果
Google
Runoob
Taobao
Baidu
Sina
*/
}
}
3、Stream API(灰常重点)
1.什么是Stream
流Stream是一个来自数据源的元素队列并支持聚合操作
数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
2.生成流
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
forEach
Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map
map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
limit
limit方法用于获取指定数量的流。
以下代码片段使用 limit 方法打印出 10 条数据:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted
sorted 方法用于对流进行排序。
System.out.println("sorted");
Random random2 = new Random();
random2.ints().limit(5).sorted().forEach(System.out::println);
并行(parallel)程序
parallelStream 是流并行处理程序的代替方法。
System.out.println("parallel");
List<String> strings1 = Arrays.asList("a", "", "bc", "efs", "");
long count1 = strings1.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println(count1);
Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
//Collectors
List<String> strings2 = Arrays.asList("avc","ws","wsdsad");
List<String> collect1 = strings2.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表"+collect1);
String collect2 = strings2.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining());
System.out.println("合并字符串"+collect2);
统计
1.统计单个
numbers.stream().mapToInt(x -> x)…
//创建集合
List<Integer> numbers = Arrays.asList(4, 6, 65, 3, 44, 2, 17, 19);
int max = numbers.stream().mapToInt(x -> x).max().getAsInt();
int min = numbers.stream().mapToInt(x -> x).min().getAsInt();
long count = numbers.stream().mapToInt(x -> x).count();
double avg = numbers.stream().mapToInt(x -> x).average().getAsDouble();
int sum = numbers.stream().mapToInt(x -> x).sum();
System.out.println("最大值:" + max);
System.out.println("最小值:" + min);
System.out.println("数量:" + count);
System.out.println("平均值:" + avg);
System.out.println("和:" + sum);
2.统计所有
//创建集合
List<Integer> numbers = Arrays.asList(4, 6, 65, 3, 44, 2, 17, 19);
IntSummaryStatistics stat = numbers.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("最大值:" + stat.getMax());
System.out.println("最小值:" + stat.getMin());
System.out.println("数量:" + stat.getCount());
System.out.println("平均值:" + stat.getAverage());
System.out.println("和:" + stat.getSum());
4、Optional类的使用
Optional 类是一个可以为null的容器对象。如果值存在则isPresent() 方法会返回true,调用get()方法会返回该对象。
Optional 类的引入可以很好的解决空指针异常。
public class demo5 {
public static void main(String[] args) {
demo5 java8Test = new demo5();
Integer value1 = null;
Integer value2 = new Integer(100);
//Optional.ofNullable可以传递null值
Optional<Integer> a = Optional.ofNullable(value1);
System.out.println(a);//输出Optional.empty
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Test.sum(a, b));
}
public Integer sum(Optional<Integer> a,Optional<Integer> b){
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(1000));//value1不存在会返回默认值1000
Integer value2 = b.get();
return value1+value2;
}
}
5、日期时间 API
本地化日期时间API
public class demo6 {
public static void main(String[] args) {
demo6 java8Test = new demo6();
java8Test.testLocalDateTime();
}
public void testLocalDateTime(){
//获取当前日期时间
LocalDateTime nowTime = LocalDateTime.now();
System.out.println("当前时间为"+nowTime);//2022-06-03T19:01:40.710
LocalDate date = nowTime.toLocalDate();
System.out.println(date);//2022-06-03
Month month = nowTime.getMonth();
int dayOfMonth = nowTime.getDayOfMonth();
int second = nowTime.getSecond();
System.out.println(month);//JUNE
System.out.println(dayOfMonth);//3 今天是6月3日
System.out.println(second);//26 秒
//输入指定日期2025-12-15T19:09:09.298 年月日指定时间是当前时间
System.out.println(nowTime.withDayOfMonth(15).withYear(2025).withMonth(12));
//LocalDate.of输出日期2025-12-15
System.out.println(LocalDate.of(2025, Month.DECEMBER, 15));
//18:53小时加分钟
System.out.println(LocalTime.of(18, 53));
//18:25:06
System.out.println(LocalTime.parse("18:25:06"));
}
}
6.反射(异常重要)
反射是框架设计的灵魂
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))
反射的定义
1.Java反射机制是在运行的状态中,对于任意一个类。都能够知道这个类的所以属性和方法。
对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2.要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
反射就是把java类中的各种成分映射成一个个的Java对象
package fanshe;
/**
* 获取Class对象的三种方式
* 1 Object ——> getClass();
* 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
* 3 通过Class类的静态方法:forName(String className)(常用)
*
*/
public class Fanshe {
public static void main(String[] args) {
//第一种方式获取Class对象
Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
Class stuClass = stu1.getClass();//获取Class对象
System.out.println(stuClass.getName());
//第二种方式获取Class对象
Class stuClass2 = Student.class;
System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
//第三种方式获取Class对象
try {
Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
7.注解
1.注解
就是对于代码中某些鲜活个体的贴上去的一张标签。
定义注解
public @interface TestAnnotation {
}
创建一个类 Test,然后在类定义的地方加上 @TestAnnotation 就可以用 TestAnnotation 注解这个类了。
2.元注解
元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
- @Retention它解释说明了这个注解的的存活时间。
- @Target 指定了注解运用的地方。
- @Documented作用是能够将注解中的元素包含到 Javadoc 中去。
- @Inherited是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
- @Repeatable可重复的意思