java基础记录

如何跳出当前的多重嵌套循环

方法一:break 带上标识

public static void method1() {
    // 注意这里的标识
    ok:
    for(int i=0;i<10;i++){
        for(int j=0;j<10;j++){
            if(j==5){

                //跳到循环外的ok出,即终止整个循环
                break ok;
            }
        }
    }
}

方法二:定义 boolean 变量判断是否跳出

public static void method2(){
    int[][] arr = {{1,2,3},{4,5,6,7},{9}};
    boolean found = false;

    // 这里继续循环的条件是 i<arr.length && !found
    for(int i=0;i<arr.length && !found;i++){
        for(int j=0;j<arr[i].length;j++){
            if(arr[i][j]==5){
            
                //找到5,使外层循环判断条件变为false则终止整个循环
                found = true;

                //跳出当前循环
                break;
            }
        }
    }
}

拼接字符串

** 要高效拼接字符串,应该使用StringBuilder**
 String[] names = {"Bob", "Alice", "Grace"};
 var sb = new StringBuilder();
 sb.append("Hello ");
 for (String name : names) {
     sb.append(name).append(", ");
 }
 // 注意去掉最后的", ":
 sb.delete(sb.length() - 2, sb.length());
 sb.append("!");
 System.out.println(sb.toString());


Java标准库还提供了一个StringJoiner来干这个事:
用StringJoiner的结果少了前面的"Hello "和结尾的"!"!遇到这种情况,需要给StringJoiner指定“开头”和“结尾”:
   String[] names = {"Bob", "Alice", "Grace"};
     var sj = new StringJoiner(", ", "Hello ", "!");
     for (String name : names) {
         sj.add(name);
     }
     System.out.println(sj.toString());

String还提供了一个静态方法join(),这个方法在内部使用了StringJoiner来拼接字符串,在不需要指定“开头”和“结尾”的时候,用String.join()更方便:

String[] names = {"Bob", "Alice", "Grace"};
var s = String.join(", ", names);

大数

在Java中,由CPU原生提供的整型。使用long型整数可以直接通过CPU指令进行计算,速度非常快。

如果我们使用的整数范围超过了long型(最大范围是64位long型整数)怎么办?java.math.BigInteger就是用来表示任意大小的整数。BigInteger内部用一个int[]数组来模拟一个非常大的整数:

BigInteger做运算的时候,只能使用实例方法,例如,加法运算:

BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780

BigInteger用于表示任意大小的整数;
BigInteger是不变类,并且继承自Number;
将BigInteger转换成基本类型时可使用longValueExact()等方法保证结果准确。

BigDecimal可以表示一个任意大小且精度完全准确的浮点数。

BigDecimalscale()表示小数位数,例如:
BigDecimal d1 = new BigDecimal("123.45");
System.out.println(d1.scale()); // 2,两位小数

通过BigDecimalstripTrailingZeros()方法,可以将一个BigDecimal格式化为一个相等的,但去掉了末尾0BigDecimalBigDecimal d1 = new BigDecimal("123.4500");
BigDecimal d2 = d1.stripTrailingZeros();
System.out.println(d1.scale()); // 4
System.out.println(d2.scale()); // 2,因为去掉了00

BigDecimal d3 = new BigDecimal("1234500");
BigDecimal d4 = d3.stripTrailingZeros();
System.out.println(d3.scale()); // 0
System.out.println(d4.scale()); // -2
如果一个BigDecimalscale()返回负数,例如,-2,表示这个数是个整数,并且末尾有20

对BigDecimal做加、减、乘时,精度不会丢失,但是做除法时,存在无法除尽的情况,这时,就必须指定精度以及如何进行截断:

BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入
BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽

** 比较BigDecimal的值是否相等,必须使用compareTo()而不能使用equals()。**

SecureRandom:生成安全的随机数

集合

创建List 除了使用ArrayList和LinkedList,我们还可以通过List接口提供的of()方法,根据给定元素快速创建List:

List list = List.of(1, 2, 5);
但是List.of()方法不接受null值,如果传入null,会抛出NullPointerException异常。

Iterator对象实现也是不同的,但总是具有最高的访问效率。
Java的for each循环本身就可以帮我们使用Iterator遍历

使用EnumMap

如果Map的key是enum类型,推荐使用EnumMap,既保证速度,也不浪费空间。

