jdk新特性

lambda表达式

Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包

基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

Lambda表达式由三部分组成:

  1. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。

  2. ->:可理解为“被用于”的意思

  3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。

// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法

注意:

  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口

  2. 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
    定义方式:

    @FunctionalInterface
    interface NoParameterNoReturn {
    	//注意:只能有一个方法
    	void test();
    }
    
    @FunctionalInterface
    interface NoParameterNoReturn {
    	void test();
    	default void test2() {
    		System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
    	}
    }
    
    

Lambda表达式的基本使用

1.无返回值函数式接口

//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
    void test(int a);
}
//无返回值两个参数
@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a,int b);
}
public class TestDemo {
    public static void main(String[] args) {
        NoParameterNoReturn n = ()->{
            System.out.println("无参数无返回值");
        };
        n.test();

        OneParameterNoReturn o = (a)-> {
            System.out.println("无返回值一个参数"+a);
        };
        o.test(666);
        MoreParameterNoReturn m = (int a,int b)->{
            System.out.println("无返回值两个参数"+a+" "+b);
        };
        m.test(666,999);
    }
}

2.有返回值函数接口

//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
    int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
    int test(int a);
}
//有返回值多个参数
@FunctionalInterface
interface MoreParameterReturn {
    int test(int a,int b);
}
public class TestDemo {
    public static void main(String[] args) {
        NoParameterReturn n = ()->{
            return 666;
        };
        int ret1 = n.test();
        System.out.println(ret1);
        System.out.println("================");
        OneParameterReturn o = (int a)->{
            return a;
        };
        int ret2 = o.test(999);
        System.out.println(ret2);
        System.out.println("================");
        MoreParameterReturn m = (int a,int b)-> {
            return a+b;
        };
        int ret3 = m.test(10,90);
        System.out.println(ret3);
    }
}

3.语法精简

Lambda表达式的语法还可以精简,显得非常有逼格,但是可读性就非常差。

  1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略。

  2. 参数的小括号里面只有一个参数,那么小括号可以省略

  3. 如果方法体当中只有一句代码,那么大括号可以省略

  4. 如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字
    把上面的代码精简示例:

	public static void main(String[] args) {
        MoreParameterNoReturn moreParameterNoReturn = (a, b)->{
            System.out.println("无返回值多个参数,省略参数类型:"+a+" "+b);
        };
        moreParameterNoReturn.test(20,30);
        OneParameterNoReturn oneParameterNoReturn = a ->{
            System.out.println("无参数一个返回值,小括号可以省略:"+ a);
        };
        oneParameterNoReturn.test(10);
        NoParameterNoReturn noParameterNoReturn = ()->System.out.println("无参数无返回值,方法体中只有 一行代码");
        noParameterNoReturn.test();
        //方法体中只有一条语句,且是return语句
        NoParameterReturn noParameterReturn = ()-> 40;
        int ret = noParameterReturn.test();
        System.out.println(ret);
    }


三、变量捕获

Lambda 表达式中存在变量捕获 ,了解了变量捕获之后,我们才能更好的理解Lambda 表达式的作用域 。Java当中的匿名类中,会存在变量捕获

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这样会报错

总结

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读
优点:

  1. 代码简洁,开发迅速
  2. 方便函数式编程
  3. 非常容易进行并行计算
  4. Java 引入 Lambda,改善了集合操作
    缺点:
  5. 代码可读性变差
  6. 在非并行计算中,很多计算未必有传统的 for 性能要高
  7. 不容易进行调试

接口中新增的方法

jdk1.8后对接口做了增加,接口中可以有默认方法和静态方法’

interface name{
	静态常量;
    抽象方法;
    默认方法;
    静态方法;
}

2.默认方法

2,1为什么要增加默认方法

​ 接口中如果要新增抽象方法,所有实现类必须要重写这个方法,不利于接口的扩展.

2.2接口中默认方法的语句格式

interface 接口名{
	修饰符 default 返回值类型 方法名{
	
	}
}

2.3接口中的默认方法是的使用方式

  1. 实现类直接调用接口的默认方法.
  2. 实现类重写接口的默认方法.

3.静态方法

3,1语法规则

interface 接口名{
    修饰符 static 返回值类型 方法名{
        方法体;
    }
}

3.2静态方法的使用

接口的静态方法在实现类中是不能被重写的,调用的话只能通过接口类型来实现:接口名.静态方法();

3.3两者的区别

1.默认方法通过实例对象调用,静态方法通过接口名调用

2.默认方法可以被继承,实现类可以直接调用默认方法,也可以重写默认方法

3.静态方法不能被继承,实现类不能重写接口的静态方法,只能使用接口名调用

函数式接口

1.函数式接口的由来

使用lambda表达式的前提是需要函数式接口,而lambda表达式不关心接口名,抽象方法名,只关心抽象方法的参数列表和返回值类型

因此jdk中提供了大量的常用的函数式接口.

