一、JUnit

1.1、为什么需要 JUnit

1、一个类有很多功能代码需要测试,为了测试,就需要写入到main方法中

2、如果有多个功能代码测试,就需要来回注销,切换很麻烦

3、如果可以直接运行一个方法,就方便很多,并且可以给出相关信息,就好了->JUnit

1.2、基本介绍

1、JUnit是一个Java语言的单元测试框架

2、多数Java的开发环境都已经集成了JUnit作为单元测试的工具

1.3、使用方法

import org.junit.Test;
public class JUnit_ {
    public static void main(String[] args) {
        //传统方式
        //new JUnit_().m1();
        //new JUnit_().m2();

    }


    @Test
    public void m1() {
        System.out.println("m1方法被调用");
    }

    @Test
    public void m2() {
        System.out.println("m2方法被调用");
    }

    @Test
    public void m3() {
        System.out.println("m3方法被调用");
    }
}

二、单例设计模式

public class Test {
    public static void main(String[] args) {
        // 目标:设计单例类。
        A a1 = A.getInstance();
        A a2 = A.getInstance();
        System.out.println(a1);
        System.out.println(a2);
        System.out.println(a1 == a2);

        System.out.println("============================");

        B b1 = B.getInstance();
        B b2 = B.getInstance();
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b1 == b2);
    }
}

2.1、懒汉式

// 设计成单例设计模式-饿汉式单例类
// 拿对象时,对象已经创立好了
public class A {
    // 2、定义一个静态变量,用于存储本类的一个唯一对象。
    // public static final A a = new A();
    private static A a = new A();
    // private static final A a = new A();

    // 1、私有化构造器: 确保单例类对外不能创建太多对象,单例才有可能性。
    private A() {
    }

    // 3、提供一个公开的静态方法,返回这个类的唯一对象。
    public static A getInstance() {
        return a;
    }
}

2.2、饿汉式

// 设计成单例设计模式-懒汉式单例类
// 拿对象时,对象可能还没创立好
public class B {
    // 2、私有化静态变量
    private static B b;

    // 1、私有化构造器
    private B() {
    }

    // 3、提供静态方法返回对象: 真正需要对象的时候才开始创建对象。
    public static B getInstance() {
        if (b == null) {
            // 第一次拿对象时,会创建对象,给静态变量b记住。
            b = new B();
        }
        return b;
    }
}

三、函数式编程Lambda表达式

3.1、基本介绍

1、此“函数”类似于数学中的函数 ( 强调做什么 ) ,只要输入的数据一致返回的结果也是一致的

2、函数式编程解决了什么问题?
使用 Lambda 函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。

3、JDK8开始新增的一种语法形式,它表示函数
可以用于替代某些匿名内部类对象,从而让程序更简洁,可读性更好。

(被重写方法的形参列表)->{

        被重写方法的方法体代码。

}

3.2、注意事项

1、注意:Lambda 表达式只能替代函数式接口的匿名内部类!!!

2、什么是函数式接口?
有且仅有一个抽象方法的接口。
注意:将来见到的大部分函数式接口,上面都可能会有一个 @Functionallnterface 的注解,该注解用于约束当前接口必须是函数式接口。

3.3、应用

3.3.1、示例1

public class LambdaDemo1 {
    public static void main(String[] args) {
        // 目标:认识Lambda表达式:搞清楚其基本作用。
        Animal a = new Animal() {
            @Override
            public void cry() {
                System.out.println("🐱是喵喵喵的叫~~~~");
            }
        };
        a.cry();

        // 错误示范:Lambda并不是可以简化全部的匿名内部类,Lambda只能简化函数式接口的匿名内部类。
//        Animal a1 = () -> {
//            System.out.println("🐱是喵喵喵的叫~~~~");
//        };
//        a1.cry();

        System.out.println("=====================================================");

       /* Swim s1 = new Swim() {
            @Override
            public void swimming() {
                System.out.println("学生🏊‍贼快~~~~");
            }
        }; */

        // Lambda只能简化函数式接口的匿名内部类。
        Swim s1 = () -> {
            System.out.println("学生🏊‍贼快~~~~");
        };
        s1.swimming();
    }
}