import java.time.DayOfWeek;
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Map<DayOfWeek, String> map = new EnumMap<>(DayOfWeek.class);
        map.put(DayOfWeek.MONDAY, "星期一");
        map.put(DayOfWeek.TUESDAY, "星期二");
        map.put(DayOfWeek.WEDNESDAY, "星期三");
        map.put(DayOfWeek.THURSDAY, "星期四");
        map.put(DayOfWeek.FRIDAY, "星期五");
        map.put(DayOfWeek.SATURDAY, "星期六");
        map.put(DayOfWeek.SUNDAY, "星期日");
        System.out.println(map);
        System.out.println(map.get(DayOfWeek.MONDAY));
    }
}

TreeMap

还有一种Map,它在内部会对Key进行排序,这种Map就是SortedMap。注意到SortedMap是接口,它的实现类是TreeMap。
使用TreeMap时,放入的Key必须实现Comparable接口。String、Integer这些类已经实现了Comparable接口,因此可以直接作为Key使用。作为Value的对象则没有任何要求。

如果作为Key的class没有实现Comparable接口,那么,必须在创建TreeMap时同时指定一个自定义排序算法:

public class Main {
    public static void main(String[] args) {
        Map<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {
			public int compare(Student p1, Student p2) {
			    if (p1.score == p2.score) {
			        return 0;
			    }
			    return p1.score > p2.score ? -1 : 1;
			}
        });
        map.put(new Student("Tom", 77), 1);
        map.put(new Student("Bob", 66), 2);
        map.put(new Student("Lily", 99), 3);
        for (Student key : map.keySet()) {
            System.out.println(key);
        }
        System.out.println(map.get(new Student("Bob", 66))); // null?
    }
}

class Student {
    public String name;
    public int score;
    Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    public String toString() {
        return String.format("{%s: score=%d}", name, score);
    }
}

Properties

用Properties读取配置文件,一共有三步:
创建Properties实例; 调用load()读取文件;
调用getProperty()获取配置。

写入配置文件

Properties props = new Properties();
props.setProperty("url", "http://www.liaoxuefeng.com");
props.setProperty("language", "Java");
props.store(new FileOutputStream("C:\\conf\\setting.properties"), "这是写入的properties注释");

读取配置文件

可以从文件系统读取这个.properties文件:

String f = "setting.properties";
Properties props = new Properties();
props.load(new java.io.FileInputStream(f));

String filepath = props.getProperty("last_open_file");
String interval = props.getProperty("auto_save_interval", "120");

可以从classpath读取.properties文件,因为load(InputStream)方法接收一个InputStream实例,表示一个字节流,它不一定是文件流,也可以是从jar包中读取的资源流:

Properties props = new Properties();
props.load(getClass().getResourceAsStream("/common/setting.properties"));

由于load(InputStream)默认总是以ASCII编码读取字节流,所以会导致读到乱码。我们需要用另一个重载方法load(Reader)读取:

Properties props = new Properties();
props.load(new FileReader("settings.properties", StandardCharsets.UTF_8));

PriorityQueue优先队列

从队首获取元素时,总是获取优先级最高的元素。
PriorityQueue默认按元素比较的顺序排序(必须实现Comparable接口),也可以通过Comparator自定义排序算法(元素就不必实现Comparable接口)。

放入PriorityQueue的元素,必须实现Comparable接口,PriorityQueue会根据元素的排序顺序决定出队的优先级。

如果我们要放入的元素并没有实现Comparable接口怎么办?PriorityQueue允许我们提供一个Comparator对象来判断两个元素的顺序。我们以银行排队业务为例,实现一个PriorityQueue:

public class Main {
    public static void main(String[] args) {
        Queue<User> q = new PriorityQueue<>(new UserComparator());
        // 添加3个元素到队列:
        q.offer(new User("Bob", "A1"));
        q.offer(new User("Alice", "A2"));
        q.offer(new User("Boss", "V1"));
        System.out.println(q.poll()); // Boss/V1
        System.out.println(q.poll()); // Bob/A1
        System.out.println(q.poll()); // Alice/A2
        System.out.println(q.poll()); // null,因为队列为空
    }
}

class UserComparator implements Comparator<User> {
    public int compare(User u1, User u2) {
        if (u1.number.charAt(0) == u2.number.charAt(0)) {
            // 如果两人的号都是A开头或者都是V开头,比较号的大小:
            return u1.number.compareTo(u2.number);
        }
        if (u1.number.charAt(0) == 'V') {
            // u1的号码是V开头,优先级高:
            return -1;
        } else {
            return 1;
        }
    }
}

class User {
    public final String name;
    public final String number;

    public User(String name, String number) {
        this.name = name;
        this.number = number;
    }

