GP_08_Lambda和Stream

0.晨考

1. 接口定义的规则
	interface 接口名 {
		成员变量 缺省属性 public static final 定义时必须初始化,通常采用下划线命名法
        成员方法 缺省属性 public abstract
	}
	
	
2. default 关键字在接口中有什么作用
	修饰方法,对应方法可以有方法体
	JDK1.8 以上版本支持。
	
3. abstract 修饰的方法有什么特征
	1. 没有方法体
	2. 有且只能定义在 abstract 修饰的类内 或者 interface 接口内
	3. 一个非 abstract 修饰类继承 abstract 类或者遵从 接口必须实现对应的 abstract 方法
	
4. 代码简述匿名内部类形式	
interface A() {
    void test();
}

main() {
    // 创建的是遵从接口 A 的匿名类实例化对象。
    A a = new A() {
        @Override
        public void test() {
            System.out.println("匿名内部类");
        }
    };
    
    a.test();
}
5. HashMap 操作相关方法
	构造
		HashMap();
		HashMap(int initCapacity);		
        
	成员
		增
			put(K k, V v);
			putAll(Map<? extends K, ? extends V> map)V remove(Object k);
			boolean remove(Object k, Object v);put(K k, V v);int size();
			boolean isEmpty();
			boolean containsKey(Object key);
			boolean containsValue(Object value);
			Collection<V> valus();
			Set<K> keySet();
			Set<Map.Entry<K, V>> entrySet()
			
6. LinkedList 性能分析
	因为 LinkedList 底层是一个带有链表头结构双向链表,在头结点和尾结点进行【增删改查】操作效率极高,其他的结点因为空间不连续的问题,需要进行逐一遍历,效率较低。
    LinkedList 适用的场景都是一些队列,线程池,数据库连接池,消息队列,任务队列...
	
7. <? extends E><? super E> 分析
	<? extends E> 
		泛型的上限,约束当前类型可以是 E 类型本身或者其子类类型
		泛型的上限操作一般用于集合,Map 双边队列
	<? super E>
		泛型的下限,约束当前类型可以是 E 类型本身或者其父类类型
		泛型的下限用于方法类型约束

1. 函数式接口(java8新特性)

JDK 1.8 版本以上有效

1.1函数式接口的定义:

接口中【有且只能有一个】尚未完成的 缺省属性为 public abstract 修饰的抽象方法。并在上面加@FunctionalInterface注解

1.2函数式接口的作用:

是Lambda 表达式及其方法引用的前提!

一般用于方法的增强,直接作为方法的参数,实现【插件式编程】。

@FunctionalInterface
interface Test {
    void test();
}

1.3JDK提供的常用函数式接口

在java.util.Function包下

消费型接口 Consumer 常用于遍历 void accpet(T t)
生产者接口 Supplier 用于产生数据 T get()

比较器接口:Comparator

过滤器接口 Predicate 用于判断 boolean test(T t)
类型转换器接口 Function<T,R> 用于逻辑处理 R apply(T t)

2. Lambda 表达式(java8新特性)

基本格式:

(联想参数临时变量) -> {执行任务代码块}

解释:

—> Lambda操作符

() Lambda的形参列表 对应的接口的那个抽象方法的形参列表

{} 其实就是抽象方法的方法体

注:Lambda 表达式关注的是接口中方法的【返回值】和【参数】。方法名和接口名不重要!可以随便起!

2.1 无参数无返回值 Lambda

package com.qf.lambda_;

@FunctionalInterface
interface A {
    void methodName();
}

public class Demo1 {



    public static void main(String[] args) {

        /*
        1. 匿名内部类方式
         */
        testLambda(new A() {
            @Override
            public void methodName() {
                System.out.println("无参数返回值 匿名内部类对象方法实现");
            }
        });

        /*
        2. Lambda 表达式实现
        无参无返回值
         */
        testLambda(() -> {
            System.out.println("Lambda 表达式初体验");
        });

        // Lambda优化1: 表达式有且只有一行代码,可以省略大括号
        testLambda(() -> System.out.println("Lambda 表达式初体验"));

        // 方法引用方式
        testLambda(Demo1::test);
    }