abstract class Animal{
    public abstract void cry();
}

// 函数式接口:只有一个抽象方法的接口。
@FunctionalInterface // 声明函数式接口的注解。
interface Swim{
    void swimming();
}

3.3.2、示例2

import lombok.*;

@Data // getter setter toString
@NoArgsConstructor // 无参构造
@AllArgsConstructor // 全参构造
@Getter // getter
@Setter // setter
public class Student {
    // 姓名 年龄 身高 性别
    private String name;
    private int age;
    private double height;
    private char sex;
}
import javax.swing.*;
import java.util.Arrays;

public class LamdbaDemo2 {
    public static void main(String[] args) {
        // 目标:用Lambda表达式简化实际示例。
        test1();
        test2();
    }

    public static void test1(){
        Student[] students = new Student[6];
        students[0] = new Student("殷素素", 35, 171.5, '女');
        students[1] = new Student("杨幂", 28, 168.5, '女');
        students[2] = new Student("张无忌", 25, 181.5, '男');
        students[3] = new Student("小昭", 19, 165.5, '女');
        students[4] = new Student("赵敏", 27, 167.5, '女');
        students[5] = new Student("刘亦菲", 36, 168, '女');

        // 需求:按钮年龄升序排序。可以调用sun公司写好的API直接对数组进行排序。
//        Arrays.sort(students, new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return o1.getAge() - o2.getAge(); // 按照年龄升序!
//            }
//        });

//        Arrays.sort(students, (Student o1, Student o2) -> {
//            return o1.getAge() - o2.getAge(); // 按照年龄升序!
//        });

//        Arrays.sort(students, (o1,  o2) -> {
//            return o1.getAge() - o2.getAge(); // 按照年龄升序!
//        });

        Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());

        // 遍历数组中的学生对象并输出
        for (int i = 0; i < students.length; i++) {
            Student s = students[i];
            System.out.println(s);
        }
    }

    public static void test2(){
        JFrame win = new JFrame("登录窗口");
        win.setSize(300, 200);
        win.setLocationRelativeTo(null); // 居中显示。
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        win.add(panel);

        JButton btn = new JButton("登录");
        panel.add(btn);
        // java要求必须给这个按钮添加一个点击事件监听器对象,这样就可以监听用户的点击操作,就可以做出反应。
        // 开发中不是我们要主动去写匿名内部类,而是用别人的功能的时候,别人可以让我们写一个匿名内部类吗,我们才会写!!
//        btn.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                System.out.println("登录成功!");
//            }
//        });

//        btn.addActionListener((ActionEvent e) -> {
//                System.out.println("登录成功!");
//        });

//        btn.addActionListener((e) -> {
//            System.out.println("登录成功!");
//        });

//        btn.addActionListener(e -> {
//            System.out.println("登录成功!");
//        });

        btn.addActionListener(e ->  System.out.println("登录成功!"));

        win.setVisible(true);
    }
}

四、方法引用

4.1、概述

4.1.1、介绍

方法引用可以拆分为方法和引用两方面:

方法引用:把已经有的方法拿过来用,当作函数接口中抽象方法的方法体。

方法引用符:::

4.1.2、使用条件

 并不是所有的方法都可以直接引用,需要满足以下四种条件

  • 引用处必须是函数式接口
  • 被引用的方法必须已经存在
  • 被引用方法的形参和返回值必须和抽象方法保持一致
  • 被引用方法的功能要满足当前需求

4.1.3、示例