    public String toString() {
        return name + "/" + number;
    }
}

使用Files

Files是java.nio包里面的类,封装了很多读写文件的简单方法,

例如,我们要把一个文件的全部内容读取为一个byte[],可以这么写:

byte[] data = Files.readAllBytes(Path.of("/path/to/file.txt"));

如果是文本文件,可以把一个文件的全部内容读取为String:

// 默认使用UTF-8编码读取:
String content1 = Files.readString(Path.of("/path/to/file.txt"));
// 可指定编码:
String content2 = Files.readString(Path.of("/path", "to", "file.txt"), StandardCharsets.ISO_8859_1);
// 按行读取并返回每行内容:
List<String> lines = Files.readAllLines(Path.of("/path/to/file.txt"));

写入文件也非常方便:

// 写入二进制文件:
byte[] data = ...
Files.write(Path.of("/path/to/file.txt"), data);
// 写入文本并指定编码:
Files.writeString(Path.of("/path/to/file.txt"), "文本内容...", StandardCharsets.ISO_8859_1);
// 按行写入文本:
List<String> lines = ...
Files.write(Path.of("/path/to/file.txt"), lines);

注意的是,Files提供的读写方法,受内存限制,只能读写小文件,例如配置文件等,不可一次读入几个G的大文件。读写大型文件仍然要使用文件流,每次只读写一部分文件内容。

Date

java.util.Date是用于表示一个日期和时间的对象

public class Main {
    public static void main(String[] args) {
        // 获取当前时间:
        Date date = new Date();
        System.out.println(date.getYear() + 1900); // 必须加上1900
        System.out.println(date.getMonth() + 1); // 0~11,必须加上1
        System.out.println(date.getDate()); // 1~31,不能加1
        // 转换为String:
        System.out.println(date.toString());
        // 转换为GMT时区:
        System.out.println(date.toGMTString());
        // 转换为本地时区:
        System.out.println(date.toLocaleString());
    }
}

LocalDateTime

从Java 8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:

本地日期和时间:LocalDateTime,LocalDate,LocalTime; 带时区的日期和时间:ZonedDateTime;
时刻:Instant; 时区:ZoneId,ZoneOffset; 时间间隔:Duration。
以及一套新的用于取代SimpleDateFormat的格式化类型 DateTimeFormatter。

java.time中以Instant类型表示,我们用Instant.now()获取当前时间戳,效果和System.currentTimeMillis()类似:

        Instant now = Instant.now();
        System.out.println(now.getEpochSecond()); // 秒
        System.out.println(now.toEpochMilli()); // 毫秒

** 具体: ** 添加链接描述

java主线程捕获子线程中的异常

package com.xueyou.demo.theadexceptiondemo;

import com.sun.glass.ui.TouchInputSupport;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class ThreadExceptionDemo {
    public static void main(String[] args) {
        try {
            Thread thread = new Thread(new ThreadExceptionRunner());
            thread.start();
        } catch (Exception e) {
            System.out.println("========");
            e.printStackTrace();
        } finally {
        }
        System.out.println(123);
        ExecutorService exec = Executors.newCachedThreadPool(new HandleThreadFactory());
        exec.execute(new ThreadExceptionRunner());
        exec.shutdown();
    }
}

class MyUncaughtExceptionHandle implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught " + e);
    }
}

class HandleThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        System.out.println("create thread t");
        Thread t = new Thread(r);
        System.out.println("set uncaughtException for t");
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandle());
        return t;
    }

}

上面的方式是设置每一个线程执行时候的异常处理。如果每一个线程的异常处理相同,我们可以用如下的方式进行处理,使用Thread的静态方法。

Thread.setDefaultUncaughtExceptionHandler(new
MyUncaughtExceptionHandle());

package com.xueyou.demo.theadexceptiondemo;

import com.sun.glass.ui.TouchInputSupport;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

/**
 * Created by wuxueyou on 2018/6/24.
 */
public class ThreadExceptionDemo {
    public static void main(String[] args) {
        try {
            Thread thread = new Thread(new ThreadExceptionRunner());
            thread.start();
        } catch (Exception e) {
            System.out.println("========");
            e.printStackTrace();
        } finally {
        }
        System.out.println(123);
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandle());
//        ExecutorService exec = Executors.newCachedThreadPool(new HandleThreadFactory());
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new ThreadExceptionRunner());
        exec.shutdown();

    }
}

ProcessBuilder执行命令

