java必备基础7(反射、JDK8新特性)

目录

反射

获取Class实例的三种方式

通过反射获取类属性、方法、构造器

JDK8新特性

lambda表达式

函数式接口

方法引用

StreamAPI

流的中间操作

映射

排序

流的终止操作

聚合

Collectors

Collectors.groupingBy() 分组

Collectors.groupingBy() 分组之统计分组总值

接口中的默认方法和静态方法

Optional

日期使用

LocalDate 

日期计算

日期比较

日期和字符串转化

获取对象上常用的属性

LocalTime

LocalDateTime

TemporalAdjusters


反射

        其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解刨。

反射的好处:大大增强了程序的扩展性。

反射的基本步骤:

  1. 获取Class对象,就是获取到指定的名称的字节码文件对象。
  2. 实例化对象,获得类的属性、方法、构造函数。
  3. 访问属性、调用方法、调用构造函数创建对象。

获取Class实例的三种方式

  1. 实例化对象调用getClass()方法。弊端:必须要创建该类对象,才能调用getClass方法。
  2. 每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。

  3. 使用Class类的静态方法forName(),用类的名字获取一个Class实例。

// 1. 根据给定的类名来获得  用于类加载
String classname = "cn.itcast.reflect.Person";// 来自配置文件
Class clazz = Class.forName(classname);// 此对象代表Person.class

// 2. 如果拿到了对象,不知道是什么类型   用于获得对象的类型
Object obj = new Person();
Class clazz1 = obj.getClass();// 获得对象具体的类型

// 3. 如果是明确地获得某个类的Class对象  主要用于传参
Class clazz2 = Person.class;

通过反射获取类属性、方法、构造器

例:Field[] fields = Apple.class.getFields();

方法

返回值

说明

getFields

Field[]

返回一个类中所有可访问的公共字段

getDeclaredFields

Field[]

返回一个类中全部字段,但只包括该类字段 

getField("xxx")

field

根据字段名返回一个公开字段

getDeclaredField("xxx")

field

根据字段名返回一个字段

getDeclaredMethods()

Method[]

Methodh获取方式

getDeclaredConstructors()

Constructor[]

获取构造方法

field.setAccessible(true)

可更改属性的访问权限

JDK8新特性

lambda表达式

        最直接作用就是减少代码,显得非常简洁。

// java7中  筛选产品为nike的
public  List<Product> filterProductByColor(List<Product> list){
    List<Product> prods = new ArrayList<>();
    for (Product product : list){
        if ("nike".equals(product.getName())){
            prods.add(product);
        }
    }
    return prods;
 }

// 使用 lambda
public  List<Product> filterProductByPrice(List<Product> list){
  return list.stream().filter(p->"nike".equals(p.getName())).collect(Collectors.toList());  
 }

函数式接口

位于java.util.functaion包下,下面介绍最常用的几个

Predicate

        接收一个值返回boolean    Predicate p = t->true;

        

        运用详情:    https://www.jianshu.com/p/b38ff80e3039

Supplier

        无接受参数返回一个值      Supplier<T> s = () -> new T();

        

        运用详情:  https://www.jianshu.com/p/1386445719bc

Consumer
        接受一个参数无返回值       Consumer<String> c = c -> System.out.println(s);

        运用详情: Java 常用函数式接口之Consumer接口 - LeeHua - 博客园

Function<T,R>  接受参数T 返回参数R      Function<Long,String> f = c -> String.valueof(c);
其他还有一些 BiFunction,BiConsumer,DoubleSupplier等大家有兴趣自己去阅读下源码

方法引用

 静态引用:格式 Class::static_method

List<String> list = Arrays.asList("a","b","c");
list.forEach(str -> System.out.print(str));
list.forEach(System.out::print);

构造器调用 格式:Class::new 

List<String> list = Arrays.asList("a","b","c");
List<Test> list.stream().map(Test::new).collect(Collectors.toList());

public class Test{
    private final String desc;
  
    public Test(String desc){
      this.desc=desc;
    }
}

方法调用 格式:instance::method

List<String> list = Arrays.asList("a","b","c");
Test test = new Test();
List<String> list.stream().map(test::toAdd).collect(Collectors.toList());

public class Test{
    private final String desc;
  
    public Test(String desc){
      this.desc=desc;
    }

    public String toAdd(String desc){
        return desc+"add";
    }
}

StreamAPI

// 使用jdk1.8中的Stream API进行集合的操作
@Test
public void test(){
    // 循环过滤元素                                       
    proList.stream()
           .fliter((p) -> "红色".equals(p.getColor()))
           .forEach(System.out::println);

    // map处理元素然后再循环遍历
    proList.stream()
           .map(Product::getName)
           .forEach(System.out::println);
  
   // map处理元素转换成一个List
   proList.stream()
           .map(Product::getName)
           .collect(Collectors.toList());
}

  Collection下的Stream()串行流和parallelStream()并行流

