JDK新特性(二)

课程笔记Day16

  • Lambda 表达式
  • 方法引用
  • Stream流

第一章 Lambda表达式

第01节 基础理论

lambda表达式的体验

发现问题

以前写 匿名内部类的时候,会觉得代码非常的繁琐。写起来比较麻烦。

体验 Lambda表达式

接口

//接口
public interface JieKou {
    //抽象方法
    public abstract void methodAbstract();
}

接口实现类

//实现类
public class ShiXian implements JieKou {
    @Override
    public void methodAbstract() {
        System.out.println("接口实现类...");
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        //可以使用多态的写法
        JieKou kou = new ShiXian();
        function(kou);
        //可以使用匿名内部类的写法
        function(new JieKou() {
            @Override
            public void methodAbstract() {
                System.out.println("匿名内部类");
            }
        });
        //采用Lambda表达式对于匿名内部类进行简化。
        function(()->System.out.println("Lambda"));
    }

    //将方法的参数定义为接口
    public static void function(JieKou kou){
        kou.methodAbstract();
    }
}

lambda表达式的格式

格式:

(参数列表)->{ 方法体; }

1. 小括号:参数列表。指的是 接口当中抽象方法的参数列表。
2. 箭头: 就是一个指向,没有具体的含义。可以理解为:将参数传递给方法体。
3. 大括号: 方法体。指的是 接口当中抽象方法的具体实现。

前提:

如果想要使用 Lambda 表达式,则必须有 函数式接口。
什么是函数式接口呢?
函数式接口: 有且仅有一个抽象方法的接口,就叫做函数式接口。
如何去校验是否是正确的函数式接口呢?
可以采用注解  @FunctionalInterface

辨别函数式接口

在这里插入图片描述

第02节 系统函数式接口

Supplier

源代码

//作用:只出不进
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

测试类

import java.util.function.Supplier;

//目标:学习系统提供的Supplier接口
public class Test01 {

    public static void main(String[] args) {
        //匿名内部类版本
        function(new Supplier<String>() {
            @Override
            public String get() {
                return "sleep 真香";
            }
        });
        //采用 Lambda 表达式简化
        function(()->{return "sleep 真香,尤其是上课sleep";});
    }

    //定义一个方法,该方法的参数是函数式接口
    public static void function(Supplier<String> fun){
        String s = fun.get();
        System.out.println(s);
    }
}

Consumer

源代码

//作用:只进不出
@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); };
    }
}

测试类

import java.util.function.Consumer;

//函数式接口 Consumer的使用
public class Test02 {

    public static void main(String[] args) {
        //调用方法, 采用的是匿名内部类的写法
        function(100, new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });

        //如果想要写 lambda表达式应该怎么写呢?
        function(100,(Integer integer)->{ System.out.println(integer);});
    }

    //函数式接口作为方法的参数传递
    public static void function(Integer ii,Consumer<Integer> fun){
        fun.accept(ii);
    }
}

Predicatie

源代码

//作用:条件判断
@FunctionalInterface
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);
    }
}

测试类

import java.util.function.Predicate;

//目标:学习Predicate 函数式接口的使用
public class Test03 {

    public static void main(String[] args) {
        //匿名内部类
        function("张无忌", new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("王");
            }
        });
        //Lambda表达式的写法
        function("隔壁老王",(String s)->{return s.startsWith("王");});
    }

    public static void function(String str,Predicate<String> fun){
        boolean flag = fun.test(str);
        System.out.println("flag = " + flag);
    }
}

Function

源代码

//作用:类型转换
@FunctionalInterface
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;
    }
}

测试类

import java.util.function.Function;

//目标:学习 Function 函数式接口的使用
public class Test04 {

    public static void main(String[] args) {
        //匿名内部类写法
        function("hello", new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();
            }
        });
        //Lambda表达式的写法
        function("world",(String s)->{return s.length();});
    }

    //写一个方法,方法的参数是函数式接口
    public static void function(String str,Function<String,Integer> fun){
        Integer num = fun.apply(str);
        System.out.println(num);
    }
}
第03节 省略策略

关于 Lambda表达式,除了标准格式外,还可以继续的简化代码。

1. 什么时候,小括号可以省略呢?
	只有一个参数的时候,可以省略小括号不写。

2. 什么时候,大括号可以省略呢?
	在方法体当中,只有一句话的时候,可以省略大括号,分号,return语句。

3. 百分百可以省略的是什么?
	我们 参数列表的数据类型,可以百分百省略。
第04节 Lambda和匿名内部类

说明