    /**
     * Lambda 的测试方法,当前方法所需参数是 A 接口实例化对象,因为当前 A 接口
     * 是一个函数式接口,可以使用 Lambda 表达式解决问题
     *
     */
    public static void testLambda(A a) {
        a.methodName();
    }

    public static void test() {
        System.out.println("方法引用");
    }
}

2.2 有参数无返回值 Lambda

2.2.1消费者接口,

数据最终处理接口,数据处理终止方法接口…因为当前接口中,数据有去无回

泛型可以在使用过程中,支持数据类型多样性,同时满足数据类型一致化要求!当前方法可以支持的数据类型满足所有情况。

@FunctionalInterface
public interface Consumer<T> {
    /**
    * 消费者接口,数据最终处理接口,数据处理终止方法接口,对应的方法要求
    * 方法有参数无返回值
    *
    * @param t 泛型数据数据类型 T ,支持任意类型,在接口约束之后,要求符合
    *			数据类型一致化要求
    */
    void accept(T t);
}

方法设计

/**
 * 有参数无返回 Lambda 测试方法,
 * 方法参数是 String 类型和约束泛型为 String 类型进行数据处理的 Consumer 接口,
 * Consumer 接口可以传入实现类对象和 Lambda 表达式
 *
 * @param str    目标处理的 String 字符串数据
 * @param handle 已经约束为处理 String 类型数据的 Consumer 接口处理器
 */
public static void testLambda(String str, Consumer<String> handle) {
    /*
    需要方法外部提供针对于当前 String 字符串的处理能力。
    处理能力通过 Consumer 接口传入
     */
    handle.accept(str);
}

代码实现

public static void main(String[] args) {
    /*
    1、匿名内部类 Low
     */
    testLambda("孟州市炒面第一名", new Consumer<String>() {
        @Override
        public void accept(String t) {
            System.out.println(t);
        }
    });

    /*
    2. Lambda 表达式
    【分析】
        void accept(T t); ==> 泛型约束为 String ==> void accept(String t);

     Lambda 格式
        Lambda 小括号中的临时变量名称,没有数据类型体现,需要【联想】目标方法数据类型
        只按照参数的个数定义临时小变量
        (s) -> {大括号中无需返回值类型}
            Lambda 表达式临时变量 s 对应的数据类型为 String 类型 【联想可得】
     */
    testLambda("lambda表达式需要联想!!!", (s) -> {
        System.out.println(Arrays.toString(s.toCharArray()));
    });

    /*
    Lambda 优化:
        2. 代码块有且只有一行,可以省略大括号
        3. 小括号中有且只有一个 参数,可以省略小括号

    【注意】
        Lambda 承担的角色是一个针对于 String 字符串的处理器
     */
    testLambda("lambda表达式需要联想!!!", s -> System.out.println(Arrays.toString(s.toCharArray())));

    // 方法引用
    testLambda("lambda表达式需要联想!!!", System.out::println);
    testLambda("lambda表达式需要联想!!!", Demo2::test);

}

public static void test(String str) {
    System.out.println(str);
}

2.3 无参数有返回值 Lambda

2.3.1 生产者接口

巧妇难为无米之炊,使用的数据都是对应方法中的数据内容,利用方法【局部变量 Local Variable】

接口设计

@FunctionalInterface
interface Supplier<T> {
    /**
    * 泛型约束的是接口对应的返回值数据类型,要求按照泛型约束返回对应的数据内容
    *
    * @return 返回一个数据,符合泛型约束
    */
	T get();
}

方法设计

