十八、设计模式与JDK新特性

1.设计模式

概述:是一套经人反复使用的代码设计经验的总结
           也可以理解为特定问题的特定的解决方案
 
 好处:可读性更强更容易复用

 设计模式的归类,分三大类:(23种)
 1.对象型模式:对象的创建方式;例如:单例,工厂模式等
 2.结构型模式:组织结构的包装;例如:装饰者模式(处理流),代理模式等
 3.行为型模式:对象的行为监听;例如:观察者模式等

1.1工厂模式

/*
 概述:从工厂中根据需求,获取产品(对象)  
 两种工厂模式:1.静态工厂; 2.实例工厂
 静态工厂使用:工厂类.静态方法   new 工厂对象.成员方法
 案例:从肉工厂中获取产品;例如1号车间-牛肉;2号车间-猪肉
 * 
 * */

class Factory{

	public static Object getObject(int num) {
		//违背了OCP原则:对外新增代码持开放状态,对内修改的代码持关闭状态
		//此处应该要固定好,增强可维护性
		if(num==1) {
			return new Beef();
		}else if(num==2) {
			return new Pig();
		}
		return null;
	}

	public static Object getObject(Class clazz) throws InstantiationException, IllegalAccessException {
		
		return clazz.newInstance();
	}
	
}

class Beef{
	
}

class Pig{
	
}

public class Test1 {
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
		System.out.println("请输入你要获取的产品:1.牛肉,2.猪肉");
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		//1.基本的静态工厂
		//弊端:违背ocp原则的设计,不够灵活,维护性差
		/*Object obj = Factory.getObject(num);
		System.out.println(obj);*/
		
		//2.静态工厂+反射=增强灵活性与可维护性;且使得代码变为软编码模式(配置文件灵活变更)
		//分析:Properties加载配置文件,根据输入的编号,得到value
		Properties properties = new Properties();
		properties.load(new FileInputStream("factory.properties"));
		String className = properties.getProperty(num+"");  //获取类名
		
		Class clazz = Class.forName(className);
		Object obj = Factory.getObject(clazz);
		System.out.println(obj);
	
	}
}

1.2单例

单例:
        目标:每次获取到的对象都是同一个对象
步骤:
        1.通过静态方法返回对象
        2.返回的对象是静态属性(静态属性只初始一份)
        3.属性私有化
单例中的饿汉式---立即加载的模式
单例中的懒汉式---延时加载的模式

======================饿汉式=======================
class MySingle{
	private MySingle() {}
	
	private static MySingle single = new MySingle();
	public static MySingle getInstance() {
		return single;  //饿汉式
	}
}
public class Test1 {
	public static void main(String[] args) {
		MySingle single1 = MySingle.getInstance();
		MySingle single2 = MySingle.getInstance();
		System.out.println(single1==single2);
 	}
}
====================懒汉式=======================
class MySingle2{
	private MySingle2() {}
	private static MySingle2 single;  //懒汉式
	public static MySingle2 getInstance() {
		if(single==null) {
			single = new MySingle2();  //懒汉式
		}
		return single;  
	}
}
public class Test2 {
	public static void main(String[] args) {
		MySingle2 single1 = MySingle2.getInstance();
		MySingle2 single2 = MySingle2.getInstance();
		System.out.println(single1==single2);
 	}
}
=============懒汉式在多线程中的安全隐患==============
//思考:两种单例模式,在多线程中哪种有安全隐患,请复现并处理---懒汉式
//分析:
//问题:创建线程类,多线程在run方法中调用getInstance方法; 
//看看getInstance的if判断中进入了几次,如果有多次,则出现了安全问题
//解决方案:加锁
class MySingle{
	private static MySingle single;
	public static  MySingle getInstance() {
		if(single==null) { //单例懒汉式线程安全提高效率的写法
			synchronized ("lock") {
				if(single==null) {
					System.out.println("实例化对象...");
					single = new MySingle();
				}
				
			}
		}
		
		return single;
		
	}
}

