JAVA基础知识七(补充知识:lambda表达式、正则表达式)

十二、lambda表达式

1.接口新特性

在jdk1.8前:常量 和 抽象方法

成员都是公共的,修饰也是固定的

实现类必须实现所有的抽象方法,否则还是抽象类

在jdk1.8后:允许有带有方法体的方法。

默认方法 default修饰

静态方法 static修饰

1.默认方法:

1.实现类可以重写也可以不重写

2.实现类中可以直接调用默认方法

3.重写了默认方法,想要调用父接口中的,父接口名.super.默认方法名().

4.实现类实现了多个接口,接口中有相同的方法定义,实现类必须重写该方法

想要调用某个父接口中的默认方法,父接口名.super.默认方法名().

5.一个类继承了一个父类并实现了接口,父类和父接口中有相同的默认方法,优先找类

这样定义接口,发现接口与抽象类越来越像,因此接口有要替代抽象类的趋势。

因此类和类是继承,耦合度高,接口和类是实现关系,耦合度要低。

2.静态方法:

接口名.静态方法名。

静态方法不被实现类继承,因此实现类不能调用。

静态方法只能访问静态,非静态既可以访问静态也可以访问非静态。

jdk9.0:

接口中可以有私有方法。

这种方法就是只能在当前接口中使用,外部其他类不让其使用。

3.函数式接口

概念: 接口中有且只有一个抽象方法的,叫做函数式接口(默认方法和静态不考虑)

使用Lambda表达式的前提就是该接口是一个函数式接口。

验证一个接口是否是函数式接口: @FunctionalInterface

在定义接口的上边(interface),写该注解,如果是编译没问题,如果不是,编译时期就报错

自定义函数式接口:

@FunctionalInterface

修饰符 interface 接口名<T,U,...>{

抽象方法; 1个

默认方法 多个

静态方法 多个

}

public class Demo3 {
    public static void main(String[] args) {
        //调用方法
        String s = toUpperStr("hello", new ImInter<String>() {
            @Override
            public String method(String s) {
                return s.toUpperCase();
            }
        });
        String s1 = toUpperStr("world", ss -> ss.toUpperCase());
        System.out.println(s1);
     }
    
     //定义方法,将参数上的字符串转为大写形式
    public static  String  toUpperStr(String str,ImInter<String> im){
        return im.method(str);
    }
}
​
//自定义函数式接口
@FunctionalInterface
interface  ImInter<T>{
    T  method(T t);
​
    default  void show(){}
    static void  function(){}
}

4.核心函数式接口

消费型接口: Consumer.andThen先执行左边,再执行右边

Consumer<T>

void accept(T t) :对t进行处理操作,操作完成后就结束。

//打印字符串的长度
        Consumer<String> con = s -> System.out.println(s.length());
        con.accept("asd");

函数型(功能型)接口:

Function<T,R> fun.andThen(x -> x+2); 先算fun fun.compose(x -> x+2); 先算参数

R apply(T t) : 对t进行各种计算,最终得到一个R类型的结果

//将字符串变成大写形式
        Function<String, String> fun = s -> s.toUpperCase();
        System.out.println(fun.apply("abc"));

断言型接口: Predicate 的 and 与 or 或 negate 非

Predicate<T>:

boolean test(T t):对t进行各种判断,最终得到一个boolean类型的结果。

//判断字符串的长度是否大于5
        Predicate<String> pre = s -> s.length() > 5;
        System.out.println(pre.test("asdaffd"));

供给型接口:

Supplier<T> :

T get(): 返回T类型数据

 //返回字符串abc
        Supplier<String> su = () -> "abc";
        System.out.println(su.get());

2.介绍

Lambda表达式出现是模拟的数学中的函数,数学中的函数最终会有一个结果,即是一个数值,Lambda表达式最终也会有一个值。实际就是一个匿名实现类的对象,也就是匿名内部类的简写格式,也可以当做一个数据直接进行传递。

好处:代码简洁,效率高(不会有对应的class文件去创建)

前提:有接口,接口中有且只有一个抽象方法(默认方法和静态方法不考虑)

格式:(参数列表) -> {方法体语句;};

说明:

(参数列表) : 接口中的抽象方法的参数列表

-> :Lambda表达式的固定符号

{方法体语句;} : 接口中抽象方法的具体实现代码

1.案例

1.方法无参数,有返回值

 new Thread  (()->System.out.println("哈哈哈")).start();

2.有参数,无返回值

Consumer<String> con = s -> System.out.println(s.length());
        con.accept("asd");

3.无参数,有返回值

Callable<String> call = ()->"hello";
        System.out.println(call.call());

4.有参数,有返回值

Comparator<Integer> com = (Integer a , Integer b ) -> Integer.compare(a,b);

省略规则:

1.左右各为一的时候可以省略对应的括号