/**
 * 当前方法要求返回一个字符串数据内容
 *
 * @param s Supplier 生产者,数据提供接口对应的参数
 * @return 字符串数据
 */
public static String testLambda(Supplier<String> s) {
    return s.get();
}

代码实现

public static void main(String[] args) {
    /*
    1. 匿名内部类形式
     */
    String s = testLambda(new Supplier<String>() {
        @Override
        public String get() {
            return "这是一个字符串";
        }
    });

    System.out.println(s);

    
    /*
    2. Lambda 表达式
    【分析】
        T get(); ==> 泛型约束为 String ==> String get();

     Lambda 格式
        () -> {必须返回一个 String 类型}
            return 关键字出马
     */
    String s1 = testLambda(() -> {
        return "这里也是一个字符串";
    });
    System.out.println(s1);

    /*
    Lambda 优化4:只要 -> 之后是一个 字符串数据内容就可以满足当前 Lambda 所需
    可以省略 return ,前提是当前 Lambda 有且只有一行代码
     */
    String s2 = testLambda(() -> "这里也是一个字符串");
    System.out.println(s2);

    /*
    Lambda 内部使用使用方法局部变量
     */
    String str = "name=周冠宇&age=23&country=中国";
    String s3 = testLambda(() -> {
        // str 是当前 main 方法局部变量,Lambda 内部可以直接使用
        String[] split = str.split("&");
        return split[0];
    });
    System.out.println(s3);

    // 方法引用
    String s4 = testLambda(Demo3::test);
    System.out.println(s4);
}

public static String test() {
    return "Function Reference";
}

2.4 有参数有返回值 Lambda【重点】

2.4.1 比较器接口

@FunctionalInterface
interface Comparator<T> {
    /**
     * 比较器接口要求的方法,参数是泛型参数,用户指定类型
     *
     * @param o1 用户在使用接口时约束的泛型对应具体数据类型参数
     * @param o2 用户在使用接口时约束的泛型对应具体数据类型参数
     * @return 返回值为 int 类型,0 表示两个元素一致。
     */
    int compare(T o1, T o2);
}

比较器案例代码

/**
 * @author Anonymous 2023/3/3 11:31
 */
public class Demo5 {
    public static void main(String[] args) {
        Person[] array = new Person[5];

        for (int i = 0; i < array.length; i++) {
            int age = (int) (Math.random() * 50);
            array[i] = new Person(i + 1, "张三", age, false);
        }

        /*
        Lambda 分析
            boolean test(T t); ==> 泛型约束为 Person 类型 ==> boolean test(Person t);
        方法返回值是 boolean
        方法参数
            1. 1 个
            2. Person 类型
         Lambda 格式
            p -> {要求必须返回一个 boolean}
         */
        Person[] temp = filterPersonArrayUsingPredicate(array, p -> p.getAge() > 10);

        for (Person person : temp) {
            System.out.println(person);
        }

    }

    /**
     * 过滤限定操作,利用 Predicate 过滤器接口限定数组内容
     *
     * @param array  Person 类型数组
     * @param filter Predicate 过滤器参数
     * @return 过滤限定之后的新数组
     */
    public static Person[] filterPersonArrayUsingPredicate(Person[] array, Predicate<Person> filter) {
        Person[] temp = new Person[array.length];

        int count = 0;
        for (int i = 0; i < array.length; i++) {
            /*
             Predicate 接口提供的方法是  boolean test(T t);
             目前泛型约束之后是 boolean test(Person t);
             判断当前 Person 对象是否满足要求,如果满足,存储到 temp 数组中。
             */
            if (filter.test(array[i])) {
                temp[count++] = array[i];
            }
        }

        return temp;
    }
}

2.4.2 过滤器接口

// 过滤器接口,判断器接口,条件接口
@FunctionalInterface
interface Predicate<T> {
    /**
     * 过滤器接口约束的方法,方法参数是用户使用时约束泛型对应具体数据参数
     * 返回值类型是 boolean 类型,用于条件判断,数据过来
     *
     * @param t 用户约束泛型对应的具体数据类型参数
     * @return boolean 数据,判断结果反馈
     */
    boolean test(T t);
}

