Java基础 — 正则表达式+函数式编程

一、正则表达式

正则表达式

正则表达式是用来匹配字符串的,Java内置了正则表达式的支持。

正则表达式可以用字符串来描述规则,用来匹配字符串。一个正则表达式就是一个描述规则的字符串。

使用正则表达式可以快速判断给定的字符串是否符合匹配规则。

正则表达式是一套标准,可以用于任何语言,Java标准库内置了正则表达式引擎。

java 复制代码
String regex="20\\d\\d";
        System.out.println("2020".matches(regex));

匹配规则

如果正则表达式中有特殊字符,需要用"/"转义。

想匹配非ASCII字符,如中文,用\u####的十六机制表示。

"."可以匹配任意字符,仅限一个字符。

"\d"可以匹配0~9数字,仅限一个字符。

"\w"可以匹配一个字母,数字或者下划线。

"\s"可以匹配一个空格字符、Tab键。

"\D"可以匹配一个非数字。

修饰符(重复匹配)

"A*":可以匹配任意个字符,如"A\d*",可以匹配为A,A0,A380;

"A+":可以匹配至少1个字符;

"A?":可以匹配0个或1个字符;

"A{n}":可以精确指定n个字符;

复杂匹配规则

用正则表达式进行多行匹配时,用"^"表示开头,"$"表示结尾;

匹配指定范围:

使用[......]可以匹配到范围内的字符,如[123456789]\d或[1-9]\d,开头就不能取到0;

或规则匹配:

"|",AB|CD

使用括号

a\s(b|c|d),也就是 a\sb|a\sc|a\sd

分组匹配

简单的String。matches()方法,只能简单地匹配字符串,无法将提取出字串。可以使用Pattern类和Matcher类,提取子串。

正则表达式用(......)分组可以通过Matcher对象快速提取子串。

java 复制代码
Pattern p = Pattern.compile("(\\d{3,4})\\-(\\d{7,8})");
        Matcher m = p.matcher("010-1234567");
        if (m.matches()){    //尝试整个序列和模式匹配
            System.out.println("Yes");
            System.out.println(m.group(0));    //返回上一个匹配操作期间匹配的子序列
            System.out.println(m.group(1));
            System.out.println(m.group(2));
        }
        else{
            System.out.println("匹配失败!");
        }

非贪婪匹配

正则表达式匹配默认使用贪婪匹配,就是从左到右进行匹配,贪婪地满足前面的,才到后面的。

可以使用"?"表示对某一规则进行非贪婪匹配,如 "(\\d+?)(0*)"

分割字符串

使用正则表达式分割字符串可以实现更加灵活的功能。String。split()方法传入的正是正则表达式。

java 复制代码
String a="a b c";
        for (String x:a.split("\\s")){
            System.out.print(x+" ");
        }
        System.out.println();
        a="a b  c";
        for (String x:a.split("\\s")){
            System.out.print(x+" ");
        }
        System.out.println();
        a="a, b ;; c";
        for (String x:a.split("[\\,\\;\\s]+")){
            System.out.print(x+" ");
        }

搜索字符串

使用正则表达式可以搜索字符串

java 复制代码
String s = "the quick brwn fox jumps over the lazy dog.";
        Pattern p = Pattern.compile("\\wo\\w");
        Matcher m = p.matcher(s);   //创建一个匹配器对象
        while (m.find()) {  //查找字符串序列中与模式匹配的下一个子序列
            String sub = s.substring(m.start(), m.end());   //返回上一个匹配操作期间匹配的子序列的起始和结束索引
            System.out.println(sub);
        }

替换字符串

使用正则表达式替换字符串可以直接调用String.replaceALL("\\s+"," ");

二、函数式编程

函数式编程

函数式面向过程的程序设计的基本单元

Java不支持单独定义函数,但是可以将静态方法视为独立函数,对象方法看作自带this参数的函数。

函数式编程就是一种抽象程度很高的编程范式。

函数式编程的特点,允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

Lambda基础

函数式编程是把函数作为基本运算单元,函数可以作为变量,可以接收函数,返回函数。我们经常把支持函数式编程风格称为Lambda表达式。

Lambda表达式

Java8开始,可以用Lambda表达式替换单方法接口,大大简化代码!!

java 复制代码
// 只需要写出方法定义,可以省略参数类型,替换之前的写法
        String[] s=new String[] {"apple0","orange1","banana11","Lemon1111"};
        Arrays.sort(s,(s1,s2)->{
            return s2.length()-s1.length();
        });
        System.out.println(Arrays.toString(s));

方法引用

接口和某个方法签名一致,就可以直接传入方法引用。一个接口方法和一个静态方法,除了方法名外,方法参数一致,返回类型相同,就可以说两者的方法签名一致,可以直接吧方法名作为Lambda表达式传入。