2.左侧的参数类型可以省略,注意没有参数小括号不能省略

3.右侧语句大于等于2的时候不能省略大括号

4.有return,并且只有一条语句,那么return和大括号一起省略

3.StreamAPI

1.作用

可以对数据源进行想要的计算,比如:过滤、去重复..,最终返回的是一个新的Stream。

2.特点

1.不会改变数据源,而是得到新的Stream。

2.可以对数据源进行一系列流水线似的操作(类似于车间)

3.是一个惰性求值,只有看到终止命令才进行一系列的流水线计算

4.数据源是:数组或集合

5.数据源是存储数据的,而Stream是用来做计算的

6.Stream一旦执行了终止操作,Stream不可以再使用。

3.步骤

1.获取Stream对象 2.一系列流水线似的操作(方法) 3.终止操作

说明:不是一定要有流水线操作,可以只有第一步和第三步

只有1和2步,没有3步,那么不做计算。

获取Stream对象:

包名:java.util.stream;

Collection.stream()

Arrays.stream()

Stream.of()

Map.keySet().stream()

Map.values().stream()

Map.entrySet().stream()

    Stream<String> s1 = list.stream();      //list 方法
    Stream<String> s2 = Stream.of(arr);     //Stream类 方法
    Stream<String> s3 = Arrays.stream(arr);     //数组方法

中间操作:

filter(Predicate) :过滤

获取到Stream对象,相当于有了数据源中的所有数据,每个数据会进行filter计算

符合就要,不符合不要,因此得到的新的Stream中存储的就是满足要求的数据。

distinct() :去重

map(Function) : 对数据运行function的计算操作

limit(int num) : 从0-num个

skip(int num) :从num--末尾个

sorted()

sorted(Comparator)

终止方法:

foreach(Consumer)

count(): 统计个数

collect(Collctor):收集

4.注解

1.概念

Annotation,称之为叫做元数据,属于一种代码级别的注释。在jdk5.0版本新增的一个特性。与类、接口、枚举是同级别的,可以使用在类、方法、属性、参数、局部变量、包的前边,可以参与代码的执行。

2.作用

1.替代配置文件 (eg:Servlet xml 注解)

2.制作帮助文档(javadoc) @author @since...

3.在编译时期做检测 @Override @FunctionalInterface...

常见注解:

@Override @FunctionalInterface @Deprecated(已过时方法,不建议使用) @Test...

3.元注解

修饰注解的注解。

@Target 被修饰的注解能在哪里使用

常用的值: ElementType.TYPE

ELementType.METHOD...

@Retention 被修饰的注解的生命周期

RetentionPolicy.SOUCE:参与编译,但不在class文件中

RetentionPolicy.CLASS:参与编译,在class中,但是不执行

RetentionPolicy.RUNTIME:参与编译和运行

@Documented 是否参与生成版主文档

@Inherited 是否被继承

4.自定义注解

格式:

修饰符 @interface 注解名{

属性;...

}

注解其实一个接口,是java.lang.annotation.Anotationde的子接口。

编写是不要手动写继承,编译器会自动补全。

属性:可以参与执行,因此作用是用来传递参数数据的,使注解的功能增强。

格式:

数据类型 属性名();

数据类型 属性名() default 数据值;

注解中一旦有属性,这个属性没有默认值,那么使用时必须给属性赋值

如果有默认值,赋值不赋值都可以。

数据类型:

基本类型、String、枚举、Class、注解.

以上这些类型的数组形式。

特殊属性名:

value:在使用时可以省略value=,直接写属性值即可,哪怕是数组形式也是如此。

还有其他属性,这些属性都有默认值,那么可以省略value=,前提是这些属性不重新

赋值。其他属性至少有一个没有默认值,必须写上value=

反射注解:

1.获取使用注解的类的Class对象

2.获取使用注解的成员对象

3.获取对应的注解

    public static void main(String[] args) throws NoSuchMethodException {
        //获取CLASS对象
        Class<Demo1> c = Demo1.class;
        //获取方法
        Method m = c.getDeclaredMethod("show");
        //获取方法的注解
        Myinter1 annotation = m.getAnnotation(Myinter1.class);
        int age = annotation.age();
        String value = annotation.value();
        System.out.println(age+"..."+value);
        System.out.println(annotation);
    }
    //使用自定义注解时需要给属性赋值
    @Myinter1(value = "za",age = 30)
    void show(){}
​
    @Myiter2(name = "s")
    void test(){}
​
​
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface  Myinter1{
    String value();
    int age () default 20 ;
}
​
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Myiter2{
    String name();
}

十三、正则表达式

1.概念

正则表达式就是字符串,只不过是特定规则的字符串

2.方法

1.判断

boolean  str.matches(String reg)
    //判断此字符串是否符合这个正则表达式,如果符合返回true,否则是false