public class FunctionDemo {
	public static void main(String[] args) {
		// 需求: 床技术组,进行倒序排列
		Integer[] arr = { 3, 5, 4, 1, 6, 2 };
		// 通过层层递进 进一步学习方法引用
 
		//匿名内部类
		Arrays.sort(arr, new Comparator<Integer>() {
			@Override
			public int compare(Integer o1,Integer o2) {
				return o2 -o1;
			}
		});
		System.out.println(Arrays.toString(arr));
		
		//lambda表达式
		//因为第二个参数的类型Comparator是一个函数式接口
		Arrays.sort(arr, (Integer o1,Integer o2) -> {
			return o2 - o1;
		});
				
		//lambda表达式简化格式
		Arrays.sort(arr, (o1,o2) -> o2 - o1);
 
		//方法引用
		//1.引用处必须是函数式接口
		//2.被引用的方法必须已经存在
		//3.被引用方法的形参和返回值必须和抽象方法保持一致
		//4.被引用方法的功能要满足当前需求
		
		//表示引用FunctionDemo中的substraction方法
		//把这个方法当作抽象方法的方法体
		Arrays.sort(arr, FunctionDemo::subStraction);
		System.out.println(Arrays.toString(arr));
		
	}
	//可以使Java已经写好的 ,也可以是一些第三方工具类
	//静态方法 类名调用
	public static int subStraction(int num1,int num2) {
		return num2 - num1 ;
	}
}

4.2、方法引用的分类

4.2.1、引用静态方法

格式: 类名:: 静态方法

范例: Integer:: parseInt

public class FunctionTest {
	public static void main(String[] args) {
		//1.创建集合并添加对象
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "1","2","3","4","5");
		
		//2.转变成int类型
		list.stream().map(new Function<String, Integer>() {
			@Override
			public Integer apply(String s) {
				return Integer.parseInt(s);
			}
		}).forEach(s -> System.out.println(s));
		
		//1.方法需要已经存在
		//2.方法的形参和返回值需要和抽象方法的形参和返回值保持一致
		//3.方法的功能需要把形参的字符串转换为整数
		
		//方法引用
		//list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s));
        list.stream().map(Integer::parseInt).forEach(System.out::println);
	}
}

4.2.2、引用成员方法

格式:对象::成员方法

4.2.2.1、引用其他类的成员方法

其他类:其他类对象::方法名

public class FunctionTest {
	public static void main(String[] args) {
		//1.创建集合
		ArrayList<String> list =new ArrayList<>();
		//2.添加数据
		Collections.addAll(list, "张大三","李四","王五","赵六","张七");
		
		//3.过滤数据//lambda表达式
		list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3 ).forEach(s->System.out.println(s)); //张大三
		
        //匿名内部类
		list.stream().filter(new Predicate<String>() {
			@Override
			public boolean test(String s) {
			return	s.startsWith("张") && s.length() == 3;
			}
		}).forEach(s->System.out.println(s));
		
		//4.方法引用
		StringOperation so = new StringOperation();
		//list.stream().filter(so::StringJudge).forEach(s->System.out.println(s));
        list.stream().filter(so::StringJudge).forEach(System.out::println);
	}
}
public class StringOperation {
	public boolean StringJudge(String s) {
		return s.startsWith("张") && s.length() == 3;
	}
}
4.2.2.2、引用本类或父类的成员方法

本类:this::方法名

父类:super::方法名

注意:引用处不能是静态方法

4.2.3、引用构造方法

格式:类名::new

范例:student::new

public class FunctionDemo03 {
	public static void main(String[] args) {
		// 1.创建集合对象
		ArrayList<String> list = new ArrayList<>();
		// 2.添加数据
		Collections.addAll(list, "张三,23", "李四,24", "王五,25", "赵六,26");
 
		// 3.封装成Student对象 并且收集到list集合中
		List<Student> newList = list.stream()
				.map(new Function<String, Student>() {
			@Override
			public Student apply(String s) {
				String[] arr = s.split(",");
				String name = arr[0];
 
				int age = Integer.parseInt(arr[1]);
				return new Student(name, age);
			}
		}).collect(Collectors.toList());
		System.out.println(newList);
 
		// 引用构造方法
		List<Student> newList2 = list.stream().map(Student::new).collect(Collectors.toList());
		System.out.println(newList2);
	}
}
public class Student {
	private String name;
	private int age;
	