ProcessBuilderbuilder不支持包含空格的命令。

  String cmd = "cp";
 // 命令的各个部分组成一个字符串数组,用该数组创建ProcessBuilder对象
    String[] cmds = new String[] {cmd, "-rf", src, tag};
    ProcessBuilder builder = new ProcessBuilder(cmds);
    try {
        Process process = builder.start();
        process.waitFor();
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println(e.toString());
    }

Java执行cmd命令

一般java在执行CMD命令时,通常是使用Runtime.getRuntime.exec(command)来执行的

  public static void aaa(String stam){
    BufferedReader br = null;
    try {
      File file = new File("D:\\daemonTmp");
      File tmpFile = new File("D:\\daemonTmp\\temp.tmp");//新建一个用来存储结果的缓存文件
      if (!file.exists()){
        file.mkdirs();
      }
      if(!tmpFile.exists()) {
        tmpFile.createNewFile();
      }
      ProcessBuilder pb = new ProcessBuilder().command("cmd.exe", "/c", stam).inheritIO();
      pb.redirectErrorStream(true);//这里是把控制台中的红字变成了黑字,用通常的方法其实获取不到,控制台的结果是pb.start()方法内部输出的。
      pb.redirectOutput(tmpFile);//把执行结果输出。
      pb.start().waitFor();//等待语句执行完成,否则可能会读不到结果。
      InputStream in = new FileInputStream(tmpFile);
      br= new BufferedReader(new InputStreamReader(in));
      String line = null;
      while((line = br.readLine()) != null) {
        System.out.println(line);
      }
      br.close();
      br = null;
      tmpFile.delete();//卸磨杀驴。
      System.out.println("执行完成");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if(br != null) {
        try {
          br.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
// An highlighted block
public void executeBat() {
    try {
        Runtime run = Runtime.getRuntime();
        String cmd = "E:\\Re-Architecture\\test.bat"
        Process pro = run.exec(cmd);
        InputStream ers= pro.getErrorStream();
        pro.waitFor();
    } catch (IOException ioe) {
        ioe.printStackTrace();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

获取运行jar的路径

URL location = MethodHsdk.class.getProtectionDomain().getCodeSource().getLocation();
 String decode = URLDecoder.decode(location.getPath(), "utf-8");//转化为utf-8编码

http常见的状态码

下面给出一些状态码的适用场景:

100:客户端在发送POST数据给服务器前,征询服务器情况,看服务器是否处理POST的数据,如果不处理,客户端则不上传POST数据,如果处理,则POST上传数据。常用于POST大数据传输

206:一般用来做断点续传,或者是视频文件等大文件的加载

301:永久重定向会缓存。新域名替换旧域名,旧的域名不再使用时,用户访问旧域名时用301就重定向到新的域名

302:临时重定向不会缓存,常用 于未登陆的用户访问用户中心重定向到登录页面

304:协商缓存,告诉客户端有缓存,直接使用缓存中的数据,返回页面的只有头部信息,是没有内容部分

400:参数有误,请求无法被服务器识别

403:告诉客户端禁止访问该站点或者资源,如在外网环境下,然后访问只有内网IP才能访问的时候则返回

404:服务器找不到资源时,或者服务器拒绝请求又不想说明理由时

503:服务器停机维护时,主动用503响应请求或 nginx 设置限速,超过限速,会返回503

504:网关超时

数组转成 List

最原始的方式,就是通过遍历数组的方式,一个个将数组添加到 List 中。

int[] anArray = new int[] {1, 2, 3, 4, 5};

List<Integer> aList = new ArrayList<>();
for (int element : anArray) {
    aList.add(element);
}

更优雅的方式是通过 Arrays 类的 asList() 方法:

List<Integer> aList = Arrays.asList(anArray);

不过需要注意的是,Arrays.asList 的参数需要是 Integer 数组
还需要注意的是

Arrays.asList 方法返回的 ArrayList 并不是 java.util.ArrayList,它其实是 Arrays 类的一个内部类
如果需要添加元素或者删除元素的话,需要把它转成 java.util.ArrayList。

new ArrayList<>(Arrays.asList(anArray));

换另外一种方式

List<Integer> aList = Arrays.stream(anArray).boxed().collect(Collectors.toList());

Java 8 新增了 Stream 流的概念,这就意味着我们也可以将数组转成 Stream 进行操作。

String[] anArray = new String[] {"沉默王二", "一枚有趣的程序员", "好好珍重他"};
Stream<String> aStream = Arrays.stream(anArray);
如果想对数组进行排序的话,可以使用 Arrays 类提供的 sort() 方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值