class MyThread extends Thread{
	@Override
	public void run() {
		//T1,T2,T3
		MySingle.getInstance();
	}
}
public class Test1 {
	public static void main(String[] args) {
		for(int i=0;i<10;i++) {
			new MyThread().start();
		}
	}
}

2.枚举

枚举:应用场景与状态值是一致的
        在枚举中提供了多个常量值,可以更方便的使用这些常量值进行逻辑判断
选择:
        1.如果状态值不多,直接选择静态常量
        2.如果状态值很多,可以使用枚举更方便更安全地使用这些常量值
案例:通过状态值来判断性别

枚举的本质
        1.继承Enum的终止类
        2.里面的枚举值是静态常量

//枚举应用:
enum MyEnum{
	//枚举值
	S_MAN,S_WOMAN
}

@Deprecated  //过期的注解,定义到类上,类过期;定义到方法上,方法过期
class MyClass{
	@Deprecated
	public void test() {
		
	}
}

//@interface:标注该注解类中只能有属性
@interface Annotation{
	//里面只能写属性
	 String name();  //定义属性未赋值
	 int age() default 30;  //定义属性并赋值
}

public class Test1 {
	public static final int SEX_MAN = 1;
	public static final int SEX_WOMAN = 2;
	
	public static void main(String[] args) {
		/*int sex = Test1.SEX_MAN;
		switch (sex) {
		case Test1.SEX_MAN:
			System.out.println("你选择的是男性");
			break;
		case Test1.SEX_WOMAN:
			System.out.println("你选择的是女性");
			break;
		default:
			System.out.println("您的输入有误~");
			break;
		}*/
		
		MyEnum en = MyEnum.S_MAN;
		switch (en) {
		case S_MAN:
			System.out.println("你选择的是男性");
			break;
		case S_WOMAN:
			System.out.println("你选择的是女性");
			break;
		default:
			System.out.println("您的输入有误~");
			break;
		}
	}
}

3.Lambda表达式

概述:特殊的匿名内部类,书写格式参照着匿名内部类来改造即可
用法:可以将lambda表达式(相当于匿名内部类的传参写法)以参数形式传递
lambda语法结构:
接口引用 = (参数)->{}
描述:->左边是匿名内部类中重写方法的参数
           ->右边是匿名内部类中的函数体及返回值
  
细节1:如果匿名内部类的重写方法体只有一条语句,return和{}可以省略
细节2:lambda表达式可以通过接口引用自动识别结构
细节3:()中只填写参数名即可;如果只有一个参数,则可省略()
细节4:形参列表为空,则保留()
细节5:lambda表达式不会单独生成内部类文件

3.1Lambda表达式案例

public class Test1 {
	public static void main(String[] args) {
		//案例1:线程的创建
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("启动子线程..");
			}
		}).start();
		//Lambda表达式:
		new Thread(()->System.out.println("lambda表达式启动")).start();
		
		
		//案例2:比较器方法
		Comparator<Integer> com = new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				return o1-o2;  //升序形式
			}
		};
		//lambda表达式:
		Comparator<Integer> com2 = (c1,c2)->c1-c2;
		
	}
}

3.2自定义函数式接口

函数式接口:也是lambda表达式的内容,约定了接口中只有一个方法

//自定义函数式接口:  定义usb接口
@FunctionalInterface  //函数式接口注解
interface IUsb{
	void connect(); //只能有一个方法
}
public class Test2 {
	public static void main(String[] args) {
		//匿名内部类
		IUsb usb = new IUsb() {
			@Override
			public void connect() {
				System.out.println("匿名内部类调用");
			}
		};
		usb.connect();
		//lambda表达式
		IUsb usb2 = ()->System.out.println("lambda表达式");
		usb2.connect();
	}
}

3.3系统提供的函数式接口

系统定义好的函数式接口
        1.消费型接口:Consumer
        2.供给型接口:Supplier
        3.函数型接口:Function
        4.断言型接口:Predicate
分析: 左边接口引用   右边先写匿名内部类,再改造成lambda表达式