	public Student() {}
	public Student(String str) {
		String[] arr = str.split(",");
		this. name = arr[0];
		
		this.age = Integer.parseInt(arr[1]);
	}
	public Student(String name,int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

4.2.4、其他调用方法

4.2.4.1、类名引用成员方法

格式:类名::成员方法

范例:String :: subString

局限性:
不能引用所有类中的成员方法。
与抽象方法第一个参数有关,参数类型是什么那么就只能一怒用这个类中的方法。

public class FunctionDemo04 {
	public static void main(String[] args) {
		//抽象方法形参详解:
//		第一个参数: 表示被引用方法的调用者,决定了可以引用哪些类中的方法
//		           在Stream流中,第一个参数一般表示流里面的每一个数据
//		      假设流连的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
//		      
//		第二个参数到最后一个参数: 与被引用方法的形参保持一致
//		        如果没有第一个参数,说明被引用的方法需要时无参的成员方法 	
		
		// 1.创建集合对象
		ArrayList<String> list = new ArrayList<>();
		// 2.添加数据
		Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");
		
		//3.变成大写再输出
		//匿名内部类
		//String --> String
		list.stream().map(new Function<String, String>() {
			@Override
			public String apply(String s) {
				return s.toUpperCase();	
			}
		}).forEach(s -> System.out.println(s));
		
		//类名引用
		//list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s)); 
        list.stream().map(String::toUpperCase).forEach(System.out::println);
	}
}
4.2.4.2、引用数组的构造方法

格式:数据类型[ ] :: new

范例:int[ ] :: new

public class FunctionDemo05 {
	public static void main(String[] args) {
		//细节:数组类型需要和数据类型保持一致
		
		// 1.创建集合并添加数据
		ArrayList<Integer> list = new ArrayList<>();
		Collections.addAll(list, 1, 2, 3, 4, 5);
		
		//2.创建数组 数据收集到数组中
		//匿名内部类
		Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {
			@Override
			public Integer[] apply(int value) {
				return new Integer[value];
			}
		});
		System.out.println(Arrays.toString(arr));
		
		//方法引用
		Integer[] arr2 = list.stream().toArray(Integer[]::new);
        System.out.println(Arrays.toString(arr2));
	}
}

4.2.5、区别4.2.2与4.2.4.1

对象::成员方法-----类名::成员方法

类名::成员方法

不能引用所有类中的成员方法

如果抽象方法的第一个参数是A类型的只能引用A类中的方法

4.3、方法引用综合小练习

4.3.1、转为自定义对象并且收集到数组

需求:

集合中存储一些字符串的数据,比如:张三,23。
收集到Student类型的数组当中(使用方法引用完成)

public class FunctionText {
	public static void main(String[] args) {
		// 1.创建集合对象
		ArrayList<String> list = new ArrayList<>();
		// 2.添加数据
		Collections.addAll(list, "张三,23", "李四,24", "王五,25", "赵六,26");
		
		
		//3.收集到Student类型的数组中
		//先把字符变成Student对象  再把Student对象收集起来
		
		//此时流中数据是Student还是String类型呢?  -> Student类型
		Student[] arr =list.stream()
				//先把字符变成Student对象
				.map(Student::new)
				//数组构造方法 -》构建数组并将数据存放进去
				.toArray(Student[]::new);
		
		System.out.println(Arrays.toString(arr));
	}
}

4.3.2、获取部分属性并收集到数组

需求:

创建集合添加学生对象,学生对象属性:name,age
只获取姓名并放到数组当中(使用方法引用完成)

public class FunctionText {
	public static void main(String[] args) {
		//方法引用小技巧:
		//1.现在有没有一个方法符合当前需求
		//2.如果有,则看这个方法是否满足引用的规则
		//静态: 类名::方法名
		//成员方法:本类中:类名::方法名 this 
		//         其他类中: 对象名::方法名 super
		//构造方法:类名:: new
		
		// 1.创建集合
		ArrayList<Student> list = new ArrayList<>();
		// 2.添加元素
		list.add(new Student("张三", 23));
		list.add(new Student("李四", 24));
		list.add(new Student("王五", 25));
 
		// 3.获取姓名添加进数组
		// 匿名内部类
		String[] arr = list.stream().map(new Function<Student, String>() {
			@Override
			public String apply(Student student) {
				return student.getName();
			}
		}).toArray(String[]::new);
		System.out.println(Arrays.toString(arr));
		
		//方法引用
		String[] arr2 = list.stream().map(Student::getName).toArray(String[]::new);
		System.out.println(Arrays.toString(arr2));
	}
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