Stream

使用Stream

Java8开始,引入了一个全新的流式API:Stream API,位于java.util.stream包

这个Stream不同于java.io的Inputstream和OutputStream,它代表的是任意Java对象的序列。

Stream输出的元素可能并没有预先存储在内存中,而是实时计算出来的;是惰性计算;

List存储的每个元素都是已经存储在内存中的某个Java对象。

Stream可以看作是一个容器,数据类型。

Stream特点:

它可以存储有限个或者无限个元素,因为它是惰性计算,所以它是根据实时需要进行计算。

一个Stream可以轻易地转换成为另一个Stream,而不是修改原Stream本身,实际上只存储了转换规则,并没有任何计算发生。

Stream API 提供了一套新的流式处理的抽象序列

Stream API 支持函数式编程和链式操作

Stream 可以表示无限序列,并且大多数情况下是惰性求值的。

每个Steam只会被操作一次,就是当完成最终计算后,就会被关闭

StreamAPI的基本用法:

创建一个Stream,然后做若干次转换,最后调用一个求值方法获取真正计算的结果。

创建Stream

这两种方法都是把一个现有的序列变为Stream,它的元素是固定的

静态方法stream.of()创建Stream,但是只能传入和输出确定的元素

java 复制代码
        Stream<Integer> a = Stream.of(12, 1, 2, 4);
        a.forEach(System.out::print);
        System.out.println();
        //基于数组或者集合创建Stream
        Stream<String> b = Arrays.stream(new String[]{"A", "B", "C", "D"});
        b.forEach(System.out::print);
        System.out.println();
        Stream<String> c = List.of("X", "Y", "Z").stream();
        c.forEach(System.out::print);
        System.out.println();

基于Supplier方法
通过Stream.generate()方法 ,创建Stream,需要传入一个Supplier对象

在使用forEach()或count()这些最终求值操作时,要将这个无限序列变成有限序列,可以使用limit()方法,再求最终值。

java 复制代码
        Stream<Integer> d = Stream.generate(new Natual());
        d.limit(10).forEach(s-> System.out.print(s+" "));
        System.out.println();

通过一些API提供的接口 ,直接获得Stream

Files类的lines()方法可以把一个文件变成一个Stream,每个元素代表文件的一行内容。

java 复制代码
Stream<String> e = Files.lines(Paths.get("D://name"));

正则表达式的Pattern对象有一个splitAsStream()方法,可以直接把一个长字符串分割为Stream序列而不是数组。

java 复制代码
        Pattern p =Pattern.compile("\\s+");
        Stream<String> f = p.splitAsStream("My name is olderhard");
        f.forEach(System.out::println);

针对基本类型

因为Java泛型不支持基本泛型,要是使用Stream<Integer>又会产生频繁的装箱、拆箱操作。

Java标准库提供了IntStream、LongStream、DoubleStream三种使用基本类型的Stream,提供运行效率

java 复制代码
        IntStream g=Arrays.stream(new int[]{1,2,3});
        g.forEach(System.out::print);

    }
}
class Natual implements Supplier<Integer>{
    int a=0,b=1,c=0;
    @Override
    public Integer get() {
        c=a+b;
        a=b;
        b=c;
        return a;
    }
}

使用map

使用Stream.map()是Stream最常用的一个转换方法,它把一个Stream转换为另一个新的Stream

map操作,把一个Stream的每个元素一一对应到应用了目标函数的结果上

java 复制代码
        Stream<Integer> a1 = Stream.of(1, 2, 3, 4, 5);
        //a1.forEach(System.out::print);
        //System.out.println();
        Stream<Integer> b = a1.map(n -> n * n);
        b.forEach(s-> System.out.print(s+" "));
        System.out.println();

利用map(),完成字符串的操作,以及任何Java对象都是非常有用的

java 复制代码
        List.of("  Apple ", " pear ", " ORANGE", " BaNaNa ")
                .stream()
                .map(String::trim) // 去空格
                .map(String::toLowerCase) // 变小写
                .forEach(System.out::println); // 打印

使用filter

Stream.filter()是Stream的另一个常用转换方法

所谓filter操作,就是对一个Stream的所有元素一一进行测试,不满足条件的删去,剩下的构成一个新的Stream。

java 复制代码
        IntStream.of(1,2,3,4,5,6,7,8,9)
                .filter(n->n%2!=0)
                .forEach(s-> System.out.print(s+" "));

filter()除了常用于数值外,也可应用于任何Java对象

使用reduce

Stream.reduce()是Stream的一个聚合方法,它可以把一个Stream的所有元素按照聚合函数聚合成一个结果。

聚合运算会不断请求它的上游输出它的每个元素,之后上游经过一系列的转换,最终被reduce()聚合出结果。

