一、Integer等包装类要使用equals进行对比,否则会有问题。
public class HelloWorld {
public static void main(String[] args) {
Integer a=150;
Integer b=150;
Integer c = new Integer(20);
System.out.println(a==b);//false
System.out.println(a.equals(b));//true
}
}
二、List等列表遍历时移除要采用以下:
推荐做法:
Iterator<Integer> integerIterator = integerList.listIterator();
while(integerIterator.hasNext()){
Integer eachInteger = integerIterator.next();
if(eachInteger.equals(removeInteger)){
integerIterator.remove();
}
}
错误做法,会导致java.util.ConcurrentModificationException异常。代码如下:
for(Integer eachInteger:integerList){
if(eachInteger.equals(removeInteger)){
integerList.remove(eachInteger);
}
}
三、equals和hashCode
equals()和 hashcode()是java.lang.Object中提供的用以对象比较的两个重要方法,下面是其定义及默认实现:
public boolean equals(Object obj) {return (this == obj);}
用以判断变量参数与当前实例是否相等,JDK默认实现是基于对象内存地址是否相同,如果两个对象内存地址相同,则表示两个对象相同。
public native int hashCode();
默认情况下,该方法返回一个随机整数,对于每个对象来说该数字唯一,但该数字并非恒定,可能随着程序的执行发生变化。
但是这一性质并不符合场景,比如一个不允许有重复值的对象数组/LIST(CONTAINS方法)。通过重写可以实现。
Jdk的api建议:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,
该协定声明相等对象必须具有相等的哈希码。
class Person{
private String name;
private Integer age;
@Override
public boolean equals(Object obj) {
if(obj == this) return true;
if(obj == null) return false;
if(getClass() != obj.getClass()) return false;
Person other = (Person) obj;
return name.equals(other.name) && age.equals(other.age);
}
@Override
public int hashCode() {
String id = this.name + this.age + "";
return id.hashCode();
}
}
四、AtomicInteger原子操作类
1.为什么需要AtomicInteger原子操作类?
对于Java中的运算操作,例如自增或自减,若没有进行额外的同步操作,在多线程环境下就是线程不安全的。
num++解析为num=num+1,明显,这个操作不具备原子性,多线程并发共享这个变量时必然会出现问题。
测试代码如下:
public class AtomicIntegerTest {
private static final int THREADS_CONUT = 10;
public static volatile int count = 0;
public static void increase() { count++; }
public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_CONUT];
for (int i = 0; i < THREADS_CONUT; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
increase();
}
}
});
threads[i].start();
}
//当有活动线程时,不往下执行
while (Thread.activeCount() > 1) {Thread.yield();}
System.out.println(count);
}
}
每个线程对count变量进行1000此自增操作,实际结果却发现每次运行的结果都不相同。
2.要是换成volatile修饰count变量呢?
volatile关键字很重要的两个特性:
保证变量在线程间可见,对volatile变量所有的写操作都能立即反应到其他线程中,换句话说,volatile变量在各个线程中是一致的;
禁止指令的重排序优化;
经过测试数字仍然不正确,因为核心点在于java里的运算(比如自增)并不是原子性的。
3.用了AtomicInteger类后会变成什么样子呢?
public class AtomicIntegerTest {
private static final int THREADS_CONUT = 10;
public static AtomicInteger count = new AtomicInteger(0);
public static void increase() { count.incrementAndGet(); }
public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_CONUT];
for (int i = 0; i < THREADS_CONUT; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
increase();
}
}
});
threads[i].start();
}
while (Thread.activeCount() > 1) {Thread.yield();}
System.out.println(count);
}
}
结果每次都输出20000,程序输出了正确的结果,这都归功于AtomicInteger.incrementAndGet()方法的原子性。
五.TreeSet的使用
TreeSet集合:可以对Set集合中的元素进行排序。要求传入TreeSet的元素/对象实现了Comparable接口
class Person implements Comparable<Person>{
private String name;
private Integer age;
public int compareTo(Person o) {
Person p = (Person)o;
return age.compareTo(p.age);
}
}
java.util.TreeSet.pollFirst()用于检索和删除最小(第一个)元素。
六、ReentrantLock
相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:
1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。
通过lock.lockInterruptibly()来实现这个机制。
2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,
ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。ReenTrantLock提供了一个Condition(条件)类,
用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
六.创建新线程
Thread prodRaceThread = new Thread(new Runnable(){
public void run(){
try {
executeService.doProdRaceSales(prsThread);
} catch (Exception e) {
prsThread.setCalStatus(Constants.PRODRACE_CALSTATUS_HANDLEFAIL);
prodRaceSalesDao.updateProdRaceSales(prsThread);
LOGGER.error("竞赛计算失败", e);
}
}
},"FeeRecal-Batch");
prodRaceThread.start();
七.循环调用代码
public void getAllDependFailTask(List<Task> taskList, Task failTask, Set<Task> dependTasklist) {
Integer failTaskId = failTask.getId();
List<Task> checkList = taskList.stream().filter(t -> t.getDepsId().contains(String.valueOf(failTaskId))).collect(Collectors.toList());
dependTasklist.addAll(checkList);
checkList.stream().forEach(t -> getAllDependFailTask(taskList,t,dependTasklist));
}
八.ENUM枚举
package Enum;
public class EnumTest1 {
//常量定义(字符串)
enum WeekDay {SUN, MON, TUE, WED, THT, FRI, SAT}
//枚举接口
public interface Behaviour {String getColour();}
enum ColorEnum implements Behaviour{
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private ColorEnum(String name, int index) {this.name = name;this.index = index;}
// 普通方法
public static String getName(int index) {
for (ColorEnum c : ColorEnum.values()) {
if (c.getIndex() == index) {
return c.name;
}
} return null;
}
// get set 方法
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getIndex() {return index;}
public void setIndex(int index) {this.index = index;}
@Override
public String toString() {return this.index+"_"+this.name;}
public String getColour() {return this.name;}
}
public static void main(String args[]){
System.out.print(WeekDay.FRI+"\n");
System.out.print("Week每一天:");
for (WeekDay c : WeekDay.values()){
System.out.print(c+",");
}
System.out.println("RED:"+ColorEnum.RED.getName());
System.out.println("RED:"+ColorEnum.RED.getColour());
}
}
九.Springboot注解等
@SpringBootApplication
通常用在主类上, 包含@Configuration、@EnableAutoConfiguration、@ComponentScan
@RestController
用于标注控制层组件(如struts中的action),包含@Controller和@ResponseBody
@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
该注解有六个属性:
params:指定request中必须包含某些参数值是,才让该方法处理。
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
value:指定请求的实际地址,指定的地址可以是URI Template 模式
method:指定请求的method类型, GET、POST、PUT、DELETE等
consumes:指定处理请求的提交内容类型(Content-Type),如application/json,text/html;
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
@ResponseBody
表示该方法的返回结果直接写入HTTP response body中
一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析
为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@responsebody后,会直接返回json数据。
@RequestBody
允许request的参数在request体中,而不是在直接连接的地址后面。(放在参数前)
@RequestParam
是来自HTTP请求体或请求url的QueryString中。
十.Java8新特性
1.Optional
Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常
import java.util.Optional;
class Person{
private String name;
public String getName() {return name;}
public Person(String name){this.name = name;}
}
public class OptionalTest {
public static void main(String args[]) throws Exception {
OptionalTest java8Tester = new OptionalTest();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a, b));
//Optional.ofNullable.orElseThrow 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
Integer c = Optional.ofNullable(value1).orElseThrow(() -> new Exception("当前对象为空!"));
//Optional.map 若有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
String d = a.map(a1 -> String.valueOf(a1)).orElse(null);
Person p = new Person("小明");
Optional<String> pName1 = Optional.ofNullable(p).map(Person::getName);
String pName = Optional.ofNullable(p).map(Person::getName).orElse("");
}
public Integer sum(Optional<Integer> a, Optional<Integer> b) {
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
Lambda表达式
Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中), 使用Lambda表达式可以使代码变的更加简洁紧凑。
示例:
// Java 8之前:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
//Java 8方式:
new Thread(()-> System.out.println("Before Java8, too much code for too little to do")).start();
lambda 表达式的语法格式如下:
() -> {}()
Lambda语法解析:
括号就是接口方法的括号,接口方法如果有参数,也需要写参数。只有一个参数时, 括号可以省略。
-> : 分割左右部分的, 没啥好讲的。
{} : 要实现的方法体。只有一行代码时, 可以不加括号, 可以不写return。
注意:Lambda表达式要求首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
Lambda表达式简单例子:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
代码示例:
package com.erayt;
public class Java8Tester {
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
public static void main(String args[]){
Java8Tester tester = new Java8Tester();
// 类型声明
MathOperation addition = (int a,int b) -> a + b;
// 不用类型声明
MathOperation subtraction = (a, b) -> a - b;
// 大括号中的返回语句
MathOperation multiplication = (int a, int b) -> { return a * b; };
// 没有大括号及返回语句
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// 不用括号
GreetingService greetService1 = message1 -> System.out.println("Hello " + message1);
// 用括号
GreetingService greetService2 = (message2) -> System.out.println("Hello " + message2);
greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}