Java 8 新特性简介
思维导图
并行流与串行流
Lambda表达式
package com.lambda;
import org.junit.Test;
import java.util.Comparator;
/**
* Lambda入门
*
* @author wty
* @date 2022/11/12 15:53
*/
public class Example01 {
@Test
public void example01(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("run1().");
}
};
r1.run();
// Lambda表达式
Runnable r2 = ()->System.out.println("run2().");
r2.run();
}
@Test
public void example02(){
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare = comparator1.compare(12, 21);
System.out.println(compare);
/**
* 返回结果:
* -1
* 说明前面小,后面大
*/
// Lambda表达式
Comparator<Integer> comparator2 = (o1,o2) -> Integer.compare(o1,o2);
int compare2 = comparator2.compare(32, 21);
System.out.println(compare2);
// 继续简化 方法引用
Comparator<Integer> comparator3 = Integer::compare;
int compare3 = comparator3.compare(21, 21);
System.out.println(compare3);
}
}
Lambda 表达式语法
语法格式一:无参,无返回值,Lambda体只需一条语句
语法格式二:Lambda需要一个参数
语法格式三:Lambda只需要一个参数时,参数的小括号可以省略
语法格式四:Lambda需要两个参数,并且有返回值
语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
语法格式六:
代码示例
package com.lambda;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
/**
* Lambda 表达式的使用
*
* 1.举例:(o1,o2) -> Integer.compare(o1,o2);
* 2.格式
* ->: lambda操作符/箭头操作符
* (o1,o2):lambda形参列表 其实就是接口中抽象方法的形参列表
* Integer.compare(o1,o2):lambda体 其实就是重写的抽象方法的方法体
* 3.lambda表达式的使用
* 4.本质:作为接口的实例(对象)
*
* 总结
* ->的左边 lambda形参列表的参数类型可以省略(类型推断),如果只有一个参数()可以省略,两个以及以上的不能省略
* ->的右边 lambda体,如果只有一条执行语句,大括号可以省略,如果有两条以及以上,则大括号不能省略,return一定要省略
*
* @author wty
* @date 2022/11/12 16:08
*/
public class LambdaTest01 {
@Test
public void test01(){
//语法格式一:无参,无返回值,Lambda体只需一条语句
Runnable runnable = ()->{
System.out.println("hello world");
};
runnable.run();
}
@Test
public void test02(){
// 语法格式二:Lambda需要一个参数
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("今天天气不错");
System.out.println();
// Lambda表示
Consumer<String> con2 = (String s)->{
System.out.println(s);
};
con2.accept("今天天气不错2");
}
@Test
public void test3(){
//语法格式三:Lambda只需要一个参数时,参数的小括号可以省略、参数类型也可以省略
// 也可以称为类型推断
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("hello");
Consumer<String> con2 = s -> System.out.println(s);
con2.accept("world");
}
@Test
public void test04(){
BinaryOperator<Long> binaryOperator = new BinaryOperator<Long>() {
@Override
public Long apply(Long x, Long y) {
System.out.println("实现apply");
return (x+y);
}
};
System.out.println(binaryOperator.apply((long) 1, (long) 2));
// 语法格式四:Lambda需要两个参数,并且有返回值
// Lambda表达式
BinaryOperator<Long> binaryOperator2 = (x,y) -> {
System.out.println("实现apply");
return (x+y);
};
System.out.println(binaryOperator2.apply((long) 2, (long) 3));
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer t1, Integer t2) {
return Integer.compare(t1,t2);
}
};
comparator1.compare(12,21);
// 使用Lambda表达式
Comparator<Integer> comparator2 = (t1,t2) -> Integer.compare(t1,t2);
comparator2.compare(12,21);
// 语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
BinaryOperator<Long> binaryOperator3 = (x,y) -> (x+y);
System.out.println(binaryOperator3.apply((long) 3, (long) 4));
}
@Test
public void test05(){
// 语法格式六:
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer t1, Integer t2) {
return Integer.compare(t1,t2);
}
};
int compare1 = comparator1.compare(12, 45);
System.out.println(compare1);
// 使用lambda表达式
Comparator<Integer> comparator2 = (t1,t2) -> Integer.compare(t1,t2);
int compare2 = comparator2.compare(12, 5);
System.out.println(compare2);
}
@Test
public void test8(){
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("天气不错");
// 使用lambda表达式
Consumer<String> consumer2 = s -> System.out.println(s);
consumer2.accept("是的");
}
}
函数式接口介绍
例如Runnable接口是函数式接口,上面有注解@FunctionalInterface
@FunctionalInterface
public interface Runnable {
void run();
}
自己写一个函数式接口
package com.lambda;
/**
* 自己写一个函数式接口
*
* @InterfaceName: MyInterface
* @Description:
* @Author: wty
* @Date: 2022/11/12
*/
@FunctionalInterface
public interface MyInterface {
void method1();
}
如何理解函数式接口
Java内置四大核心函数式接口
package com.lambda;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Java内置四大核心函数式接口
* 1.消费型Consumer<T> void accept(T t)
* 2.供给型Suppiler<T> T get()
* 3.函数型Function<T,R> R appply(T t)
* 4.断定型Predicate<T> boolean test(T t)
*
*
* @author wty
* @date 2022/11/12 23:00
*/
public class Lambda02 {
@Test
public void testLambda02(){
// 原来的写法
happyTime(599, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("您消费了"+aDouble);
}
});
// Lambda表达式
happyTime(400,aDouble -> System.out.println("您消费了"+aDouble));
}
// 消费型
public void happyTime(double money, Consumer<Double> consumer){
consumer.accept(money);
}
@Test
public void testLambda03(){
String array[] = {"北京","南京","天津","普京","烤面筋"};
List<String> list = Arrays.asList(array);
List<String> filter = filterString(list, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("京");
}
});
System.out.println(filter);
// 使用Lambda表达式
System.out.println("使用Lambda表达式");
List<String> filter2 = filterString(list, s -> s.contains("京"));
System.out.println(filter2);
}
/**
* 根据规则,过滤集合中的字符串,规则由Predicate方法指定
*
* @param
* @param: list
* @param: predicate
* @return java.util.List<java.lang.String>
* @date 2022/11/12 23:15
* @author wty
**/
public List<String> filterString(List<String> list, Predicate<String> predicate){
ArrayList<String> arrayList = new ArrayList<>();
for (String s : list) {
if (predicate.test(s)){
arrayList.add(s);
}
}
return arrayList;
}
}
其它接口
方法引用
方法引用代码示例
Employee
package com.methodreference;
/**
* @author wty
* @date 2022/11/12 23:48
*/
@SuppressWarnings("all")
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Employee() {
System.out.println("Employee().....");
}
public Employee(int id) {
this.id = id;
System.out.println("Employee(int id).....");
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Employee employee = (Employee) o;
if (id != employee.id)
return false;
if (age != employee.age)
return false;
if (Double.compare(employee.salary, salary) != 0)
return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(salary);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
MethodRefTest
package com.methodreference;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 方法引用的使用
* 1.使用的情境: 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
* 2.本质:Lambda表达式,而Lambda本质是函数式接口的实例(对象),所以方法的引用也是函数式接口的实例
* 3.格式: 类(或对象) :: 方法名
* 4.具体分为以下3种情况
* (1) 对象 :: 非静态方法
* (2) 类 :: 静态方法
* (3) 类 :: 非静态方法
* 5.方法引用使用的要求:针对情况(1)和情况(2)
* 接口 中的抽象方法的形参列表和返回值类型
* 与
* 方法引用 中的形参列表和返回值类型相同
*
* 6.接口方法的形参列表作为返回函数类型的形参列表之一 则可以使用方法引用
*
*
* @author wty
* @date 2022/11/12 23:51
*/
@SuppressWarnings({"all"})
public class MethodRefTest {
// 情况一:对象 :: 实例方法
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
@Test
public void test() {
Consumer<Double> consumer = new Consumer<Double>() {
@Override
public void accept(Double money) {
System.out.println(money);
}
};
consumer.accept(300.02);
// Lambda
Consumer<Double> consumer2 = money -> System.out.println(money);
consumer2.accept(301.02);
// 方法引用
/**
* 对象 :: 非静态方法
*/
PrintStream ps = System.out;
Consumer<Double> consumer3 = ps::println;
consumer2.accept(302.02);
}
//Supplier中的T get()
//Employee中的String getName()
@Test
public void test2() {
Employee employee = new Employee(1001,"小明",25,10000.22);
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return employee.getName();
}
};
System.out.println(supplier.get());
// 使用Lambda表达式
Supplier<String> supplier2 = () -> employee.getName();
System.out.println(supplier2.get());
// 使用方法引用
Supplier<String> supplier3 = employee :: getName;
System.out.println(supplier3.get());
}
// 情况二:类 :: 静态方法
//Comparator中的int compare(T t1,T t2)
// 静态方法
//Integer中的int compare(T t1,T t2)
@Test
public void test3() {
// (2) 类 :: 静态方法
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer t1, Integer t2) {
return Integer.compare(t1,t2);
}
};
System.out.println(comparator.compare(12, 31));
// Lambda表达式
Comparator<Integer> comparator2 = (t1,t2) -> Integer.compare(t1,t2);
System.out.println(comparator2.compare(0, 0));
// 使用 方法引用
Comparator<Integer> comparator3 = Integer :: compare;
System.out.println(comparator3.compare(12, 1));
}
//Function中的R apply(T t)
//Math中的Long round(Double d)
@Test
public void test4() {
Function<Double,Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double num) {
return Math.round(num);
}
};
System.out.println(function.apply(12.33));
// Lambda表达式
Function<Double,Long> function2 = num -> Math.round(num);
System.out.println(function2.apply(11.33));
// 方法引用
Function<Double,Long> function3 = Math :: round;
System.out.println(function3.apply(10.33));
}
// 情况三:类 :: 实例方法 (有难度)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
@Test
public void test5() {
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String t1, String t2) {
return t1.compareTo(t2);
}
};
System.out.println(comparator.compare("我喜欢", "我"));
// Lambda表达式
Comparator<String> comparator2 = (t1, t2) -> t1.compareTo(t2);
System.out.println(comparator2.compare("我和你", "我和你"));
// 方法引用
Comparator<String> comparator3 = String :: compareTo;
System.out.println(comparator3.compare("你", "我和你"));
}
//BiPredicate中的boolean test(T t1, T t2);
//String中的boolean t1.equals(t2)
@Test
public void test6() {
BiPredicate<String,String> biPredicate = new BiPredicate<String, String>() {
@Override
public boolean test(String s1, String s2) {
return s1.equals(s2);
}
};
System.out.println(biPredicate.test("我", "你"));
// Lambda表达式
BiPredicate<String,String> biPredicate2 = (s1,s2) -> s1.equals(s2);
System.out.println(biPredicate2.test("我", "我"));
// 方法引用
BiPredicate<String,String> biPredicate3 = String :: equals;
System.out.println(biPredicate3.test("你", "我"));
}
// Function中的R apply(T t)
// Employee中的String getName();
@Test
public void test7() {
Employee employee = new Employee(1002,"小玉",25,200.06);
Function<Employee,String> function = new Function<Employee, String>() {
@Override
public String apply(Employee employee) {
return employee.getName();
}
};
System.out.println(function.apply(employee));
// Lambda表达式
employee = new Employee(1003,"小智",24,200.06);
Function<Employee,String> function2 = employee2 -> employee2.getName();
System.out.println(function2.apply(employee));
// 方法引用
employee = new Employee(1004,"小霞",21,210.06);
Function<Employee,String> function3 = Employee :: getName;
System.out.println(function3.apply(employee));
}
/**
* Double 和 Long 的转换
*
* @param
* @return void
* @date 2022/11/13 10:02
* @author wty
**/
@Test
public void change(){
// Double > Long
Double a = 12.33;
Long b = a.longValue();
System.out.println(b);
// Long > Double
Long d = 17L;
Double c = d.doubleValue();
System.out.println(c);
}
}
构造器引用
格式
类名::new
代码示例
ConstructorRefTest
package com.methodreference;
import org.junit.Test;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 构造器引用
* 1.和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致
* 2.抽象方法的返回值类型即为构造器所属的类的类型
*
* @author wty
* @date 2022/11/13 10:34
*/
public class ConstructorRefTest {
//构造器引用
//Supplier中的T get()
//Employee的空参构造器:Employee()
@Test
public void test() {
Supplier<Employee> supplier = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
System.out.println(supplier.get());
// Lambda
Supplier<Employee> supplier2 = () -> new Employee();
System.out.println(supplier2.get());
// 构造器引用
Supplier<Employee> supplier3 = Employee :: new;
System.out.println(supplier3.get());
}
//Function中的R apply(T t)
@Test
public void test2() {
Function<Integer,Employee> function = new Function<Integer,Employee>() {
@Override
public Employee apply(Integer t1) {
return new Employee(t1);
}
};
function.apply(1006);
// Lambda
Function<Integer,Employee> function2 = t1 -> new Employee(t1);
function2.apply(1007);
// 构造器引用
Function<Integer,Employee> function3 = Employee :: new;
function3.apply(1008);
}
//BiFunction中的R apply(T t,U u)
@Test
public void test3() {
BiFunction<Integer,String,Employee> biFunction = new BiFunction<Integer, String, Employee>() {
@Override
public Employee apply(Integer integer, String s) {
return new Employee(integer,s);
}
};
biFunction.apply(1009,"小张");
// Lambda
BiFunction<Integer,String,Employee> biFunction2 = (integer,s) -> new Employee(integer,s);
biFunction2.apply(1010,"小李");
// 构造器引用
BiFunction<Integer,String,Employee> biFunction3 = Employee :: new;
biFunction3.apply(1011,"小刚");
}
}
数组引用
格式
数组类型 [ ]::new
代码示例
package com.methodreference;
import org.junit.Test;
import java.sql.Array;
import java.util.function.Function;
/**
* 数组引用
*
* 可以把数组看成是一个特殊的类,和构造器引用保持一致即可
*
* @author wty
* @date 2022/11/13 11:07
*/
public class ArrayRefTest {
//数组引用
//Function中的R apply(T t)
@Test
public void test4() {
Function<Integer, String[]> function = new Function<Integer, String[]>() {
@Override
public String[] apply(Integer integer) {
return new String[integer];
}
};
String[] array = function.apply(2);
for (String s : array) {
System.out.println(s);
}
System.out.println("=====Lambda=====");
// Lambda
Function<Integer, String[]> function2 = integer -> new String[integer];
String[] array2 = function2.apply(3);
for (String s : array2) {
System.out.println(s);
}
System.out.println("=====数组引用=====");
// 数组引用
Function<Integer, String[]> function3 = String[]:: new;
String[] array3 = function3.apply(4);
for (String s : array3) {
System.out.println(s);
}
}
}
强大的Stream API
为什么要使用Stream API
什么是Stream
Stream 的操作三个步骤
创建 Stream
创建 Stream方式一:通过集合
创建 Stream方式二:由数组创建流
创建 Stream方式三:由值创建流
创建 Stream方式四:由函数创建流:创建无限流
代码示例
EmployeeData
package com.methodreference;
import java.util.ArrayList;
import java.util.List;
/**
* @author wty
* @date 2022/11/12 23:49
*/
public class EmployeeData {
public static List<Employee> getEmployees(){
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001, "马化腾", 34, 6000.38));
list.add(new Employee(1002, "马云", 12, 9876.12));
list.add(new Employee(1003, "刘强东", 33, 3000.82));
list.add(new Employee(1004, "雷军", 26, 7657.37));
list.add(new Employee(1005, "李彦宏", 65, 5555.32));
list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
list.add(new Employee(1007, "任正非", 26, 4333.32));
list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
return list;
}
}
StreamAPITest
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* Stream API
*
* 1.Stream 关注的是数据的运算,与CPU打交道
* 集合关注的是数据的存储,与内存打交道
* 2.
* Stream 自己不会存储元素
* Stream 不会改变源对象,相反它们会返回一个持有结果的新Stream
* Stream 操作时延迟执行的,这意味着它们会等到需要结果的时候才执行
*
* 3.Stream 执行流程
* Stream的实例化
* 一系列的中间操作(过滤、映射、……)
* 终止操作
*
* 4.说明
* 一个中间操作链,对数据源的数据进行处理
* 一旦执行终止操作,就执行中间操作链,并产生结果,之后不再使用
*
* @author wty
* @date 2022/11/13 12:24
*/
public class StreamAPITest {
// 测试Stream实例化
/**
* 创建方式一; 通过集合
* default Stream<E> stream() : 返回一个顺序流
* default Stream<E> parallelStream() : 返回一个并行流
*/
@Test
public void streamAPITest() {
List<Employee> employees = EmployeeData.getEmployees();
//default Stream<E> stream() : 返回一个顺序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream() : 返回一个并行流
Stream<Employee> parallelStream = employees.parallelStream();
}
/**
* 创建方式二; 通过数组
*/
@Test
public void streamAPITest02() {
// 调用Arrays 的静态方法 stream() 可以获取数组流:
/**
* static <T> Stream<T> stream(T[] array): 返回一个流
*/
int array[] = new int[]{1,2,3,4,5};
IntStream stream = Arrays.stream(array);
Employee employee1 = new Employee(1012,"Jerry");
Employee employee2 = new Employee(1013,"Timiy");
Employee [] arr = new Employee[]{employee1,employee2};
Stream<Employee> stream1 = Arrays.stream(arr);
}
/**
* 创建方式三; 由值创建流
*/
@Test
public void streamAPITest03() {
/**
* public static<T> Stream<T> of(T... values) : 返回一个流
*/
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
}
/**
* 创建方式四; 创建无限流
*
* 迭代
*
* public static<T> Stream<T> iterate(final T seed, finalUnaryOperator<T> f)
*/
@Test
public void streamAPITest04() {
// 遍历前10个偶数
Stream.iterate(0, new UnaryOperator<Integer>() {
@Override
public Integer apply(Integer t) {
return t + 2;
}
});
// lambda表达式
PrintStream ps = System.out;
// limit(10) 中间操作
// forEach(ps::println) 终止操作
Stream.iterate(0,t -> t + 2).limit(10).forEach(ps::println);
}
/**
*
* 生成
* public static<T> Stream<T> generate(Supplier<T> s) :
*/
@Test
public void streamAPITest05() {
Employee employee = new Employee(1013,"小帽",22,10300.22);
Stream.generate(new Supplier<String>() {
@Override
public String get() {
return employee.getName();
}
});
// lambda表达式
Stream.generate(() -> employee.getName());
Stream.generate(new Supplier<Double>() {
@Override
public Double get() {
return Math.random();
}
});
// lambda表达式
Stream.generate(() -> Math.random());
// 方法引用
PrintStream ps = System.out;
// limit(10) 中间操作
// forEach(ps::println) 终止操作
Stream.generate( Math::random).limit(10).forEach(ps::println);
}
}
中间操作
筛选与切片
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.io.PrintStream;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* 测试Stream的中间操作
*
* @author wty
* @date 2022/11/13 22:33
*/
public class StreamAPITest1 {
private List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
/**
* // 1.筛选与切片
*/
@Test
public void test1(){
/**
* filter(Predicate p) 接收 Lambda,从流中排除某些元素。
*/
// stream.filter(new Predicate<Employee>() {
// @Override
// public boolean test(Employee employee) {
// return employee.getSalary() > 7000;
// }
// });
// 使用lambda表达式
PrintStream ps = System.out;
stream.filter(employee -> employee.getSalary() > 7000).forEach(ps::println);
}
@Test
public void test2(){
/**
* limit(long maxSize) 截断流,使其元素不超过给定数量。
*
* 截取表中前4条数据
*/
stream.limit(4).forEach(System.out::println);
}
@Test
public void test3(){
/**
* skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。
* 若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
*/
stream.skip(3).forEach(System.out::println);
/**
* 返回结果:跳过前3个,输出剩下的
* Employee{id=1004, name='雷军', age=26, salary=7657.37}
* Employee{id=1005, name='李彦宏', age=65, salary=5555.32}
* Employee{id=1006, name='比尔盖茨', age=42, salary=9500.43}
* Employee{id=1007, name='任正非', age=26, salary=4333.32}
* Employee{id=1008, name='扎克伯格', age=35, salary=2500.32}
*/
stream.skip(30).forEach(System.out::println);
/**
* 返回空流,因为数据量不足30
*/
}
@Test
public void test4(){
/**
* distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
*/
employees.add(new Employee(1009, "刘强东", 40, 8000.99));
employees.add(new Employee(1009, "刘强东", 40, 8000.99));
employees.add(new Employee(1009, "刘强东", 40, 8000.99));
for (Employee employee : employees) {
System.out.println(employee);
}
System.out.println("=====distinct=====");
stream.distinct().forEach(System.out::println);
}
}
映射
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.io.PrintStream;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* 映射
*
* @author wty
* @date 2022/11/13 23:00
*/
public class StreamAPITest2 {
/**
* mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元
* 素上,产生一个新的 DoubleStream。
* mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元
* 素上,产生一个新的 IntStream。
* mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元
* 素上,产生一个新的 LongStream。
*
*/
@Test
public void test1(){
/**
* map(Function f) 接收一个函数作为参数,该函数会被应用到每个元
* 素上,并将其映射成一个新的元素。
*/
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
Stream<String> stream = list.stream();
// stream.map(new Function<String, String>() {
// @Override
// public String apply(String s) {
// return s.toUpperCase();
// }
// });
// Lambda表达式
stream.map(s -> s.toUpperCase()).forEach(System.out::println);
}
@Test
public void test2(){
// 获取员工姓名长度大于3的员工的姓名
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
// stream.filter(new Predicate<Employee>() {
// @Override
// public boolean test(Employee employee) {
// return employee.getName().length() >3;
// }
// });
// Lambda表达式
// stream.filter(employee -> employee.getName().length() >3).map(new Function<Employee, String>() {
// @Override
// public String apply(Employee employee) {
// return employee.getName();
// }
// }).forEach(System.out::println);
// Lambda表达式 优化
// 1.先过滤名字长度大于3的对象 2.再从对象中取出名字
stream.filter(employee -> employee.getName().length() >3).map(employee -> employee.getName()).forEach(System.out::println);
System.out.println("===============");
// 2. 先从对象中取出名字 2.再过滤长度大于3的
// 这里stream需要重新创建,因为上面终止语句执行后,就关闭了
stream = employees.stream();
stream.map(employee -> employee.getName()).filter(s -> s.length() > 3).forEach(System.out::println);
}
@Test
public void test3(){
/**
* flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另
* 一个流,然后把所有流连接成一个流
*/
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
Stream<String> stream = list.stream();
stream.map(new Function<String, Stream<Character>>() {
@Override
public Stream<Character> apply(String s) {
return fromStringToStream(s);
}
});
// 使用lambda表达式
stream = list.stream();
stream.map(s -> fromStringToStream(s));
// 使用方法引用
stream = list.stream();
Stream<Stream<Character>> streamStream = stream.map(StreamAPITest2::fromStringToStream);
// 遍历看看streamStream里面有什么
streamStream.forEach(new Consumer<Stream<Character>>() {
@Override
public void accept(Stream<Character> characterStream) {
PrintStream ps = System.out;
characterStream.forEach(ps::println);
}
});
System.out.println("Lambda表达式");
// 写成Lambda表达式
stream = list.stream();
streamStream = stream.map(StreamAPITest2::fromStringToStream);
streamStream.forEach(characterStream -> {{
PrintStream ps = System.out;
characterStream.forEach(ps::println);
}});
//flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另
// 一个流,然后把所有流连接成一个流
System.out.println("flatMap");
stream = list.stream();
Stream<Character> characterStream = stream.flatMap(StreamAPITest2::fromStringToStream);
characterStream.forEach(System.out::println);
}
/**
* 把String中的多个字符构成的集合转换成对应的Stream实例
*
* @param
* @param: str
* @return void
* @date 2022/11/14 10:15
* @author wty
**/
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
/**
* 由addAll和add引出flatMap
*
* @param
* @return void
* @date 2022/11/14 10:12
* @author wty
**/
@Test
public void test4(){
ArrayList list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
ArrayList list3 = new ArrayList();
for (int i = 0; i < list1.size(); i++) {
list3.add(i);
}
Collections.copy(list3,list1);
System.out.println("list3:" +list3);
ArrayList list2 = new ArrayList();
list2.add(4);
list2.add(5);
list2.add(6);
ArrayList list4 = new ArrayList();
for (int i = 0; i < list2.size(); i++) {
list4.add(i);
}
Collections.copy(list4,list2);
list1.add(list2);
for (Object o : list1) {
System.out.println(o);
}
System.out.println("addAll");
list3.addAll(list4);
for (Object o : list3) {
System.out.println(o);
}
}
}
逐段分析
@Test
public void test1(){
/**
* map(Function f) 接收一个函数作为参数,该函数会被应用到每个元
* 素上,并将其映射成一个新的元素。
*/
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
Stream<String> stream = list.stream();
// stream.map(new Function<String, String>() {
// @Override
// public String apply(String s) {
// return s.toUpperCase();
// }
// });
// Lambda表达式
stream.map(s -> s.toUpperCase()).forEach(System.out::println);
}
输出结果
AA
BB
CC
DD
@Test
public void test2(){
// 获取员工姓名长度大于3的员工的姓名
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
// stream.filter(new Predicate<Employee>() {
// @Override
// public boolean test(Employee employee) {
// return employee.getName().length() >3;
// }
// });
// Lambda表达式
// stream.filter(employee -> employee.getName().length() >3).map(new Function<Employee, String>() {
// @Override
// public String apply(Employee employee) {
// return employee.getName();
// }
// }).forEach(System.out::println);
// Lambda表达式 优化
// 1.先过滤名字长度大于3的对象 2.再从对象中取出名字
stream.filter(employee -> employee.getName().length() >3).map(employee -> employee.getName()).forEach(System.out::println);
System.out.println("===============");
// 2. 先从对象中取出名字 2.再过滤长度大于3的
// 这里stream需要重新创建,因为上面终止语句执行后,就关闭了
stream = employees.stream();
stream.map(employee -> employee.getName()).filter(s -> s.length() > 3).forEach(System.out::println);
}
输出结果
比尔盖茨
扎克伯格
===============
比尔盖茨
扎克伯格
@Test
public void test3(){
/**
* flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另
* 一个流,然后把所有流连接成一个流
*/
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
Stream<String> stream = list.stream();
stream.map(new Function<String, Stream<Character>>() {
@Override
public Stream<Character> apply(String s) {
return fromStringToStream(s);
}
});
// 使用lambda表达式
stream = list.stream();
stream.map(s -> fromStringToStream(s));
// 使用方法引用
stream = list.stream();
Stream<Stream<Character>> streamStream = stream.map(StreamAPITest2::fromStringToStream);
// 遍历看看streamStream里面有什么
streamStream.forEach(new Consumer<Stream<Character>>() {
@Override
public void accept(Stream<Character> characterStream) {
PrintStream ps = System.out;
characterStream.forEach(ps::println);
}
});
System.out.println("Lambda表达式");
// 写成Lambda表达式
stream = list.stream();
streamStream = stream.map(StreamAPITest2::fromStringToStream);
// 此时是[aa,bb,cc,dd]要提取每个字符还要遍历循环集合
streamStream.forEach(characterStream -> {{
PrintStream ps = System.out;
characterStream.forEach(ps::println);
}});
//flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另
// 一个流,然后把所有流连接成一个流
System.out.println("flatMap");
stream = list.stream();
Stream<Character> characterStream = stream.flatMap(StreamAPITest2::fromStringToStream);
// 此时是[aa],[bb],[cc],[dd]
characterStream.forEach(System.out::println);
}
输出结果
a
a
b
b
c
c
d
d
Lambda表达式
a
a
b
b
c
c
d
d
flatMap
a
a
b
b
c
c
d
d
map类似于add
flatMap类似于addAll
@Test
public void test4(){
ArrayList list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);
ArrayList list3 = new ArrayList();
for (int i = 0; i < list1.size(); i++) {
list3.add(i);
}
Collections.copy(list3,list1);
System.out.println("list3:" +list3);
ArrayList list2 = new ArrayList();
list2.add(4);
list2.add(5);
list2.add(6);
ArrayList list4 = new ArrayList();
for (int i = 0; i < list2.size(); i++) {
list4.add(i);
}
Collections.copy(list4,list2);
list1.add(list2);
for (Object o : list1) {
System.out.println(o);
}
System.out.println("addAll");
list3.addAll(list4);
for (Object o : list3) {
System.out.println(o);
}
}
输出结果
list3:[1, 2, 3]
1
2
3
[4, 5, 6]
addAll
1
2
3
4
5
6
上面的例子举的不是太好,我们再看一个例子。
需求:对于给定的单词列表(数组)[“Hello”,“World”],你想返回列表[“H”,“e”,“l”,“o”,“W”,“r”,“d”]
先用map操作看是否成功:
@Test
public void test(){
List<String> stringList = Arrays.asList("hello", "world");
List<String[]> collect = stringList.stream()
.map(str -> str.split(""))
.distinct().collect(Collectors.toList());
collect.forEach(col-> System.out.println(Arrays.toString(col)));
}
输出结果
[h,e,l,l,o]
[w,o,r,l,d]
大家可以看到返回结果是两个数组,并没有达到我们的要求。map的操作只是将元素放入map中的函数中使其返回另一个Stream<String[]>类型的,但我们真正想要的是一个Stream[String]类型的,所以我们需要扁平化处理,将多个数组放入一个数组中。
看下flatMap的操作:
再来看看flatMap
@Test
public void test(){
List<String> stringList = Arrays.asList("hello", "world");
List<String> collect = stringList.stream()
.map(str -> str.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
System.out.println(collect);
}
输出结果
[h, e, l, o, w, r, d]
flatmap用法:使用flatMap的效果是,各个数组并不是分别映射一个流,而是映射成流的内容,所有使用flatMap(Arrays::stream)时生成的单个流被合并起来,扁平化成了一个流。
排序
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
/**
* 排序
*
* @author wty
* @date 2022/11/14 10:48
*/
public class StreamAPITest3 {
@Test
public void test1(){
/**
* sorted() 产生一个新流,其中按自然顺序排序
* sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序
*/
List<Integer> list = Arrays.asList(0,-98,-3, 3, 12, 29, 33,1);
Stream<Integer> stream = list.stream();
Stream<Integer> sorted = stream.sorted();
sorted.forEach(System.out::println);
System.out.println("====EmployeeData====");
// List<Employee> employees = EmployeeData.getEmployees();
// employees.stream().sorted().forEach(System.out::println);
/**
* 返回结果:抛出异常,因为Employee没有实现Comparable接口
*
* java.lang.ClassCastException: com.methodreference.Employee
* cannot be cast to java.lang.Comparable
*/
// 引出定制排序
}
@Test
public void test2(){
// 工资由小到大排序
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())).forEach(System.out::println);
}
@Test
public void test3(){
// 年龄相同的时候,工资由小到大排序
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2) -> {
int compare = Integer.compare(e1.getAge(), e2.getAge());
if (compare != 0){
return compare;
}else {
return Double.compare(e1.getSalary(),e2.getSalary());
}
}).forEach(System.out::println);
}
}
终止操作(终端操作)
查找与匹配
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* 终止操作
*
* 匹配与查找
*
* @author wty
* @date 2022/11/14 11:08
*/
public class StreamAPI4 {
@Test
public void test1(){
/**
* allMatch(Predicate p) 检查是否匹配所有元素
* anyMatch(Predicate p) 检查是否至少匹配一个元素
* noneMatch(Predicate p) 检查是否没有匹配所有元素
* findFirst() 返回第一个元素
* findAny() 返回当前流中的任意元素
*/
// 是否所有的员工的年龄都大于18岁
// allMatch(Predicate p) 检查是否匹配所有元素 所有都是true才返回true
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().allMatch(new Predicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getAge() > 18;
}
});
// 使用Lambda表达式
System.out.println("是否所有的员工的年龄都大于18岁");
boolean b = employees.stream().allMatch(employee -> employee.getAge() > 18);
System.out.println(b);
//anyMatch(Predicate p) 检查是否至少匹配一个元素
// 是否存在一个员工的工资大于9000
System.out.println("是否存在一个员工的工资大于9000");
boolean b1 = employees.stream().anyMatch(employee -> employee.getSalary() > 9000);
System.out.println(b1);
// 是否存在员工姓"雷"
//noneMatch(Predicate p) 检查是否没有匹配所有元素
System.out.println("员工是否都姓雷");
boolean b3 = employees.stream().noneMatch(employee -> employee.getName().startsWith("雷"));
System.out.println(b3);
//findFirst() 返回id最大的第一个元素
System.out.println("=====findFirst() 返回id最大的第一个元素=====");
Optional<Employee> first = employees.stream().sorted((e1,e2) -> -Integer.compare(e1.getId(),e2.getId())).findFirst();
System.out.println(first);
// findAny() 返回当前流中的任意元素
System.out.println("=====findAny() 返回任意一个元素=====");
// 这里用并行流而不是串行流
for (int i = 1; i <= 1000 ; i++) {
Optional<Employee> any = employees.parallelStream().findAny();
System.out.println(any);
}
}
/**
* 匹配与查找
*/
@Test
public void test2(){
/**
* count() 返回流中元素总数
* max(Comparator c) 返回流中最大值
* min(Comparator c) 返回流中最小值
* forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭
* 代,称为外部迭代。相反,Stream API 使用内部
* 迭代——它帮你把迭代做了)
*/
List<Employee> employees = EmployeeData.getEmployees();
// count() 返回流中元素总数
long count = employees.stream().count();
System.out.println(count);
// max(Comparator c) 返回流中最大值 返回最高工资
System.out.println("=====返回最高工资 方法一=====");
Optional<Employee> max = employees.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max);
System.out.println("=====返回最高工资 方法二=====");
// 先把对象转换成工资取出来
Stream<Double> doubleStream = employees.stream().map(employee -> employee.getSalary());
Optional<Double> max1 = doubleStream.max((sal1, sal2) -> Double.compare(sal1, sal2));
System.out.println(max1);
System.out.println("=====返回最高工资 方法三=====");
// 先把对象转换成工资取出来
Stream<Double> doubleStream1 = employees.stream().map(employee -> employee.getSalary());
Optional<Double> max2 = doubleStream1.max(Double::compare);
System.out.println(max2);
//min(Comparator c) 返回流中最小值 返回最低工资
System.out.println("=====返回最低工资的员工名 方法一=====");
Optional<Employee> min = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min);
System.out.println("=====返回最低工资 方法一=====");
Optional<Double> min1 = employees.stream().map(employee -> employee.getSalary()).min((d1, d2) -> Double.compare(d1, d2));
System.out.println(min1);
System.out.println("=====返回最低工资 方法二=====");
Optional<Double> min2 = employees.stream().map(employee -> employee.getSalary()).min(Double::compare);
System.out.println(min2);
// forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭
System.out.println("=====forEach(Consumer c) 内部迭代=====");
employees.stream().forEach(System.out::println);
// 使用集合的遍历操作
System.out.println("=====集合的遍历操作=====");
employees.forEach(System.out::println);
}
}
归约
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;
/**
* 规约
*
* @author wty
* @date 2022/11/14 11:56
*/
public class StreamAPITest5 {
@Test
public void test1(){
/**
* reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
* 返回 T
* reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
* 返回 Optional<T>
* 备注:map 和 reduce 的连接通常称为map-reduce 模式,因 Google 用它
* 来进行网络搜索而出名。
*/
// reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
// 返回 T
// 计算自然数1-10的合
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream().reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer t1, Integer t2) {
return t1+t2;
}
});
// 使用Lambda表达式 方式一
Optional<Integer> reduce = list.stream().reduce((t1, t2) -> t1 + t2);
System.out.println(reduce);
// 使用Interger.sum 方式二
list.stream().reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer t1, Integer t2) {
return Integer.sum(t1,t2);
}
});
// 使用Interger.sum 方式二 使用Lambda表达式
System.out.println("=====使用Interger.sum 方式二 使用Lambda表达式=====");
Optional<Integer> reduce1 = list.stream().reduce((t1, t2) -> Integer.sum(t1, t2));
System.out.println(reduce1);
// 使用Interger.sum 方式二 使用方法引用
System.out.println("=====使用Interger.sum 方式二 使用方法引用=====");
Optional<Integer> reduce2 = list.stream().reduce(Integer::sum);
System.out.println(reduce2);
//使用reduce(T var1, BinaryOperator<T> var2);
System.out.println("使用reduce(T var1, BinaryOperator<T> var2)");
Integer reduce3 = list.stream().reduce(0, (t1, t2) -> Integer.sum(t1, t2));
System.out.println(reduce3);
//使用reduce(T var1, BinaryOperator<T> var2);方法引用
System.out.println("使用reduce(T var1, BinaryOperator<T> var2)方法引用");
Integer reduce4 = list.stream().reduce(0, Integer::sum);
System.out.println(reduce4);
}
@Test
public void test2(){
/**reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
* 返回 Optional<T>
*/
// 计算公司所有员工工资的总和 方法一
List<Employee> employees = EmployeeData.getEmployees();
Stream<Double> doubleStream = employees.stream().map(employee -> employee.getSalary());
Double reduce = doubleStream.reduce(0.00, (sal, sal2) -> Double.sum(sal, sal2));
System.out.println(reduce);
// 计算公司所有员工工资的总和 方法二
System.out.println("=====计算公司所有员工工资的总和 方法二=====");
doubleStream = employees.stream().map(Employee::getSalary);
Double reduce2 = doubleStream.reduce(0.00, Double::sum);
System.out.println(reduce2);
}
}
收集
package com.Stream;
import com.methodreference.Employee;
import com.methodreference.EmployeeData;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
* 收集
*
* @author wty
* @date 2022/11/14 15:28
*/
public class StreamAPITest6 {
@Test
public void test1(){
/**
* collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的
* 实现,用于给Stream中元素做汇总的方法
*/
// 查找工资大于6000的员工,返回一个list或者set
List<Employee> employees = EmployeeData.getEmployees();
// 先筛选后组装成List
List<Employee> collect = employees.stream().filter(employee -> employee.getSalary() > 6000).collect(Collectors.toList());
for (Employee employee : collect) {
System.out.println(employee);
}
System.out.println("=======组装成Set=====");
// 先筛选后组装成Set
Set<Employee> collect1 = employees.stream().filter(employee -> employee.getSalary() > 6000).collect(Collectors.toSet());
for (Employee employee : collect1) {
System.out.println(employee);
}
System.out.println("=======toCollection=====");
Collector<Employee, ?, ArrayList<Employee>> collector = Collectors.toCollection(ArrayList::new);
employees.stream().filter(employee -> employee.getSalary() > 6000).collect(collector).forEach(System.out::println);
}
}
举例:
按照姓名和分数合集输出。
package com.Stream;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author wty
* @date 2023/2/6 20:48
*/
public class StreamAPITest7 {
@Test
public void test(){
List<Student> list = Arrays.asList(
new Student("张三", "语文", 78),
new Student("张三", "数学", 70),
new Student("张三", "英语", 65),
new Student("李四", "语文", 70),
new Student("李四", "数学", 45),
new Student("李四", "英语", 35),
new Student("王五", "语文", 60),
new Student("王五", "数学", 70),
new Student("王五", "英语", 10)
);
list.forEach(System.out::println);
Map<String, IntSummaryStatistics> collectMap = list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.summarizingInt(Student::getScore)));
// 姓名,分数总和
HashMap<String, Integer> map = new HashMap<>();
Set<String> keySet = collectMap.keySet();
for (String s : keySet) {
map.put(s,(int)collectMap.get(s).getSum());
}
System.out.println("===合集===");
System.out.println(map);
}
}
输出结果
{李四=150, 张三=213, 王五=140}
Optional类
package com.optional;
import org.junit.Test;
import java.util.Optional;
/**
* Optional类:为了在程序中避免出现空指针异常而创建的
*
* 常用的方法;
*s
* * Optional.of(T t) : 创建一个 Optional 实例
* * Optional.empty() : 创建一个空的 Optional 实例
* * Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
* * isPresent() : 判断是否包含值
* * orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
* * orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
* * map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
* * flatMap(Function mapper):与 map 类似,要求返回值必须是Optiona
* @author wty
* @date 2022/11/14 15:44
*/
public class OPtionalEx {
@Test
public void test1(){
/**
* Optional.of(T t) : 创建一个 Optional 实例 必须保证t是非空的
*/
Girl girl = new Girl();
Optional<Girl> girl1 = Optional.of(girl);
}
@Test
public void test2(){
/**
* Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
*/
Girl girl = new Girl();
girl = null;
Optional<Girl> girl1 = Optional.ofNullable(girl);
System.out.println(girl1);
//对象.orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
Girl girl2 = girl1.orElse(new Girl("赵丽颖"));
System.out.println(girl2);
}
/**
* 空指针异常示例
*/
@Test
public void test3(){
Boy boy = new Boy();
String girlName = getGirlName(boy);
System.out.println(girlName);
/**
* 结果
* java.lang.NullPointerException
*/
}
public String getGirlName(Boy boy){
return boy.getGirl().getName();
}
/**
* 优化后,去掉空指针异常
*/
@Test
public void test4(){
Boy boy = new Boy();
String girlName = getGirlNameUpdate(boy);
System.out.println(girlName);
}
public String getGirlNameUpdate(Boy boy){
if (boy != null){
Girl girl = boy.getGirl();
if (null != girl){
return girl.getName();
}
}
return null;
}
/**
* 使用Optional杜绝空指针异常
*/
@Test
public void test5(){
Boy boy = null;
String girlNameUpdateOptional = getGirlNameUpdateOptional(boy);
System.out.println(girlNameUpdateOptional);
System.out.println("==========");
boy = new Boy();
girlNameUpdateOptional = getGirlNameUpdateOptional(boy);
System.out.println(girlNameUpdateOptional);
System.out.println("==========");
Boy boy1 = new Boy(new Girl("钟楚曦"));
girlNameUpdateOptional = getGirlNameUpdateOptional(boy1);
System.out.println(girlNameUpdateOptional);
}
public String getGirlNameUpdateOptional(Boy boy){
Optional<Boy> boyOptional = Optional.ofNullable(boy);
// 此时boy1一定非空
Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
Girl girl = boy1.getGirl();
Optional<Girl> girl1 = Optional.ofNullable(girl);
// 此时girl2一定非空
Girl girl2 = girl1.orElse(new Girl("古力娜扎"));
return girl2.getName();
}
@Test
public void test6(){
// Optional.empty() : 创建一个空的 Optional 实例
Optional<Object> empty = Optional.empty();
// isPresent() : 判断是否包含值对象,不包含对象返回 false,包含对象返回true
if (empty.isPresent()) {
System.out.println("包含对象");
}else {
System.out.println("不包含对象");
}
//System.out.println(empty.get());
System.out.println(empty);
/**
* 输出结果;
*不包含对象
* Optional.empty
*/
}
@Test
public void test7(){
String str = "hello";
str = null;
Optional<String> str1 = Optional.of(str);
// str1 是null 调用get会报异常
// get()方法通常与of()方法搭配使用
String s = str1.get();
System.out.println(s);
/**
* 抛出异常
* java.lang.NullPointerException
*/
}
}
JDK8中的日期时间
新日期时间API的出现背景
新日期时间API
LocalDate、LocalTime、LocalDateTime
package com.date;
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* @author wty
* @date 2022/11/14 23:03
*/
public class JDK8DateTimeTest {
/**
* LocalDate、LocalTime、LocalDateTime
*/
@Test
public void test1(){
// LocalDateTime 使用的频率较高
// now()获取当前时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);
/**
* 输出结果
* 2022-11-14
* 23:07:17.720
* 2022-11-14T23:07:17.720
*/
// of() 设置指定的年月日时分秒 没有偏移量
LocalDateTime localDateTime1 = LocalDateTime.of(2022, 11, 14, 23, 9, 33);
System.out.println(localDateTime1);
// getXXX()获取
System.out.println("========getXXX()=======");
// 获取当月的第几天
System.out.println("获取当月的第几天\t"+localDateTime.getDayOfMonth());
// 获取本周的第几天
System.out.println("获取本周的第几天\t"+localDateTime.getDayOfWeek());
// 获取月
System.out.println("获取月\t"+localDateTime.getMonth());
// 获取月份的阿拉伯数字
System.out.println("获取月份的阿拉伯数字\t"+localDateTime.getMonthValue());
// 获取分钟
System.out.println("获取分钟\t"+localDateTime.getMinute());
// withXXX()设置时间
// 设置时间 把日期更改成22日 体现了不可变性
LocalDate localDate2 = localDate.withDayOfMonth(22);
System.out.println("localDate:" +localDate+"\tlocalDate2:"+localDate2);
// 设置时间 把小时更改为0
LocalTime localTime1 = localTime.withHour(0);
System.out.println("localTime:" +localTime+"\tlocalTime1:"+localTime1);
//plus()时间的加 加三个月
LocalDateTime localDateTime2 = localDateTime.plusMonths(3);
System.out.println("localDateTime:" +localDateTime+"\tlocalDateTime1:"+localDateTime2);
// minus 减6天
LocalDateTime localDateTime3 = localDateTime.minusDays(6);
System.out.println("localDateTime:" +localDateTime+"\tlocalDateTime3:"+localDateTime3);
//
}
}
Instant
Instant API
package com.date;
import org.junit.Test;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
/**
* Instant 时间点,瞬时点
* 类似于java.util.Date类
*
* @author wty
* @date 2022/11/14 23:26
*/
public class InstanceExercise {
@Test
public void test(){
// now() 本初子午线对应的标准时间
Instant instant = Instant.now();
System.out.println(instant);
/**结果;
* 2022-11-14T15:41:50.412Z
* 早了8小时,是格林威治时间
*/
// 根据对应的时区添加时间偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
// 获取瞬时点,距离1970年1月1日0时0分0秒对应毫秒数
long l = instant.toEpochMilli();
System.out.println("毫秒数"+l);
// 通过给定毫秒数,获取对应时间 -->Date 类的getTime()
Instant instant1 = Instant.ofEpochMilli(l);
System.out.println("毫秒数对应的时间是:"+instant1);
}
}
格式化与解析日期或时间
package com.date;
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
/**
* DateTimeFormatter 格式化日期和时间
*
* 类似于SimpleDateFormat
*
* @author wty
* @date 2022/11/14 23:51
*/
public class Format {
@Test
public void test(){
// 方式一:
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
// 格式化 日期 -> 字符串
LocalDateTime now = LocalDateTime.now();
String format = formatter.format(now);
System.out.println("LocalDateTime:"+now+"\nDateTimeFormatter.ISO_LOCAL_DATE_TIME:" + format);
// 解析 字符串 -> 日期
TemporalAccessor parse = formatter.parse("2022-11-14T23:56:31.433");
System.out.println("parse"+parse);
// 方式二: ofLocalizedDateTime() 本地化相关格式
// FormatStyle.LONG
// FormatStyle.MEDIUM
// FormatStyle.SHORT
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
String format1 = formatter1.format(now);
System.out.println("format1\t" + format1);
/**
* 输出结果:
* 2022年11月15日 上午12时02分04秒
*/
// 解析
TemporalAccessor parse1 = formatter1.parse("2022年11月15日 上午12时03分59秒");
System.out.println("parse1" + parse1);
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
String format2 = formatter2.format(now);
System.out.println("format2 "+format2);
/**输出结果:
* 2022-11-15 0:03:20
*/
DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
String format3 = formatter3.format(now);
System.out.println("format3 "+format3);
/**
*22-11-15 上午12:03
*/
// FormatStyle.FULL
// FormatStyle.FULL
// FormatStyle.FULL
// FormatStyle.FULL
LocalDate localDate = LocalDate.now();
DateTimeFormatter formatter4 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String format4 = formatter4.format(localDate);
System.out.println("format4 "+format4);
/**
* 2022年11月15日 星期二
*/
DateTimeFormatter formatter5 = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
String format5 = formatter5.format(localDate);
System.out.println("format5 " + format5);
/**
* 2022年11月15日
*/
DateTimeFormatter formatter6 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
String format6 = formatter6.format(localDate);
System.out.println("format6 " + format6);
/**
* 2022-11-15
*/
DateTimeFormatter formatter7 = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
String format7 = formatter7.format(localDate);
System.out.println("format7:" + format7);
/**
* 22-11-15
*/
// 方式三:自定义格式
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter8 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format8 = formatter8.format(localDateTime);
System.out.println("format8 " + format8);
/**
* 2022-11-15 12:12:22
*/
// 解析
TemporalAccessor parse2 = formatter8.parse("2022-11-15 00:12:49");
System.out.println("parse2 "+parse2);
}
}