Lambda表达式
jdk8之后的新语法形式
/*
(匿名内部类重写方法的形参) ->{
被重写方法的方法体代码
}
*/
简化接口中只有一个抽象方法的函数式接口
List集合
Set集合
- Set:无序、不重复、无索引
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序(天然排序)、不重复、无索引
HashSet底层原理
(数组+链表、红黑树)JDK8
当链表长度大于8的时候转成红黑树
长度为16 数组名为table 当元素=16*0.75=12时,自动扩容,每次扩容为原来的2倍
哈希值:根据地址根据某种特殊的规则推算出的int类型的数值
哈希表:对增删改查性能都很好的结构
hashset集合hashCode() equals()可以重写 javabean中右键重写
只要结果一样
linkedhashset集合 双链表
TreeSet集合默认的规则
对于数值类型:int double,官方默认按照大小进行升序排序
对于字符型:按照首字母的编号排序
对于对象类型:TreeSet需要自定义规则 implements Comparable<对象类型>
两种方式的比较规则:
如果认为第一个元素大于第二个元素返回正整数即可。
如果认为第一个元素小于第二个元素返回负整数即可。
如果认为第一个元素等于第二个元素返回0即可。
此时TreeSet集合会保留一个元素,认为两者重复。
方式一:在实体类中重写比较规则
public int comparaTo(Apple o){
return this.weight - o.weight;//会去掉相等的
return this.weight - o.weight >= 0 ? 1: -1;//相等的也会保留
}
方式二:
注意:如果TreeSet集合存储对象有实现的比较规则,集合也有自带的比较器,默认使用集合自带的比较器排序
如果方式一与方式二冲突,会采用就近原则(采用方式二)
- 如果元素可以重复,又有索引,索引查询要快 ArrayList基于数组
- 如果希望元素可以重复,又有索引,增删收尾操作块 LinkedList基于链表
- 如果希望增删改查都快,但是元素不重复,无序,无索引 HashSet基于哈希表
- 如果希望增删改查都快,但是元素不重复,有序,无索引 LinkedList基于哈希表和双链表
- 如果要对对象进行排序 TreeSet 基于红黑树,后续可以用List集合实现排序
可变参数
可以接受多个数据
对外灵活,对内数组
public class Demo {
public static void main(String[] args) {
sum();
sum(10);
sum(10,20,30);
sum(new int[]{10,20,30,40});
}
//可变参数必须放在形参列表之后
public static void sum(int...nums){
//可变参数在方法内部就是一个数组 nums
System.out.println(Arrays.toString(nums));
}
}
Collections集合工具类
1、addAll:
public static void main(String[] args) {
List<String> sets = new ArrayList<>();
//简化多行代码 sets.add("xx");
Collections.addAll(sets,"楚留香","张无忌","陆小凤");
System.out.println(sets);
}
2、shuffle://打乱list集合顺序
public class SetDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list,10,20,15,5);
Collections.shuffle(list);
System.out.println(list);
}
}
3、sort:
public class SetDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list,10,20,15,5);
Collections.sort(list);
System.out.println(list);
}
}
如果存的是对象需要定义排序规则 implements Comparable<对象类型>
重写比较规则
public int comparaTo(Apple o){
return this.weight - o.weight;//相等也会保留 属性类型必须是int类型
}
Map集合
Map集合概述
- Map集合是一种双列集合,每个元素包含两个数据。
- Map集合的每个元素的格式:Key(键)=value(值)(键值对元素)
- Map集合也被称为“键值对集合”
整体格式
Collection集合的格式:[元素1,元素2,元素3…]
Map集合的完整格式:{key1=value1 , key2=value2 , key3=value3, …} //这是三个元素
Map集合体系的特点
-
Map集合的特点都是键决定的。
-
Map集合的键是无序,不重复,无索引,值不做要求
-
Map集合后面的键对应的值会覆盖前面重复的值
-
Map集合的键值对都可以为null
-
HashMap:无序,不重复,无索引
-
LinkedHashMap:有序,不重复,无索引
-
TreeMap:有序,不重复,无索引
public class SetDemo {
public static void main(String[] args) {
Map<String,Integer> maps1 = new HashMap<>();
Map<String,Integer> maps2 = new LinkedHashMap<>();
Map<String,Integer> maps3 = new TreeMap<>();
}
}
Map常用的API
eg: Map<String,Integer> maps= new HashMap<>();
- maps.clear();//清空集合
- maps.isEmpty();//判断是否为空
- Integer key= maps.get(“value”);//根据键值对的值求对应的key
- maps.remove(“key”);//根据key来删除当前的键值对 返回的类型应该是当前key对应的value
- maps.containsKey(“key”);//判断是否包含某个键
- maps.containsValue(“Value”);//判断是否包含某个值
- Set keys = maps.keySet(); //将maps中的键放到set集合中
- Collection values = maps.values();//将maps中的值放到Collection集合中
- maps.size();//集合的大小,即拥有几个元素
- map1.putAll(map2);//将集合中map2中元素拷贝到map1中
遍历map集合
方式一:键找值(推荐)
Set<String> keys = maps.keySet();
for(String key : keys){
int value = maps.get(key);
System.out.println(key+""+value);
}
方式二:键值对(麻烦)
Set<Map.Entry<String,Integer>> entries = maps.entrySet();
for(<Map.Entry<String,Integer> : entry : entries){
String key = entry.getKey();
int value = entry.getValue();
}
方式三:Lambda(特别推荐)
maps.forEach((k,v) ->{
System.out.println(k + "---->" + v);
});
不可变集合
定义:集合在整个生命周期不可改变,否则报错
//不可变的list集合
public class CollectionDemo {
public static woid main(string[] args) {
List<Double> lists = List.of(569.5,700.5,523.0,570.5);
lists.add(689.0);
system.out.println(lists);
}
}
//不可变的set集合
Set<String> names = Set.of("迪丽热巴","迪丽热九","马尔扎哈","卡尔眨巴”);
system.out.println(names) ;
//不可变的Map集合
of方法
Stream流
names.stream().filter(s -> s.starsWith("张")).filter
获取Stream流
1.1、Collection集合
Collection list = new ArrayList<>();
Stream s = list.stream();
1.2、Map集合
Map<String , Integer> maps = new HashMap<>();
Stream keyStream = maps.keySet().stream();
Stream valueStream = maps.values().stream();
Stream<Map.Entry<String,Integer>> keyAndValueStream = maps.entrySet().stream();
1.3、数组
String[] names = {“ab”,“cd”,“ef”,“ghi”};
Stream nameStream = Arrays.stream(names);
// Stream nameStream = Stream.of(name);
常用的API
多线程
方式一:继承Thread类
- 定义一个子类MyThread继承Thread,重写run()方法
- 创建MyThread类的对象
- 调用线程对象的start()方法启动线程(启动后执行的还是run方法)
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();//放在前边才是多线程
for (int i = 0; i < 5; i++) {
System.out.println("主线程~~" + i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程~~"+ i);
}
}
}
-
优点:代码简单
-
缺点:线程类已经继承Thread,无法继承其他类,不利于扩展
方式二:实现Runnable接口
方案1:定义一个线程任务类MyRunnable实现Runnable接口
- 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
- 创建MyRunnable任务对象
- 把MyRunnable任务对象交给Thread处理
- 调用线程对象的start()方法启动线程
public class ThreadDemo {
public static void main(String[] args) {
Runnable target = new MyRunnable();
Thread thread = new Thread(target);
thread.start();
for (int i = 0; i < 10 ; i++) {
System.out.println("主线程~" + i);
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程~" + i);
}
}
}
-
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
-
缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。
方案2:匿名内部类
public class ThreadDemo {
public static void main(String[] args) {
Runnable target = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程" + i);
}
}
};
Thread t = new Thread(target);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程" + i);
}
// 简化后的写法
// new Thread(new Runnable() {
// @Override
// public void run() {
// for (int i = 0; i < 5; i++) {
// System.out.println("子线程" + i);
// }
// }
// }).start();
// Lambda写法
// new Thread(() -> {
// for (int i = 0; i < 5; i++) {
// System.out.println("子线程" + i);
// }
// }).start();
均不能返回结果,不适合返回线程结果的业务场景
方式三:JDK5.0新增Callable接口
1、得到任务对象
定义一个实现Callable接口,重写call方法,封装要做的事情。
用FutureTask把Callable对象封装成线程任务对象。
2、把线程对象交给Thread处理
3、调用Thread的start方法启动线程,执行任务
4、线程执行完毕后,通过FutureTask的get方法去获取任务执行的结果
/**
* 实现Callable接口,用FutureTask把Callable对象封装成线程任务对象
*/
public class ThreadDemo {
public static void main(String[] args) {
MyCallable call1 = new MyCallable(100);
FutureTask<String> f1 = new FutureTask<>(call1);
Thread t1 = new Thread(f1);
t1.start();
MyCallable call2 = new MyCallable(100);
FutureTask<String> f2 = new FutureTask<>(call2);
Thread t2 = new Thread(f2);
t2.start();
try {
String rs1 = f1.get();
System.out.println("第一个:"+rs1);
} catch (Exception e) {
e.printStackTrace();
}
try {
String rs2 = f2.get();
System.out.println("第二个:"+rs2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String>{
//<>应该声明线程执行完毕后返回结果的类型
private int n;
public MyCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 0; i < 5; i++) {
sum+=i;
}
return "sum=" + sum;
}
}
优点:线程任务类只是实现结果,可以继续实现接口,扩展性强
缺点:编程复杂
多线程3
反射
获取class类对象
- 方式一:Class c1 = Class.forName(“全限名”);
- 方式二:Class c2 = 类名.class
- 方式三:Class c3 = 对象.getClass();
获取构造器对象
getDeclareConstructors()
getDeclareConstructors(Class<?> 参数)
public newInstance(Object … intitargs)
如果构造器是private类型的,暴力反射
setAccessible(boolean)
反射破坏了封装性,私有的也可以执行
定位全部成员变量
Field[ ] fields = c.getDeclaredFields();
根据名称定位某一个成员变量
Field f = c.getDeclaredField(“name”);
赋值
ageF.setAcessiable(ture);
Student s = new Student();
ageF.set(s , 18);//s.setAge(18);
取值
int age = (int) ageF.get(s);
Class c = Dog.class;
Methods[ ] methods = c.getDeclaredMethods();
//Method method = c.getDeclaredMethod(“name”,Object.class);
method.getName();//方法名称
method.getReturnType();//返回值类型
method.getParameterCount();//参数个数
方法.invoke(对象 , 参数);//返回方法的返回值