集合的使用
数组和List
// 二维数组的排序,先按照第一个数的降序排序,第一个数相等的情况安装第二个数的升序排序
int[][] array2 ={
{1,1,3},{1,5,6}
};
Arrays.sort(array2, (o1, o2) -> o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0]);
首先按照数组元素的第一个值进行降序排序,如果第一个值相等,则按照第二个值进行升序排序。
for (int[] ints : array2) {
System.out.println(Arrays.toString(ints));
}
// int[] --> Integer[]
int[] arr = {1, 2, 3, 4, 5};
Integer[] integers = Arrays.stream(arr).boxed().toArray(Integer[]::new);
// Integer[] --> int[]
int[] ints = Arrays.stream(integers).mapToInt(Integer::valueOf).toArray();
for (int[] ints : array2) {
Integer[] integers1 = Arrays.stream(ints).boxed().toArray(Integer[]::new);
System.out.println(Arrays.deepToString(integers1));
}
队列数组,一维数组中存储的是队列,队列中存储字符
Deque<Character>[] arrayDeques = new ArrayDeque[10];
初始化 list
,并且添加新的元素
List<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2)) {{ add(0); }};
// list 求和
int sum = list.stream().mapToInt(i -> i).sum();
// list 转化为数组,打印数组内容,lambda 表达式进行简化
int[] array = list.stream().mapToInt(Integer::intValue).toArray();
int[] lambdaArray = list.stream().mapToInt(i -> i).toArray();
// 整形返回数组的最大值
int arrayMax = Arrays.stream(array).max().getAsInt();
// forEach 快速输出
list.forEach(System.out::println);
// 这里使用【listBug.add】可能会导致UnsupportedOperationException
List<Integer> listBug = Arrays.asList(1, 2, 3);
listBug.add(3);
数组静态内部的ArrayList
类,长度不可变,重新构造之后,移除元素出现数组 长度动态修改
ArrayList<String> removeList = new ArrayList<String>(Arrays.asList("a", "b", "c", "d","a","a","A"));
for (int i = 0; i < removeList.size(); i++) {
removeList.remove(i);
}
System.out.println(removeList);
结果一定是[b, d, a]
类型擦除
ArrayList<String> list1 = new ArrayList<String>();
list1.add("abc");
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(123);
System.out.println(list1.getClass() == list2.getClass());
结果是true
map
// 在新建 map 时候初始化 map,需要带上后面的形参,否则爆 无法将 '<>' 用于匿名内部类
// var map1 = new HashMap<Integer, Integer>(); var 编译参数是 JDK10+ 提出
Map<String, Integer> map = new HashMap<String, Integer>() {{
put("a", 0);
put("e", 1);
put("i", 2);
put("o", 3);
put("u", 4);
}};
// 获取 map 值集合中的最大值
Integer maxValue = map.values().stream().max(Integer::compare).get();
// 获取 map 中 values 最大值对应的 key , values 相同的话选取较小的 key
map.entrySet().stream().filter(e-> Objects.equals(e.getValue(),maxValue)).min(Map.Entry.comparingByKey()).get().getKey();
PriorityQueue
优先队列
public class PriorityQueueApiTest {
public static void main(String[] args){
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new MyComparator());
priorityQueue.offer(6);
priorityQueue.offer(3);
priorityQueue.offer(5);
// new PriorityQueue<>((a,b)->b.compareTo(a)); 由大到小弹出,默认由小到大
System.out.println("PriorityQueue 弹出元素");
System.out.println(priorityQueue.poll());
System.out.println(priorityQueue.poll());
System.out.println(priorityQueue.poll());
// 优先队列的迭代打印,首部默认最小元素其余按照链表打印
Iterator<Integer> iterator = priorityQueue.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
private static class MyComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
int value = o1.compareTo(o2);
if (value == 0) {
return 0;
}
return value < 0 ? 1 : -1;
}
}
}
stream
@Test
public void filterStreamTest() {
List<String> words = Arrays.stream("as as aa s".split(" ")).collect(Collectors.toList());
System.out.println(words);
long filterCount = words.parallelStream().filter(word -> word.length() > 3).count();
System.out.println(filterCount);
long distinctCount = words.parallelStream().distinct().count();
System.out.println(distinctCount);
List<Integer> map = words.parallelStream().map(String::toUpperCase).map(String::length).collect(Collectors.toList());
System.out.println(map);
boolean allMatch = words.stream().allMatch(word -> word.length() > 1);
System.out.println(allMatch);
words = Arrays.asList("a","aa","aaa","aaaa");
List<String> collect = words.stream().parallel().filter(word -> word.length() < 2).collect(Collectors.toList());
System.out.println(collect);
Optional<String> any = words.stream().parallel().filter(word -> word.length() < 2).findAny();
System.out.println(any.orElse("no"));
}
结果依次是
[as, as, aa, s]
0
3
[2, 2, 2, 1]
false
[a]
a
Arrays.stream("as as aa s".split(" ")).collect(Collectors.toList())
字符串分割后的数组转为集合
words.parallelStream().filter(word -> word.length() > 3).count()
集合并行流过滤出字符串长度大于3
的数目
words.parallelStream().distinct().count()
集合并行流去重后集合的数量
words.parallelStream().map(String::toUpperCase).map(String::length).collect(Collectors.toList())
集合并行流处理后将字符串映射全大写的,在映射为字符串的长度,收集为集合返回
words.stream().allMatch(word -> word.length() > 1)
集合转化为流匹配每一个字符串是否存在长度大于1
words.stream().parallel().filter(word -> word.length() < 2).collect(Collectors.toList())
集合转为流,并行过滤出集合元素长度小于2
的收集为集合
words.stream().parallel().filter(word -> word.length() < 2).findAny()
集合转为流并行处理过滤长度小于2
的能否找到一个,找到的话any.orElse("no")
或者any.get()
输出找到的数据,没有就输出no
函数型接口
供给型接口 接受一个输入参数T,返回一个结果R。
@Test
public void applyApi0416(){
Function<String, String> apply = new Function<String, String>() {
@Override
public String apply(String s) {
return s;
}
};
System.out.println(apply.apply("apply function interface"));
// lambda 表达式简化
Function<String,String> lambdaApply = ((s -> {return s;}));
System.out.println(lambdaApply.apply("lambdaApply"));
}
消费型接口函数 接受一个输入参数并且无返回值。没有出参,常用于打印、发送短信等消费动作
@Test
public void consumerApi0416(){
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s.concat("--->accept"));
}
};
consumer.accept("hello");
// lambda 表达式简化
Consumer<String> lambdaConsumer = (String s)->{
System.out.println(s.concat("--->lambdaConsumer"));
};
lambdaConsumer.accept("world");
}
断言式函数接口:接受一个输入参数T,返回一个布尔值结果。常用于条件判断
@Test
public void predicateApi0416(){
Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String s) {
return s.isEmpty();
}
@Override
public Predicate<String> negate() {
return Predicate.super.negate();
}
@Override
public Predicate<String> or(Predicate<? super String> other) {
return Predicate.super.or(other);
}
};
System.out.println(predicate.test(""));
System.out.println(predicate.negate());
// lambda 简化
Predicate<String> lambdaPredicate = ((str) -> {
return !str.isEmpty();
});
System.out.println(lambdaPredicate.test(""));
}
供需型接口函数 无输入参数,返回一个结果T。常用于符合条件时调用获取结果;运行结果提前定义,但不运行。
@Test
public void supplierApi0416(){
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "get()";
}
};
System.out.println(supplier.get());
// lambda 表达式简化
Supplier<Integer> lambdaSupplier = ()->{return 1024;};
System.out.println(lambdaSupplier.get());
}
线程
线程的创建和启动
public class ThreadCreateApiTest {
private volatile int tickets = 50;
@Test
public void threadCreate0416() throws ExecutionException, InterruptedException {
MyThread1 myThread1 = new MyThread1();
MyThread2 myThread2 = new MyThread2();
Mythread3 mythread3 = new Mythread3();
new Thread(myThread1,"thread").start();
new Thread(myThread2,"runnable").start();
FutureTask<String> futureTask = new FutureTask<>(mythread3);
new Thread(futureTask,"callable1").start();
new Thread(futureTask,"callable2").start();
System.out.println(futureTask.get());
}
/**
* 创建线程方法一
* 继承 Thread 类
* 重写 run() 包含了业务,多线程考虑酌情加锁
* 创建对象,对象调用 start() 开启线程
*/
class MyThread1 extends Thread{
@Override
public synchronized void run() {
// Thread.currentThread().getName() 获取当前线程的名字
while (true){
if (tickets <= 0) {
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ tickets -- +"张票");
}
}
}
/**
* 创建线程方法二
* 实现 Runnable 接口
* 重写 run() 包含了业务,多线程考虑酌情加锁
* 创建对象,对象作为 Thread 构造参数产生的对象去调用 start() 开启线程
*/
class MyThread2 implements Runnable{
@Override
public synchronized void run() {
while (true){
if (tickets <= 0) {
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ tickets -- +"张票");
}
}
}
/**
* 创建线程方法三
* 实现 Callable<String> 接口,形参是 call 的返回值类型
* 重写 call() 包含了业务,多线程考虑酌情加锁,返回值可通过 FutureTask 的 get() 获取
* 创建对象,对象作为 FutureTask 的构造参数传入 产生的 FutureTask 对象
* 这个 FutureTask 对象作为 Thread 的构造参数传入产生的对象调用 start() 开启线程
*/
class Mythread3 implements Callable<String>{
@Override
public synchronized String call() throws Exception {
while (true){
if (tickets <= 0) {
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ tickets -- +"张票");
}
return "Mythread3 mplements Callable 的 return";
}
}
}
线程安全的加锁
public class ThreadSaleTicketTest {
@Test
public void testSynchronizedSaleTicket() {
TicketWindow ticketWindow = new TicketWindow();
// 旧方式创建线程
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
ticketWindow.synchronizedSaleTicket();
}
}
},"Window A").start();
// 新方式创建线程
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticketWindow.synchronizedSaleTicket();
}
},"Window B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticketWindow.synchronizedSaleTicket();
}
},"Window C").start();
}
@Test
public void testLockSaleTicket(){
TicketWindow ticketWindow = new TicketWindow();
new Thread(() -> {
for (int i = 0; i < 30; i++) {
ticketWindow.lockSaleTicket();
}
}, "Window A").start();
new Thread(() -> {
for (int i = 0; i < 30; i++) {
ticketWindow.lockSaleTicket();
}
},"Window B").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticketWindow.lockSaleTicket();
}
},"Window C").start();
}
}
/**
* tickets:电影票,volatile 可见性,禁止指令重排序
* synchronizedSaleTicket():synchronized 关键字实现安全的买票
* lockSaleTicket():lock 实现类实现安全的买票
*/
class TicketWindow {
private volatile int tickets = 100;
private final Lock lock = new ReentrantLock(true);
public void synchronizedSaleTicket() {
while (tickets > 0) {
synchronized (TicketWindow.class) {
System.out.println(Thread.currentThread().getName() + "卖出了第 " + tickets-- + " 张票,剩余了 " + tickets + " 张票");
}
}
}
/**
* 存在问题:窗口有票,但是票没有卖完,原因窗口过度的买票,虚假信息穿透 if,将判断条件改为 while 即可解决
*/
public void lockSaleTicket() {
lock.lock();
try {
while (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了第 " + tickets-- + " 张票,剩余了 " + tickets + " 张票");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}