2.替换 replaceAll

String   str.replaceAll(String reg,String replacement)  
    //从头开始,依次读取字符,查看是否符合规则,只要符合就替换

3.分割

String[]  str.split(String reg)
    //从头开始,依次读取字符,查看是否符合规则,只要符合就切割

3.正则符号

1.转义类字符

//字符 
​
x       字符 x 
\\      反斜线字符 
\0n     带有八进制值 0 的字符 n (0 <= n <= 7) 
\0nn    带有八进制值 0 的字符 nn (0 <= n <= 7) 
\0mnn   带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) 
\xhh    带有十六进制值 0x 的字符 hh 
\uhhhh  带有十六进制值 0x 的字符 hhhh 
\t      制表符 ('\u0009') 
\n      新行(换行)符 ('\u000A') 
\r      回车符 ('\u000D') 
\f      换页符 ('\u000C') 
\a      报警 (bell) 符 ('\u0007') 
\e      转义符 ('\u001B') 
\cx     对应于 x 的控制符 

2.字符类

//字符类 
​
[abc]       a、b 或 c(简单类) 
[^abc]      任何字符,除了 a、b 或 c(否定) 
[a-zA-Z]    a 到 z 或 A 到 Z,两头的字母包括在内(范围) 
    
//注意:一对中括号代表一个字符,上边中的abc...仅仅是举例子,实际可以换有效字符

3.预定义字符类

.       任何字符(与行结束符可能匹配也可能不匹配) 
\d      数字:[0-9] 
\D      非数字: [^0-9] 
\s      空白字符:[ \t\n\x0B\f\r] 
\S      非空白字符:[^\s] 
\w      单词字符:[a-zA-Z_0-9] 
\W      非单词字符:[^\w] 
​

4.边界匹配

//边界匹配器 
​
^ 行的开头 
$ 行的结尾 
\b 单词边界 
\B 非单词边界 
\A 输入的开头 
\G 上一个匹配的结尾 
\Z 输入的结尾,仅用于最后的结束符(如果有的话) 
\z 输入的结尾 

5.数量词

X? X,一次或一次也没有 
X* X,零次或多次 
X+ X,一次或多次 
X{n} X,恰好 n 次 
X{n,} X,至少 n 次 
X{n,m} X,至少 n 次,但是不超过 m 次 

4.单例设计模式

一个常规类,理论上可以创建n个对象,没有上限(不考虑内存)。

目标:

实现一个类无论怎么使用,对象个数永远是那个。

要保障对象在内存中的唯一性。

步骤:

1.构造方法私有化

2.在类中创建一个该类对象

3.定义方法,返回该类对象

1.饿汉式

    //饿汉式
class Single {
    //因为不想外界创建对象,所有私有化构造方法
    private Single(){}
    //内部提前创建对象
    // private不希望外界可以创建对象,
    // static因为下面的方法是静态的,所以这个也得是静态
    // final为了使这个类就一个对象,每次调用都是这个,所以final修饰,锁定这个对象的引用地址
    private final static Single s = new Single();
    //定义方法返回对象,不能创建对象所有让这个方法Static修饰,直接使用类名调用
    public static Single getInstance(){
        return s ;
    }
}

特点:类一加载,就创建了该类的对象。

弊端: 对象有可能不使用,因此可能会有空间浪费。

好处:多线程模式下,没有线程安全问题。

2.懒汉式

    //懒汉式
class Single{
    //1,私有化构造方法
    private  Single(){
    }
    //2.创建对象引用
    private  static Single s = null;
    //3.定义方法,返回该类对象
    public  static  Single  getInstance(){
        if(s == null){
           synchronized (Single.class) {  //t1 t2
               if (s == null)
                    s = new Single();
           }
       }
       return s;
    }
}

特点:类加载时,不会创建对象,调用getInstance方法时才会创建对象,(延时加载).

好处:因此这种方式不会有空间浪费。

弊端:多线程模式下,可能会有线程安全问题

3.懒汉式多线程加锁

public class Demo4 {
    public static void main(String[] args) {
        /*Single s1 = Single.getInstance();
        Single s2 = Single.getInstance();
        System.out.println(s1 == s2); //比较地址值*/
        MyRun my = new MyRun();
        new Thread(my).start();
        new Thread(my).start();
​
    }
}
class MyRun implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Single.getInstance());
    }
}
​
//懒汉式
class Single{
    //1,私有化构造方法
    private  Single(){
    }
    //2.创建对象引用
    private  static Single s = null;
    //3.定义方法,返回该类对象
    public  static  Single  getInstance(){
        if(s == null){                                  //双重判断提高效率
           synchronized (Single.class) {  //t1 t2
               if (s == null)
                    s = new Single();
           }
       }
       return s;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值