聚合操作是真正需要从Stream请求数据的,对一个Stream做聚合计算后,结果就不是一个Stream,而是其他的一个Java对象。

java 复制代码
        int sum= Stream.of(1,2,3,4,5,6,7,8,9,10).reduce(0,(res,n)->res+n);
        System.out.println(sum);

除了可以对数值进行累积计算外,还可以灵活运用reduce()对Java对象进行操作

java 复制代码
List<String> props = List.of("profile=native", "debug=true", "logging=warn", "interval=500");
        Map<String, String> q = props.stream()
                // 把k=v转换为Map[k]=v:
                .map(kv -> {
                    String[] ss = kv.split("\\=", 2);
                    return Map.of(ss[0], ss[1]);
                })
                // 把所有Map聚合到一个Map:
                .reduce(new HashMap<String, String>(), (m, kv) -> {
                    m.putAll(kv);
                    return m;
                });
        // 打印结果:
        q.forEach((k, v) -> System.out.println(k + " = " + v));
    }

输出集合

将Stream变为List或者其他都是个聚合操作,它会强制Stream输出每个元素。
输出为List

将Stream中每个元素收集到List,使用filter方法过滤,使用collector方法收集

java 复制代码
 Stream<String> stream = Stream.of("apple", "", null, "pear", " ", "orange");
        List<String> collect = stream.filter(s -> s != null && !s.isBlank()).collect(Collectors.toList());
        System.out.println(collect);

输出为数组

java 复制代码
Stream<String> stream1 = Stream.of("apple", "", null, "pear", " ", "orange").filter(s -> s != null && !s.isBlank());
        String [] a=stream1.toArray(String[]::new);
        System.out.println(Arrays.toString(a));

输出为Map

java 复制代码
        Stream<String> stream2 = Stream.of("APPL:Apple", "MSFT:Microsoft");
        Map <String,String> map = stream2.collect(Collectors.toMap(s->s.substring(0,s.indexOf(':')), s->s.substring(s.indexOf(':')+1)));
        System.out.println(map);

分组输出

java 复制代码
        List<String> list = List.of("Apple", "Banana", "Blackberry", "Coconut", "Avocado", "Cherry", "Apricots");
        Map<String, List<String>> groups = list.stream()
                .collect(Collectors.groupingBy(s -> s.substring(0, 1), Collectors.toList()));
        System.out.println(groups);

其他操作
排序

java 复制代码
对Stream的元素进行排序
        List<String> l = List.of("orange", "apple", "Banana")
                .stream()
                .sorted()
                .collect(Collectors.toList());
        System.out.println(l);

去重

对一个Stream的元素进行去重

java 复制代码
        List<String> l1 = List.of("orange", "orange", "Banana")
                .stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println(l1);

截取

把一个无限的Stream转换成有限的Stream,skip()用于跳过当前Stream的前N个元素,limit()用于截取当前Stream最多N个元素。

java 复制代码
  List<String> l2 = List.of("orange", "apple", "Banana","pear","water")
                .stream()
                .skip(1)
                .limit(3)
                .collect(Collectors.toList());
        System.out.println(l2);

合并

将两个Stream合并为一个Stream可以使用Stream的静态方法concat()

java 复制代码
        Stream<Integer> stream1 = List.of(1, 2, 3).stream();
        Stream<Integer> stream2 = List.of(4, 5, 6).stream();
        Stream<Integer> concat = Stream.concat(stream1, stream2);
        System.out.println(concat.collect(Collectors.toList()));

其他一些方法就不细说了

相关推荐
stormsha10 分钟前
Java中使用接口实现回调函数的详解与示例
java·开发语言·python
Xinan_____13 分钟前
Linux——k8s组件
java·linux·kubernetes
什码情况15 分钟前
报数游戏 - 华为OD统一考试(E卷)
java·python·算法·游戏·华为od·笔试·华为od机试
钗头风27 分钟前
(一)Lambda-Stream流
java·lambda
编啊编程啊程34 分钟前
一文上手SpringSecurity【四】
java·服务器·spring boot·分布式·后端·spring
2401_8576380338 分钟前
Spring Boot 驱动的在线订餐平台
java·spring boot·后端
korgs39 分钟前
dea插件开发-自定义语言9-Rename Refactoring
java·开发语言
武子康1 小时前
大数据-151 Apache Druid 集群模式 配置启动【上篇】 超详细!
java·大数据·clickhouse·flink·apache
武子康1 小时前
大数据-144 Apache Kudu 基本概述 数据模型 使用场景
java·大数据·clickhouse·架构·flink·apache
骆晨学长1 小时前
基于Spring的社区防疫公益管理系统设计与实现
java·开发语言·spring boot·后端·spring