//Arrays 中的 stream() 方法,将数组转成流
Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);
//Stream中的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);

Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
stream2.forEach(System.out::println); // 0 2 4 6 8 10
 
Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
stream3.forEach(System.out::println);
//使用 Pattern.splitAsStream() 方法,将字符串分隔成流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);

流的中间操作

Filter过滤流中某些元素

Limit、skip、distinct、sorted都是有状态操作,这些操作只有拿到前面处理后的所有元素之后才能继续下去。

Limit(n):获取前n个元素

Skip(n):跳过n个元素,配合limit(n)可实现分页

Distinct:通过流中元素的hashCode()和equals()去除重复元素

Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);

Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14

        .distinct() //6 7 9 8 10 12 14

        .skip(2) //9 8 10 12 14

        .limit(2); //9 8

    newStream.forEach(System.out::println);

映射

Map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

FlatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

 List<String> list = Arrays.asList("a,b,c", "1,2,3");

//去掉字符串中所有的,

  List<String> collect = list.stream().map(s -> s.replaceAll(",", "")).collect(Collectors.toList());

  System.out.println(collect);

// flatMap 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

Stream<String> stringStream = list.stream().flatMap(s -> {

//将字符串以,分割后得到一个字符串数组

String[] split = s.split(",");

//然后将每个字符串数组对应流返回,flatMap会自动把返回的所有流连接成一个流

Stream<String> stream = Arrays.stream(split);

  return stream;

  });

  System.out.println(stringStream.collect(Collectors.toList()));

排序

Sorted():自然排序,流中元素实现Comparable接口

Sorted(Comparator compatator)定制排序,自定义Comparator排序器

流的终止操作

匹配

allmatch,noneMatch,anyMatch用于对集合中对象的某一个属性值进行判断,
allMatch全部符合该条件返回true,
noneMatch全部不符合该断言返回true
anyMatch 任意一个元素符合该断言返回true

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

boolean allMatch = list.stream().allMatch(e -> e > 10); //false

boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true

boolean anyMatch = list.stream().anyMatch(e -> e > 4);  //true

聚合

findFirst:返回流中第一个元素
findAny:返回流中的任意元素
count:返回流中元素的总个数
max:返回流中元素最大值
min:返回流中元素最小值

Java Steam详解_doubleStrongWu的博客-CSDN博客_java steam

Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

System.out.println("筛选列表: " + filtered);

 String mergedString = strings.stream().

filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));

System.out.println("合并字符串: " + mergedString);

Collectors.groupingBy() 分组

/**

 * 使用java8 stream groupingBy操作,按城市分组list

 */

public void groupingByCity() {

Map<String,List<Employee>>map=employees.stream().

collect(Collectors.groupingBy(Employee::getCity));

map.forEach((k, v) -> {

System.out.println(k + " = " + v);

});

}

Collectors.groupingBy() 分组之统计分组总值

Map<String, Long> map = employees.stream()

.collect(Collectors.groupingBy(Employee::getCity, Collectors.summingLong(Employee::getAmount)));

Java8 Stream 之groupingBy 分组讲解_在奋斗的大道的博客-CSDN博客_groupingby

接口中的默认方法和静态方法

public interface ProtocolAdaptor {

    ProtocolAdaptor INSTANCE = DynamicLoader.findFirst(ProtocolAdaptor.class).orElse(null);
   
    default ProtocolAdaptor proxy() {
        return (ProtocolAdaptor)     
               Proxy.newProxyInstance(ProtocolAdaptor.class.getClassLoader(),
                new Class[]{ProtocolAdaptor.class},
                (proxy, method, args) -> intercept(method, args));
    }
}  

Optional

用于处理对象空指针异常,Optrional是一个对象容器,具有以下两个特点:提示用户要注意该对象有可能为null;简化if else代码

1.创建

    Optional.empty(): 创建一个空的 Optional 实例

    Optional.of(T t):创建一个 Optional 实例,当 t为null时抛出异常      

    Optional.ofNullable(T t):创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例

2. 获取:

    get():获取optional实例中的对象,当optional 容器为空时报错

3. 判断:

    isPresent():判断optional是否为空,如果空则返回false,否则返回true

    ifPresent(Consumer c):如果optional不为空,则将optional中的对象传给Comsumer函数

    orElse(T other):如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值

    orElseGet(Supplier<T> other):如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other

    orElseThrow(Supplier<X> exception):如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常

4. 过滤:

    filter(Predicate<T> p):如果optional不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional  

5. 映射:

    map(Function<T, U> mapper):如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中。

    flatMap(Function< T,Optional<U>> mapper):跟上面一样,在optional不为空的情况下,将对象t映射成另外一个optional

    区别:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional
例子:

日期使用

于原来老旧的日期API一直被人诟病,比如java.util.Date,java.util.Calendar等,并且原来所有的日期类都是可变且线程不安全的,导致许多人要么自己手动封装,要么转去使用Joda Time等这类优秀的第三方工具包。所以,在JDK1.8中,JDK官方在Joda Time等优秀工具包基础上,重新提供了一份相当不错的日期API。并且,在JDK1.8中,java.time包中的类是不可变且线程安全的

  • java.time包:JDK8中的基础包,所有常用的基础类都是这个包的一部分,如LocalDateLocalTimeLocalDateTime等等,所有这些类都是不可变且线程安全的;
  • java.time.chrono包:这个包为非ISO的日历系统定义了一些API,我们可以在借助这个包中的一些类扩展我们自己的日历系统;
  • java.time.format包:这个包很明显了,格式化和解析日期时间对象,一般java.time包中的类都差不多能满足我们的需求了,如果有需要,可以调用这个包下的类自定义解析方式;
  • java.time.temporal包:这个包很有意思,封装了一些获取某个特定日期和时间的接口,比如某月的第一天或最后一天,并且这些方法都是属于特别好认的方法。
  • java.time.zone包:这个包就是时区相关的类了。

LocalDate 

java.time.LocalDate这个类,是用来表示日期的,也仅包含日期
 

public static void testDate() {
    // 1. 获取当前日期(年月日) -----打印输出-----2018-01-29
    LocalDate localDate = LocalDate.now();
    System.out.println(localDate.toString());
    // 2. 根据年月日构建Date ----打印输出-----2018-01-30
    LocalDate localDate1 = LocalDate.of(2018, 01, 30);
    // 3. 字符串转换日期,默认按照yyyy-MM-dd格式,也可以自定义格式 -----打印输出-----2018-01-30
    LocalDate localDate2 = LocalDate.parse("2018-01-30");
    // 4. 获取本月第一天 -----打印输出-----2018-01-01
    LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());
    // 5. 获取本月第二天  -----打印输出-----2018-01-02
    LocalDate secondDayOfMonth = localDate.withDayOfMonth(2);
    // 6. 获取本月最后一天 -----打印输出-----2018-01-31
    LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());
    // 7. 明天 -----打印输出----- 2018-01-30
    LocalDate tomorrowDay = localDate.plusDays(1L);
    // 8. 昨天 -----打印输出----- 2018-01-28
    LocalDate yesterday = localDate.minusDays(1L);
    // 9. 获取本年第12天 -----打印输出----- 2018-04-30
    LocalDate day = localDate.withDayOfYear(120);
    // 10. 计算两个日期间的天数
    long days = localDate.until(localDate1, ChronoUnit.DAYS);
    System.out.println(days);
    // 11. 计算两个日期间的周数
    long weeks = localDate.until(localDate1, ChronoUnit.WEEKS);
    System.out.println(weeks);
}

日期计算

名称

作用

plusDays

往后加n天,即获取n天后的日期

plusWeeks

往后加n周,即获取n周后的日期

plusMonths

往后加n月,即获取n月后的日期

plusYears

往后加n年,即获取n年后的日期

minusDays

往后减n天,即获取n天前的日期

...

minus也有减周、月、年相关的API这里就不写了

now

获取当前日期

日期比较

名称

作用

isBefore

判断当前日期对象是否在比较的日期对象之前

isAfter

判断当前日期对象是否在比较的日期对象之后

isEqual

判断当前日期对象是否与比较的日期对象(日期)相等

日期和字符串转化

LocalDate提供了丰富的API来满足我们对于不同日期格式的需求,最主要的核心方法就是format()和parse(),前者让我们可以实现日期的格式化,后者可以将字符串转为LocalDate对象。

1、日期的格式化(LocalDate对象转字符串)

 @Test

    public void LocalDateTest(){

        //获取当前的日期

        LocalDate date1 = LocalDate.now();

        String formatDate = date1.format(DateTimeFormatter.ofPattern("MM dd / yyyy"));

        System.out.println("格式化后的日期为:" + formatDate);

}

2.字符串转日期

我们一般使用parse()方法来进行字符串转日期的操作,需要注意的是parse()方法默认是按照yyyy-MM-dd的格式来将字符串转换为日期对象的,如果给定的字符串不是这个日期格式的,则需要手动指定解析的日期格式,否则程序会抛异常!!

 @Test

public void LocalDateTest(){

// 默认转换的日期格式为 yyyy-MM-dd

  LocalDate date = LocalDate.parse("2022-04-03");

   System.out.println("date解析后的日期为:" + date);

LocalDatedate2= LocalDate.parse("2022/04/03",DateTimeFormatter.ofPattern("yyyy/MM/dd"));

   System.out.println("date2解析后的日期为:" + date2);

 }

 

