理解匿名内部类和lambda表达式和stream流的使用方法

  • Post author:
  • Post category:其他




1.概念

我这里理解的来源1.韩顺平老师的30天学java的课件中的概念

一个类的内部又完整的嵌套了另一个类结构,被嵌套的类策划归纳为内部类(inner class),嵌套其他类的类称为外部类(outer Class)。

类的五大成员:属性、方法、构造器、代码块、内部类。

内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。源代码中有大量的内部类。



内部类的分类

定义在外部类局部位置上(比如方法内):

  1. 局部内部类(有类名)
  2. 匿名内部类(没有类名,重点!!!!)

定义在外部类的成员位置上

  1. 成员内部类(没有statc修饰)
  2. 静态内部类(使用static修饰)
class Outer{
        class Inner {
            
        }
    }
class Other {
        
    }

快速入门

package com.xxxx.innerclass;

public class InnerClass01 {				 //外部其他类
		public static void main(String[] args) {
		}
}

	class Outer {					 //外部类
		private int n1 = 100;		//属性
		public Outer(int n1) {		//构造器
		this.n1 = n1;
		}
		public void m1() {			//方法
			System.out.println("m1()");
		}

	{							//代码块
		System.out.println("代码块...");
	}
		class Inner { 			//内部类, 在 Outer 类的内部
	}
}



匿名内部类的使用

1.本质还是类

2.内部类

3.该类没有名字

4.同时还是一个对象

匿名内部类通常使用一次,后面不再使用。节省位置。

语法:

new  类或接口(参数列表){
	类体
}
/**
* 演示匿名内部类的使用
*/
public class sss {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}
class Outer04 { //外部类
    private int n1 = 10;//属性
    public void method() {//方法
            /*基于接口的匿名内部类
            老韩解读
            1.需求: 想使用 IA 接口,并创建对象
            2.传统方式,是写一个类,实现该接口,并创建对象
            3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
            4. 可以使用匿名内部类来简化开发
            5. tiger 的编译类型 ? IA
            6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
            */

            /*
            我们看底层 会分配 类名 Outer04$1
            class Outer04$1 implements IA {
                @Override
                public void cry() {
                        System.out.println("老虎叫唤...");
                }
            }

            */
            /*7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
             返回给 tiger
            8. 匿名内部类使用一次,就不能再使用*/
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫唤...");
            }
        };
        System.out.println("tiger 的运行类型=" + tiger.getClass());
        tiger.cry();
        tiger.cry();
        tiger.cry();
/*   
普通方法这样写 
IA tiger = new Tiger();
 tiger.cry();
 */
                /*演示基于类的匿名内部类
                分析
                1. father 编译类型 Father
                2. father 运行类型 Outer04$2
                3. 底层会创建匿名内部类*/
                /*
                class Outer04$2 extends Father{
                    @Override
                    public void test() {
                        System.out.println("匿名内部类重写了 test 方法");
                    }
                }
                */
                /*4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
                5. 注意("jack") 参数列表会传递给 构造器*/
        Father father = new Father("jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了 test 方法");
            }
        };
        System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
        father.test();
//基于抽象类的匿名内部类
        Animal animal = new Animal(){
            @Override
            void eat() {
                System.out.println("小狗吃骨头...");
            }
        };
        animal.eat();
    }
}
interface IA {//接口
    public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//类
    public Father(String name) {//构造器
        System.out.println("接收到 name=" + name);
    }
    public void test() {//方法
    }
}
abstract class Animal { //抽象类
        abstract void eat();
    }

仔细理解代码应该都可以看懂。注释的代码是先用普通代码写的。

这里我们理解lambda表达式。这里就看清代码中的 Father类,里面有构造方法

package com.lambda;

/**
 * 使用lambda表达式替换Runnable匿名内部类
 * @author MingChenchen
 *
 */
public class RunableTest {
    /**
     * 普通的Runnable
     */
    public static void runSomeThing(){

        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                System.out.println("I am running");
            }
        };
        new Thread(runnable).start();
    }

    /**
     * 使用lambda后的
     */
    public static void runSomeThingByLambda(){
        new Thread(() -> System.out.println("I am running")).start();
    }

    public static void main(String[] args) {
        runSomeThing();
//      runSomeThingByLambda();
    }
}

上述代码中:
() -> System.out.println("I am running")就是一个lambda表达式,
可以看出,它是替代了new Runnable(){}这个匿名内部类。

结合上面两段代码,我讲一些我的理解

new Thread(() -> System.out.println("I am running")).start();

这里的这个()中的参数是重写的方法 run() 中的参数

这个就是匿名内部类的参数位置。

/*
也可以直接调用,匿名内部类本身也是返回对象*/

class 匿名内部类 extends Person {

 	new Person(){
        @Override
        public void hi(){
            System.out.println("匿名内部类重写了 hi 方法,哈哈...");
        }
        
        @Override
        public void ok(String str){
        super.ok(str);
        }
     }.ok("jack");
}

2.使用lambda表达式实现Comparator