2.函数式接口的介绍

2.1supplier

无参有返回值接口

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

2.2consumer

有参无返回值的

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
    //用来对数据进行后续操作
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

2.3function

有参有返回值的

public interface Function<T, R> {

    R apply(T t);

   
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

2.4Predicate

返回值为boollean值的

public interface Predicate<T> {

   
    boolean test(T t);

  
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

 
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

  
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

方法引用

1.为什么要用

1.lambda表达式冗余

package org.example.fun;

import java.util.Arrays;
import java.util.function.Consumer;

public class ConsumerTest {
    public static void main(String[] args) {
        test(ConsumerTest::sum);
    }
    public static void sum(int[] a){
        int sum=0;
        for (int i : a) {
            sum += i;
        }
        System.out.println(sum);
    }

    public static void test(Consumer<int[]> consumer){
        int[] a={1,4,5,6,7};
        consumer.accept(a);
    }
}

2.方法引用的格式

符号表示 ::

符号说明:双冒号为方法应用运算符,而它所在的表达式被称为方法引用

常见的引用方式:

  1. 对象:方法名

    public class Test01 {
        public static void main(String[] args) {
            Date now = new Date();
            Supplier<Long> supplier= now::getTime;
            System.out.println(supplier.get());
        }
    }
    
  2. 类名:静态方法

    public class Test01 {
        public static void main(String[] args) {
            Supplier<Long> supplier= System::currentTimeMillis;
            System.out.println(supplier.get());
        }
    }
    
  3. 类名::引用实例方法

    public class Test01 {
        public static void main(String[] args) {
            BiFunction<String,Integer,String> function=String::substring;
            String hello = function.apply("hello", 3);
            System.out.println(hello);
        }
    }
    
  4. new 类名::new调用 的构造器

  5. new string[]::new 调用数组的构造器

stream API

1.集合处理数据的弊端

​ 当我们在需要对集合中的元素进行操作时,除了必须的添加,删除,获取外,最典型的就是集合的遍历

public class StreamTest01 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("张三", "李四", "王五");
        ArrayList<String> strings = new ArrayList<>();
        //1.获取所有张的信息
        for (String s : list) {
            if (s.startsWith("张")){
                strings.add(s);
            }
        }
        System.out.println(strings);
    }
}
public class StreamTest01 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("张三三", "李四", "王五");
        ArrayList<String> strings = new ArrayList<>();
        //1.获取所有张的信息
        /*for (String s : list) {
            if (s.startsWith("张")){
                strings.add(s);
            }
        }*/
        //所有姓张并且长度为三
        list.stream()
                .filter(s->s.startsWith("张"))
                .filter(s->s.length()==3)
                .forEach(System.out::println);
    }
}

stream和io没有任何关系,更像一个流水线,通过多个过程加工数据.

stream的来各种获取方式

根据collection获取

collection接口中加入了default方法stream,collection接口下的所有实现都可以通过stream获取Stream流.

map接口没有实现collection接口,可以根据map获取对应的key,value的集合再获取stream

通过stream的of方法

在实际开发中.不可避免的会操作数组中的数据,由于数组对象不能添加默认方法,所有stream接口中提供了静态方法of

 Stream<String> stream = Stream.of("1", "2", "2");
        String[] strings={"aa", "bb", "cc", "dd"};
        Stream<String> strings1 = Stream.of(strings);
        strings1.forEach(System.out::println);
        //基本数据类型的数组是不行的
        int[] a={1,2,3,4};
        Stream.of(a).forEach(System.out::println);

在这里插入图片描述

注意事项

stream只能操作一次,stream方法返回的是新的流,stream不调用终结方法,中间的操作不会执行.

foreach

用来遍历流中的数据的

void forEach(Consumer<? super ?> action)

该方法接受一个Consumer接口,会将每一个流函数处理

conut

long count()
public class StreamTest03 {
    public static void main(String[] args) {
        long count = Stream.of("1", "2", "2").count();

    }
}

用来统计其中的元素个数的

fillter

用来过滤数据,返回符合条件的.

 Stream<T> filter(Predicate<? super T> predicate);

limit

limit方法可以对流进行截取

  Stream<T> limit(long maxSize);

skip

如何希望跳过前面几个元素则可以使用skip

Stream<T> skip(long n);

map

如果我们需要将流中的元素映射到另一个流中,可以使用map方法

<R> Stream<R> map(Function<? super T, ? extends R> mapper);
public class StreamTest03 {
    public static void main(String[] args) {
        Stream.of("1", "2", "2").map(Integer::parseInt)
                .forEach(System.out::println);
    }
}

sorted

Stream<T> sorted();

可以对流对象进行排序

distinct

去掉重复数据

match

find

max和min

reduce方法

 Integer sum = Stream.of(1, 2, 3).reduce(0, Integer::sum);

map和reduce组合

maptoint :Integer占用的内存比int多很多,为了提高代码效率可以先将integer数据转换为int数据让后再操作