获取对象上常用的属性

便捷的在日期对象上面获取年月日等属性,方便后续程序的逻辑判断。常用的API如下:

名称

作用

get(TemporalField field)

获取指定字段的int值

getChronology()

获取该日期格式,例如:ISO

getDayOfMonth()

获取一个月中的第几号,为int类型

getDayOfWeek()

获取星期字段,返回DayOfWeek

getDayOfYear()

以 int 格式获取一年中的第几天。它可以返回从 1 到 365 或 366 (闰年)。

getEra()

获取在此日期适用的时代。例如:"CE "从第一年开始,"BCE "从零年开始。

LocalDate currentDate = LocalDate.now();
log.info("年份:{}", currentDate.getYear());
log.info("月份:{}", currentDate.getMonth());
//返回月份,从1到12
log.info("年份:{}", currentDate.getMonthValue());
//获取一个月中的第几号,为int类型 from 1 to 31
log.info("年份:{}", currentDate.getDayOfMonth());
log.info(currentDate.getChronology().toString());
log.info("{}", currentDate.get(ChronoField.DAY_OF_YEAR));

 INFO [main] (GetDateList.java:47) - 年份:2022
 INFO [main] (GetDateList.java:48) - 月份:JUNE
 INFO [main] (GetDateList.java:50) - 年份:6
 INFO [main] (GetDateList.java:52) - 年份:30
 INFO [main] (GetDateList.java:53) - ISO
 INFO [main] (GetDateList.java:54) - 181

LocalTime

全是时间,不包含日期

public static void testTime() {
    // 1. 获取当前时间,包含毫秒数 -----打印输出----- 21:03:26.315
    LocalTime localTime = LocalTime.now();
    // 2. 构建时间 -----打印输出----- 12:15:30
    LocalTime localTime1 = LocalTime.of(12, 15, 30);
    // 3. 获取当前时间,不包含毫秒数 -----打印输出----- 21:01:56
    LocalTime localTime2 = localTime.withNano(0);
    // 4. 字符串转为时间,还可以有其他格式,比如12:15, 12:15:23.233
    // -----打印输出----- 12:15:30
    LocalTime localTime3 = LocalTime.parse("12:15:30");
}

LocalDateTime

LocalDateTime就和原先的java.util.Date很像了,既包含日期,又包含时间,它经常和DateTimeFormatter一起使用。

public static void testDateTime() {
    // 1. 获取当前年月日 时分秒 -----打印输出----- 2018-01-29T21:23:26.774
    LocalDateTime localDateTime = LocalDateTime.now();
    // 2. 通过LocalDate和LocalTime构建 ----- 打印输出----- 2018-01-29T21:24:41.738
    LocalDateTime localDateTime1 = LocalDateTime.of(LocalDate.now(), LocalTime.now());
    // 3. 构建年月日 时分秒 -----打印输出----- 2018-01-29T19:23:13
    LocalDateTime localDateTime2 = LocalDateTime.of(2018, 01, 29, 19, 23, 13);
    // 4. 格式化当前时间 ----打印输出----- 2018/01/29
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
    System.out.println(formatter.format(localDateTime2));
}

使用LocalDateTime的with开头的方法可以设置相应的时间,小时,分钟等,比如:

// 设置分钟数
LocalDateTime localDateTime = LocalDateTime.now().withMinute(23);

TemporalAdjusters

该类是一个计算用的类,提供了各种各样的计算方法。比如某个月的第一天,某个月的最后一天,某一年的第一天,某一年的第几天等各种计算方法。该类内部实现基本上全都是通过JDK8的Lambda表达式来实现的。随便举一些例子,都很简单。

LocalDate localDate = LocalDate.now();
        
// 1. 本月第一天
LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());
// 2. 本月最后一天
LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());
// 3. 本年第一天
LocalDate firstDayOfYear = localDate.with(TemporalAdjusters.firstDayOfYear());
// 4. 下个月第一天
LocalDate firstDayOfNextMonth = localDate.with(TemporalAdjusters.firstDayOfNextMonth());
// 5. 本年度最后一天
LocalDate lastDayOfYear = localDate.with(TemporalAdjusters.lastDayOfYear());

System.out.println(firstDayOfMonth);
System.out.println(lastDayOfMonth);
System.out.println(firstDayOfYear);
System.out.println(firstDayOfNextMonth);
System.out.println(lastDayOfYear);

打印输出:

2018-01-01
2018-01-31
2018-01-01
2018-02-01
2018-12-31

参考链接: https://www.jianshu.com/p/f4abe1e38e09

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

what_2018

你的鼓励是我前进的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值