package com.lambda;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortList {
    //给入一个List
    private static List<String> list = 
            Arrays.asList("my","name","is","uber","and","uc");

    /**
     * 对一个String的list进行排序 - 使用老方法
     */
    public static void oldSort(){
        //排序
        Collections.sort(list,new Comparator<String>() {
            //使用新的排序规则 根据第二个字符进行逆序排
            @Override
            public int compare(String a,String b){
                if (a.charAt(1) <= b.charAt(1)) {
                    return 1;
                }else{
                    return -1;
                }
            }
        });
    }

    /**
     * 新的排序方法 - 使用lambda表达式实现
     */
    public static void newSort(){
        //lambda会自动推断出 a,b 的类型
        Collections.sort(list, (a, b) -> a.charAt(1) < b.charAt(1) ? 1:-1);
    }

    public static void main(String[] args) {
//      oldSort();
        newSort();
    }
}

记住匿名内部类的用法就是使用一次,那个类如果不再调用方法就不会再使用。,然后lambda就是节省了匿名内部类的书写。



关于方法的应有方面的额讲解,最近看到一篇文章,讲的更简单易懂:

方法引用(Method References)

https://www.cnblogs.com/Alay/p/15056737.html



字符串大小的比较从String.compareTo()方法。



在spring中lambda和stream可以很好的一起使用。

看下面两篇文章:


1.


JAVA8之lambda表达式详解,及stream中的lambda使用



2.


Java 中的双冒号“::”


双冒号“::”就是 Java 中的方法引用(Method references)

方法引用的格式是类名::方法名。一般是用作 Lambda表达式。

http://t.csdn.cn/i37UX


3

.

全面吃透JAVA Stream流操作,让代码更加的优雅


上面两个链接**1.,2.**中讲的stream还算清晰,不理解的可以多读两遍就好了。这个要仔细读。我第一遍就读得快,细节没掌握到就不懂。第二遍深夜读的。掌握了感觉。

然后写项目时,经常把 stream 流和 lambda 表达式结合起来使用。在【1.】中讲的stream的应用方法只能算入门。但是入门也要先看。有助于后续深入的提高。

后续深入学习 stream 和lambda 一起使用的文章在这里:3.

全面吃透JAVA Stream流操作,让代码更加的优雅


这里的这个流 stream 是 paralleleStream 管道流。(输出管道流PipedOutputStream或)。也是流的一种。不同于字符流字节流。

在这里插入图片描述

在这里插入图片描述

中间管道方法的讲解和终止管道方法大致简述如下(一定先看1.

JAVA8之lambda表达式详解,及stream中的lambda使用

这篇文章,有个大概的了解stream.但是它写的方法不全,看下面我写的的全的):

每个Stream管道操作类型都包含若干API方法,先列举下各个API方法的功能介绍。

开始管道

主要负责新建一个Stream流,或者基于现有的数组、List、Set、Map等集合类型对象创建出新的Stream流。

API 功能说明
stream() 创建出一个新的stream串行流对象
parallelStream() 创建出一个可并行执行的stream流对象
Stream.of() 通过给定的一系列元素创建一个新的Stream串行流对象

中间管道

负责对Stream进行处理操作,并返回一个新的Stream对象,中间管道操作可以进行叠加。

API 功能说明
filter() 按照条件过滤符合要求的元素, 返回新的stream流
map() 将已有元素转换为另一个对象类型,一对一逻辑,返回新的stream流
flatMap() 将已有元素转换为另一个对象类型,一对多逻辑,即原来一个元素对象可能会转换为1个或者多个新类型的元素,返回新的stream流
limit() 仅保留集合前面指定个数的元素,返回新的stream流
skip() 跳过集合前面指定个数的元素,返回新的stream流
concat() 将两个流的数据合并起来为1个新的流,返回新的stream流
distinct() 对Stream中所有元素进行去重,返回新的stream流
sorted() 对stream中所有的元素按照指定规则进行排序,返回新的stream流
peek() 对stream流中的每个元素进行逐个遍历处理,返回处理后的stream流

终止管道

顾名思义,通过终止管道操作之后,Stream流将会结束,最后可能会执行某些逻辑处理,或者是按照要求返回某些执行后的结果数据。

API 功能说明
count() 返回stream处理后最终的元素个数
max() 返回stream处理后的元素最大值
min() 返回stream处理后的元素最小值
findFirst() 找到第一个符合条件的元素时则终止流处理
findAny() 找到任何一个符合条件的元素时则退出流处理,这个对于串行流时与findFirst相同,对于并行流时比较高效,任何分片中找到都会终止后续计算逻辑
anyMatch() 返回一个boolean值,类似于isContains(),用于判断是否有符合条件的元素
allMatch() 返回一个boolean值,用于判断是否所有元素都符合条件
noneMatch() 安徽一个boolean值, 用于判断是否所有元素都不符合条件
collect() 将流转换为指定的类型,通过Collectors进行指定
toArray() 将流转换为数组
iterator() 将流转换为Iterator对象
foreach() 无返回值,对元素进行逐个遍历,然后执行给定的处理逻辑

上面的还是没有看懂的话看这几个其他网站的讲解:(先把下面这个**【全面吃透JAVA Stream流操作,让代码更加的优雅】**看完)


  1. https://tobebetterjavaer.com/java8/stream.html

  2. https://juejin.cn/post/6844903830254010381

  3. https://blog.51cto.com/u_15430445/5203512

**3.**下面是整个页面我插入进来了:

在这里插入图片描述



版权声明:本文为sinat_41902940原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。