1. 区别一:引用简化方式不同。
	A. 匿名内部类,他可以作用于 接口或者是类
	B. Lambda表达式, 他只能作用于函数式接口
	
2. 区别二: 底层实现不同。
	A. 匿名内部类,底层产生class文件
	B. Lambda表达式,底层没有 class 文件

第二章 方法引用

第01节 体验一下
import java.util.function.Consumer;

//目标:体验方法引用的好处
public class Test01 {

    public static void main(String[] args) {
        //采用Lambda表达式的写法
        method("hello",str-> System.out.println(str));
        //直接使用方法引用
        method("world",System.out::println);

    }

    public static void method(String str,Consumer<String> con){
        con.accept(str);
    }
}

小结:

我们发现,采用方法引用,比lambda表达式更加的简单。

条件会更加的苛刻。

你要做某件事情,刚好发现别人也要做这件事情,就顺带的使用他的事情,一起做了。

第02节 成员方法引用

普通类

//学生类
public class Student {

    //定义方法,喊出你的名字
    public void callName(String name){
        System.out.println("我叫"+name);
    }
}

测试类

import java.util.function.Consumer;

public class Test02 {

    public static void main(String[] args) {
        //原始的做法:
        method("黄雨浩",name-> System.out.println("我叫"+name));
        //直接引用方法
        method("江少东",new Student()::callName);
    }

    //定义一个方法,进行自我介绍。
    public static void method(String name,Consumer<String> con){
        con.accept(name);
    }
}

//我叫黄雨浩
//我叫江少东

小结:成员方法引用格式: 对象名称::方法名称

第03节 静态方法引用

普通类

public class Teacher {

    //定义方法,喊出你的名字
    public static void callName(String name){
        System.out.println("点名"+name);
    }
}

测试类

import java.util.function.Consumer;

public class Test03 {

    public static void main(String[] args) {
        //原始的做法:
        method("黄雨浩",name-> System.out.println("点名"+name));
        //直接引用左侧的方法
        method("江少东",Teacher::callName);

    }

    //定义一个方法,进行自我介绍。
    public static void method(String name,Consumer<String> con){
        con.accept(name);
    }
}

//点名黄雨浩
//点名江少东

小结:静态方法的引用: 类名称::方法名称

第04节 构造方法引用

普通类

public class Student{

}

测试类

import java.util.function.Supplier;

//目标:学习构造方法引用
public class Test04 {

    public static void main(String[] args) {
        //将对象,进行打印输出
        Student stu1 = makeObject(() -> new Student());
        System.out.println("stu1 = " + stu1);
        //采用方法引用
        Student stu2 = makeObject(Student::new);
        System.out.println("stu2 = " + stu2);
    }

    //泛型方法。返回一个你需要的对象
    public static <T> T makeObject(Supplier<T> sup){
        T t = sup.get();
        return t;
    }
}

小结:构造方法引用格式: 类名称::new

第三章 Stream流

第01节 基础理论
我们以前针对于集合或者数组的操作是非常频繁的。
例如:
	第一步做集合 筛选的操作(根据条件1筛选)
	第二步做集合 筛选的操作(根据条件2筛选)
	第三步做集合 合并的操作(将两个集合数据进行合并)
	第四步做集合 去重的操作(将重复的数据进行过滤)
	第五步做集合 排序的操作(将集合数据按照升序排列)

快速入门

public static void main(String[] args) {
    ArrayList<String> one = new ArrayList<>();
    Collections.addAll(one,"河北省","山西省","吉林省","辽宁省","黑龙江省","陕西省","甘肃省","青海省","山东省","福建省","浙江省","台湾省","河南省","湖北省","湖南省","江西省","江苏省","安徽省","广东省","海南省","四川省","贵州省","云南省");

    ArrayList<String> two = new ArrayList<>();
    Collections.addAll(two,"北京市","天津市","上海市","重庆市");

    ArrayList<String> three = new ArrayList<>();
    Collections.addAll(three,"内蒙古自治区","新疆维吾尔自治区","宁夏回族自治区","广西壮族自治区","西藏自治区");

    ArrayList<String> four = new ArrayList<>();
    Collections.addAll(four,"香港特别行政区","澳门特别行政区");


    Stream<String> sm1 = Stream.concat(one.stream(), two.stream());
    Stream<String> sm2 = Stream.concat(three.stream(), four.stream());
    long count = Stream.concat(sm1, sm2).filter(s -> s.length() == 3).count();
    System.out.println("xxcount = " + count);
}

流Stream的流程图

在这里插入图片描述

第02节 常用API