过滤器接口案例代码

/**
 * @author Anonymous 2023/3/3 11:31
 */
public class Demo5 {
    public static void main(String[] args) {
        Person[] array = new Person[5];

        for (int i = 0; i < array.length; i++) {
            int age = (int) (Math.random() * 50);
            array[i] = new Person(i + 1, "张三", age, false);
        }

        /*
        Lambda 分析
            boolean test(T t); ==> 泛型约束为 Person 类型 ==> boolean test(Person t);
        方法返回值是 boolean
        方法参数
            1. 1 个
            2. Person 类型
         Lambda 格式
            p -> {要求必须返回一个 boolean}
         */
        Person[] temp = filterPersonArrayUsingPredicate(array, p -> p.getAge() > 10);

        for (Person person : temp) {
            System.out.println(person);
        }

    }

    /**
     * 过滤限定操作,利用 Predicate 过滤器接口限定数组内容
     *
     * @param array  Person 类型数组
     * @param filter Predicate 过滤器参数
     * @return 过滤限定之后的新数组
     */
    public static Person[] filterPersonArrayUsingPredicate(Person[] array, Predicate<Person> filter) {
        Person[] temp = new Person[array.length];

        int count = 0;
        for (int i = 0; i < array.length; i++) {
            /*
             Predicate 接口提供的方法是  boolean test(T t);
             目前泛型约束之后是 boolean test(Person t);
             判断当前 Person 对象是否满足要求,如果满足,存储到 temp 数组中。
             */
            if (filter.test(array[i])) {
                temp[count++] = array[i];
            }
        }

        return temp;
    }
}

2.4.3 类型转换器接口

// 类型转换器接口
@FunctionalInterface
interface Function<T, R> {
	R apply(T t);	
}

代码实现

/**
 * @author Anonymous 2023/3/3 11:31
 */
public class Demo6 {
    public static void main(String[] args) {
        String str = "开封有个包青天";

        /*
        Lambda 分析
            R apply(T t); ==> 泛型约束 T => String R => Integer
            Integer apply(String t);

        Lambda 格式
            返回值类型 Integer
            方法参数
                1. 1个
                2. String
            s -> {必须返回 int 类型数据}
         */
        int i = testLambda(str, s -> s.length());
        System.out.println(i);

        // 方法引用
        int ret =  testLambda("邠州有个范仲淹", Demo6::test);
        System.out.println(ret);

    }

    public static int testLambda(String str, Function<String, Integer> fun) {
        return fun.apply(str);
    }

    public static int test(String str) {
        return str.length();
    }
}

3. Stream 流

3.1 Stream 概述

JDK 1.8 版本及其以上支持!!!
利用流水线思想对于集合,数组数据进行处理和操作。涉及到数据筛选,排序,转换类型,限制个数,最终处理....并且在处理数据的过程中,对于数据的原始空间没有任何的修改,不影响原始数据。

3.2 Stream 流体验卡

ArrayList<String> list = new ArrayList<>();

list.add("卫龙辣条");
list.add("乐事薯片");
list.add("娃哈哈AD钙奶");
list.add("浪味仙");
list.add("旺仔牛奶");
list.add("喜之郎果冻");
list.add("不二家棒棒糖");
list.add("波力海苔");
list.add("大白兔奶糖");
list.add("双汇王中王");
list.add("牛肉干");
 
System.out.println();
list.stream()
         .skip(2)
         .limit(8)
         .filter(s -> s.length() > 4)
         .sorted(Comparator.comparing(String::length))
         .forEach(System.out::println);

3.3 Stream 流相关方法

Stream 处理的是 集合 或者 数组

// 集合对象
Stream<T> stream();
	集合对象调用可以直接获取对应当前集合存储元素的 Stream 流对象。

