Day10 Java8新特性、反射和注解

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可重复的意思
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦学java只为一口饭吃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值