获取流的操作

类别做法例子
单列集合集合对象名称.stream( );mList.stream( ); mSet.stream( );
双列集合将双列集合转换成为单列集合,再调用 stream( ) 方法mMap.keySet( ).stream( ) mMap.values( ).stream( )
同类数据有多个数据类型相同的数据,直接使用静态方法 ofStream.of(数据1,数据2,数据3);

常用方法

方法名方法作用返回值类型方法种类
count统计个数long终结
foreach遍历void终结
filter过滤Stream中间
limit限定前几个Stream中间
skip跳过前几个Stream中间
map映射Stream中间
sorted排序Stream中间
distinct去重Stream中间
collect收集List、Set、Map收集

说明:

  1. 终结:操作完毕之后,不再是 Stream 流对象。
  2. 中间:操作完毕之后,还是 Stream流对象,还可以继续调用 Stream流当中的方法。
  3. 收集:操作完毕之后,可以将 Stream流转换成为集合对象。
第03节 Stream流练习
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/*

我国有34个省级行政区,分别是:
23个省:河北省、山西省、吉林省、辽宁省、黑龙江省、陕西省、甘肃省、青海省、山东省、福建省、浙江省、台湾省、河南省、湖北省、湖南省、江西省、江苏省、安徽省、广东省、海南省、四川省、贵州省、云南省。

4个直辖市:北京市、天津市、上海市、重庆市。
5个自治区:内蒙古自治区、新疆维吾尔自治区、宁夏回族自治区、广西壮族自治区、西藏自治区。
2个特别行政区:香港特别行政区、澳门特别行政区。

请使用流依次完成下列操作:
题目01:统计三个字的省份的个数
题目02:统计名字中包含方位名词的省份(东西南北)的个数
题目03:打印名字中包含方位名词的普通省份(非自治区直辖市特别行政区)的名字
题目04:将所有的特殊省份(自治区直辖市特别行政区)提取出来并放到新数组中

 */
@SuppressWarnings("all")
public class Test06 {

    public static void main(String[] args) {
        ArrayList<String> one = new ArrayList<>();
        Collections.addAll(one, "河北省", "山西省", "吉林省", "辽宁省", "黑龙江省", "陕西省", "甘肃省", "青海省", "山东省", "福建省", "浙江省", "台湾省", "河南省", "湖北省", "湖南省", "江西省", "江苏省", "安徽省", "广东省", "海南省", "四川省", "贵州省", "云南省");
        ArrayList<String> two = new ArrayList<>();
        Collections.addAll(two, "北京市", "天津市", "上海市", "重庆市");
        ArrayList<String> three = new ArrayList<>();
        Collections.addAll(three, "内蒙古自治区", "新疆维吾尔自治区", "宁夏回族自治区", "广西壮族自治区", "西藏自治区");
        ArrayList<String> four = new ArrayList<>();
        Collections.addAll(four, "香港特别行政区", "澳门特别行政区");
        //将四个集合全部存放到Stream流当中
        Stream<String> sm1 = Stream.concat(one.stream(), two.stream());
        Stream<String> sm2 = Stream.concat(three.stream(), four.stream());
        Stream<String> sm = Stream.concat(sm1, sm2);
        //先将流对象,收集到集合当中
        List<String> collect = sm.collect(Collectors.toList());
        //题目01:统计三个字的省份的个数
        long count1 = collect.stream().filter(s -> s.length() == 3).count();
        System.out.println("count1 = " + count1);
        //题目02:统计名字中包含方位名词的省份(东西南北)的个数
        long count2 = collect.stream().filter(s -> s.contains("东") || s.contains("南") || s.contains("西") || s.contains("北")).count();
        System.out.println("count2 = " + count2);
        //题目03:打印名字中包含方位名词的普通省份(非自治区直辖市特别行政区)的名字
        collect.stream().filter(s -> s.contains("东") || s.contains("南") || s.contains("西") || s.contains("北")).filter(s -> s.contains("区") == false && !s.contains("市")).forEach(System.out::println);
        //题目04:将所有的特殊省份(自治区直辖市特别行政区)提取出来并放到新数组中
        List<String> mList = collect.stream().filter(s -> s.contains("市") || s.contains("区")).collect(Collectors.toList());
        String[] array = mList.toArray(new String[mList.size()]);
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i] + ",索引:" + i);
        }
    }
}
//山东、山西、河南、河北、湖南、湖北、广东、广西、陕西、北京、江西、海南、西藏、云南
//山东、山西、河南、河北、湖南、湖北、广东、陕西、江西、云南、海南
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值