// 数组
Stream<T> Arrays.Stream(T[] t);
	利用 Arrays 工具类对当前需要按照 Stream 流方式操作的数据进行转换操作,根据当前数组的数据类型和数据存储情况,返回一个对应的 Stream 流对象

Stream 处理数据的【中间方法】

Stream<T> skip(long n);
	掐头:去掉前n个元素
Stream<T> limit(long n);
	去尾:保留前n个元素
Stream<T> distinct();
	去重

Stream<T> sorted();
	升序
Stream<T> sorted(Comparator<? super T> com);
	对当前 Stream 流存储的进行排序操作,排序规则由 Comparator 函数式接口规范

Stream<T> filter(Predicate<? super T> pre);	
	过滤:保留满足括号内条件的元素
Stream<R> map(Function<T, R> fun);
	转换流中的数据类型,将T型转换成R

Stream 处理数据的【终止方法】

终止方法,Stream 流自动关闭。对应 Stream 占用的资源空间会被 JVM 收回

long count();
	返回元素个数

void forEach(Consumer<? super T> con);
	增强for循环,后终止
	
<R, A> R collect(Collector<? super T, A, R> collector);
	Stream 流对应的元素存储内容,转换为用户要求的 集合对象。
	常用:
		Collectors.toList() 目标存储集合类型为 List 集合
		Collectors.toSet()  目标存储集合类型为 Set 集合
		
Object[] toArray();
	Stream 流存储的元素内容转换为 Object 类型数组返回

3.4 相关方法代码演示

package com.qf.stream;


/**
 * @Author: 只想做个优秀
 * @CreateTime: 2023-03-04  11:25
 * @Description: 测试终止方法<R, A> R collect(Collector<? super T, A, R> collector);
 */

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Demo1 {
    public static void main(String[] args) {

        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(100);
        list2.add(120);
        list2.add(120);
        list2.add(120);
        list2.add(120);
        list2.add(180);
        list2.add(280);
        list2.add(240);
        list2.add(260);
        list2.add(280);
        list2.add(290);
        list2.add(300);

        // [100, 120, 120, 120, 120, 180, 280, 240, 260, 280, 290, 300]
        System.out.println(list2);

        List<Integer> list3 = list2.stream()
                .skip(1)
                .limit(9)
                .distinct()
                .sorted()
                .collect(Collectors.toList());


        //[120, 180, 240, 260, 280]
        System.out.println(list3);


    }
}

package com.qf.stream;

import java.util.ArrayList;
import java.util.Comparator;

/**
 * @Author: 只想做个优秀
 * @CreateTime: 2023-03-04  11:25
 * @Description: 测试终止方法void forEach(Consumer<? super T> con);
 */
public class Demo2 {
    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();
        list.add("卫龙辣条");
        list.add("乐事薯片");
        list.add("娃哈哈AD钙奶");
        list.add("浪味仙");
        list.add("旺仔牛奶");
        list.add("喜之郎果冻");
        list.add("不二家棒棒糖");
        list.add("波力海苔");
        list.add("大白兔奶糖");
        list.add("双汇王中王");
        list.add("牛肉干");

        // [卫龙辣条, 乐事薯片, 娃哈哈AD钙奶, 浪味仙, 旺仔牛奶, 喜之郎果冻, 不二家棒棒糖, 波力海苔, 大白兔奶糖, 双汇王中王, 牛肉干]
        System.out.println(list);

        list.stream()
                .skip(2)
                .limit(8)
                .filter(s -> s.length() > 4) // 保留长度大于4的
                .sorted(Comparator.comparing(String::length)) // 根据长度排序
                .forEach(System.out::println);// 遍历
        /*输出结果:
        喜之郎果冻
        大白兔奶糖
        双汇王中王
        不二家棒棒糖
        娃哈哈AD钙奶*/
    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值