public class Test3 {
	public static void main(String[] args) {
		//-----1.消费型接口:有参数无返回值类型-----
		Consumer<Integer> consumer = new Consumer<Integer>() {
			@Override
			public void accept(Integer t) {
				System.out.println("花费了"+t+"块钱");
			}
		};
		consumer.accept(600);
		
		Consumer<Integer> consumer2 = m->System.out.println("消费了"+m);
		consumer2.accept(800);
		
		//----2.供给型接口:无参数有返回值类型-----
		Supplier<Integer> supplier = new Supplier<Integer>() {
			@Override
			public Integer get() {
				return 6;  //往往返回随机值
			}
		};
		System.out.println(supplier.get());
		
		Supplier<Integer> supplier2 = ()->new Random().nextInt(8);
		System.out.println(supplier2.get());
		
		//----3.函数型接口:有参数有返回值类型-----
		Function<String, Integer> function = new Function<String, Integer>() {

			@Override
			public Integer apply(String t) {
				return t.length();  //传入字符串,返回长度
			}
		};
		System.out.println(function.apply("hello"));  //5
		
		Function<String, String> function2 = t->t.toUpperCase();
		System.out.println(function2.apply("hello"));  //HELLO
		
		
		//----4.断言型接口:有参数有返回值类型,返回boolean类型-----
		Predicate<Integer> predicate = new Predicate<Integer>() {

			@Override
			public boolean test(Integer t) {
				return t>5;
			}
		};
		System.out.println(predicate.test(6)); //true
		
		Predicate<Integer> predicate2 = t->t>5;
		System.out.println(predicate2.test(8));  //true
	}
}

3.4方法引用

是lambda表达式的简化写法;只不过用在特别的场景

//案例:打印方式的简写

public class Test4 {
	public static void main(String[] args) {
		//lambda表达式: 可以打印参数以外信息
		Consumer<Integer> con = m->System.out.println("消费了"+m);
		con.accept(600);
		//使用方法引用继续简化: 只能打印参数信息,特定场景使用
		Consumer<Integer> con2 = System.out::println;
		con2.accept(800);
		
	}
}

4.Stream

Stream:类似于集合,只不过集合是存数据的; Stream只是操作中间过程
Stream使用:
        1.创建Stream
        2.Stream的中间操作过程
        3.Stream的终止操作: 遍历

4.1Stream的创建

//1.Stream的创建:

public class Test1 {
	public static void main(String[] args) {
		//1.通过List集合获取Stream对象
		List<String> list = new ArrayList<String>();
		list.add("zs");
		list.add("ls");
		list.add("ww");
		//单线程流--有序
		list.stream().forEach(System.out::println);
		System.out.println("--------------");
		//多线程流--无序
		list.parallelStream().forEach(System.out::println);
		
		//Arrays方式创建Stream
		Arrays.stream(new int[]{1,3,2}).forEach(System.out::println);
		
		//Stream接口的of方法创建
		Stream.of("aa","cc","bb").forEach(System.out::println);
		
		//Stream接口的iterate方法创建: 迭代(参数1:初始值  参数2:在当前值基础上的迭代)
		//limit(4):中间过程,限制多少个
		Stream.iterate(2, t->t+1).limit(4).forEach(System.out::println);
		
		//Stream接口的generate方法创建
		System.out.println("-----");
		Stream.generate(()->new Random().nextInt(6)).limit(3).forEach(System.out::println);

		//IntStream的of,range,rangeClosed
		System.out.println("====of===");
		IntStream.of(3,5,8).forEach(System.out::println);
		System.out.println("====range:开区间,不包括最后一个===");
		IntStream.range(3, 6).forEach(System.out::println);
		System.out.println("====range:闭区间,包括最后一个===");
		IntStream.rangeClosed(3, 6).forEach(System.out::println);
	}
}

4.2Stream的过程操作