public class StreamTest03 {
    public static void main(String[] args) {
       Integer[] arr={1,2,3};
         Stream.of(arr).mapToInt(Integer::intValue)
                .filter(i->i>=3)
                .forEach(System.out::println);
    }
}

contat

如何有两个流想要合并可以使用stream的静态方法

  public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);

        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }

stream结果收集

public class StreamReduceTest {
    public static void main(String[] args) {
        List<Integer> collect = Stream.of(1, 2, 3)
                .collect(Collectors.toList());
        System.out.println(collect);
        Set<Integer> collect1 = Stream.of(1, 2, 3)
                .collect(Collectors.toSet());
        //具体的类型转化如arraylist,hashset
        ArrayList<Integer> collect2 = Stream.of(1, 2, 3)
                .collect(Collectors.toCollection(ArrayList::new));
    }
}

对流的数据做聚合计算

当我们使用stream流处理数据后,可以数据库的聚合函数一言对某个字段进行操作

optional类

主要解决空指针

以前对null的处理

String userName=null;
        if(userName!=null) {
            System.out.println(userName.length());
        }else {
            System.out.println("string is empty");
        }

optional是一个没有子类的工具类,optionnal是一个可以为空的容器对象,它的主要作用就是避免null检查,防止出现空指针异常

获取方式

public class OptionalTest01 {
    public static void main(String[] args) {
        //通过of获取
        Optional<String> op1 = Optional.of("张三");
        //of方法不支持null
       // Optional<Object> o = Optional.of(null);
        //ofNullable可以传入空
        Optional<Object> o = Optional.ofNullable(null);
        //将空值封装成对象
        Optional<Object> empty = Optional.empty();
    }
}

常用的用法

 Optional<String> op1 = Optional.of("张三");
        Optional<String> op2 = Optional.empty();
        //获取optional里面的值,get()如果optional有值则返回,否则就抛出NoSuchElementException
        String s = op1.get();
        //isPresent判断是否包含值,包含返回true不包含返回false
        //orEls如果是空值则会替换
        String s1 = op1.orElse("李四");
        System.out.println(s1);
        op2.orElseGet(()->"aaa");
        System.out.println(op2);
//根据person对象将name大写返回 
public static String test03(Optional<Person> optional){
        if(optional.isPresent()){
            return optional.map(Person::getName)
                    .map(String::toUpperCase)
                    .orElse(null);
        }
        return null;

    }

新时间日期api

  1. 设计不合理,在java.util和java.sql的包中都含有日期类,java.util同时包含日期和时间的,java.sql.date仅仅包含日期

  2. 线程不安全,java.util.date是线程不安全的

  3. 时区处理麻烦,日期并不提供国际化,灭有时区支持

    在这里插入图片描述

常用的方法

package org.example.date;

import com.sun.org.apache.xpath.internal.SourceTree;

import javax.xml.soap.Node;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;

public class DateDemo01 {
    public static void main(String[] args) {
        //创建指定的日期
        LocalDate localDate = LocalDate.of(2023, 9, 22);
        System.out.println(localDate);
        //获取当前日期
        LocalDate now = LocalDate.now();
        System.out.println(now);
        //根据localDate对象获取对应的日期信息
        System.out.println("年"+now.getYear());
        System.out.println("月"+now.getMonth().getValue());
        System.out.println("日"+now.getDayOfMonth());
        System.out.println("周"+now.getDayOfWeek().getValue());
        time();
        dateTime();

    }
    public static void time(){
        //获取指定的时间
        LocalTime localTime = LocalTime.of(10, 46, 33, 1242);
        System.out.println(localTime);
        //获取当前时间
        LocalTime now = LocalTime.now();
        System.out.println(now);
        //获取时间
        System.out.println(now.getHour());
        System.out.println(now.getMinute());
        System.out.println(now.getSecond());
        System.out.println(now.getNano());

    }
    public static void dateTime(){
        //获取指定的日期时间
        //LocalDateTime.of()
        //获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
        //获取日期时间信息
        //now.get()
    }
}

instant类

时间戳类,内部保存了从1970:1:1:00:00:00的秒和纳秒

duration

用来计算时间差
);
dateTime();

}
public static void time(){
    //获取指定的时间
    LocalTime localTime = LocalTime.of(10, 46, 33, 1242);
    System.out.println(localTime);
    //获取当前时间
    LocalTime now = LocalTime.now();
    System.out.println(now);
    //获取时间
    System.out.println(now.getHour());
    System.out.println(now.getMinute());
    System.out.println(now.getSecond());
    System.out.println(now.getNano());

}
public static void dateTime(){
    //获取指定的日期时间
    //LocalDateTime.of()
    //获取当前日期时间
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);
    //获取日期时间信息
    //now.get()
}

}


### instant类

时间戳类,内部保存了从1970:1:1:00:00:00的秒和纳秒

### duration

用来计算时间差
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值