//Stream中间过程操作:
//案例:集合存储自定义对象,然后转Stream进行中间过程操作
class Person{
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
	}
	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 "Person [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
}
public class Test1 {
	public static void main(String[] args) {
		List<Person> list = new ArrayList<Person>();
		list.add(new Person("张三", 30));
		list.add(new Person("李四", 35));
		list.add(new Person("王五", 32));
		list.add(new Person("赵六", 36));
		list.add(new Person("李四", 35));
		System.out.println("filter:过滤");
		list.stream().filter(p->p.getAge()>=35).forEach(System.out::println);
		System.out.println("limit:限制");
		list.stream().limit(3).forEach(System.out::println);
		System.out.println("skip:跳过");
		list.stream().skip(1).forEach(System.out::println);
		
		System.out.println("distinct:去重--需重写hashCode和equals");
		list.stream().distinct().forEach(System.out::println);
		
		System.out.println("sorted:排序");
		list.stream().sorted((o1,o2)->o1.getAge()-o2.getAge()).forEach(System.out::println);
	
		System.out.println("map:映射");
		list.stream().map(p->p.getName()).forEach(System.out::println);
		
		System.out.println("parallel:多线程操作");
		list.stream().parallel().forEach(System.out::println);
		
	}
}

4.3Stream终止操作

//终止操作:
//获取到Stream的最终结果
public class Test2 {
	public static void main(String[] args) {
		List<Person> list = new ArrayList<Person>();
		list.add(new Person("张三", 30));
		list.add(new Person("李四", 35));
		list.add(new Person("王五", 32));
		list.add(new Person("赵六", 36));
		list.add(new Person("李四", 35));
		System.out.println("min:求最小值");
		System.out.println(list.stream().min((o1,o2)->o1.getAge()-o2.getAge()));
		System.out.println("max:求最大值");
		System.out.println(list.stream().max((o1,o2)->o1.getAge()-o2.getAge()));
		
		System.out.println("count:求个数");
		System.out.println(list.stream().count());
		
		System.out.println("reduce:汇总,先映射成age累加");
		System.out.println(list.stream().map(p->p.getAge()).reduce((a1,a2)->a1+a2).get());
		
		System.out.println("collect: 转其他集合输出");
		System.out.println(list.stream().collect(Collectors.toSet()));
	}
}

5.新的日期类

5.1日期类获取

本地日期类: LocalDate,LocalTime,LocalDateTime
场景:在单线程中我们可以直接使用Date即可;在多线中Date不具备安全性,所以需要使用本地日期

Instant: 时间戳    与时区有关,和本地时间差8小时

public class Test1 {
	public static void main(String[] args) {
		LocalDate localDate = LocalDate.now();
		System.out.println("本地日期:"+localDate);
		
		LocalTime localTime = LocalTime.now();
		System.out.println("本地时间:"+localTime);
		
		LocalDateTime localDateTime = LocalDateTime.now();
		System.out.println("本地日期与时间:"+localDateTime);
		
		Instant instant = Instant.now();
		System.out.println("时间戳:"+instant);
		
		Set<String> set = ZoneId.getAvailableZoneIds();
		for(String sq:set) {
			System.out.println(sq);
		}
		
		ZoneId zoneId = ZoneId.systemDefault();
		System.out.println("当前时区:"+zoneId);
		
		
	}
}

5.2日期类的转换

Date-->Instant--->LocalDateTime
LocalDateTime-->Instant-->Date

DateTimeFormatter: 本地日期格式类

public class Test2 {
	public static void main(String[] args) {
		Date date = new Date();
		//Date-->Instant
		Instant instant = date.toInstant();
		System.out.println("date转Instant:"+instant);
		
		//Instant-->LocalDateTime
		LocalDateTime ldt = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
		System.out.println("Instant转LocalDateTime:"+ldt);
		
		//LocalDateTime-->Instant
		Instant instant2 = ldt.atZone(ZoneId.systemDefault()).toInstant();
		System.out.println("LocalDateTime转Instant:"+instant2);
		
		//Instant-->Date
		System.out.println("Instant转Date:"+Date.from(instant2));
		
		//本地日期格式类
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
		//日期格式转出来是字符串类型
		System.out.println(dtf.format(LocalDateTime.now()));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值