Java8新特性主要内容
1.Lambda 表达式
2.函数式接口
3.方法引用与构造器引用
4.Stream API
5.接口中的默认方法与静态方法
6.新时间日期API
7.其他新特性
Java8新特性简介
1.速度更快(HashMap和方法区的改变,详细内容在其他博客中)
2.代码更少(增加了新的语法Lambda表达式)
3.强大的StreamAPI(像sql语句操作数据一样操作数据)
4.便于并行
5.最大化减少空指针异常Optional
Lambda表达式
为什么使用Lambda表达式?
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。
可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
Lambda的推导过程
package LambdaExpre;
//TestLambda类要使用到的Employee类
public class Employee {
private String name;
private int age;
private double salary;
public Employee() {
}
public Employee(String name) {
this.name = name;
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
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;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
package LambdaExpre;
//TestLambda类要使用到的自定义接口MyPredicate
public interface MyPredicate<T> {
public boolean test(T t);
}
package LambdaExpre;
//TestLambda类要使用到的实现MyPredicate接口的类
public class FilterEmployeeByAge implements MyPredicate<Employee> {
@Override
public boolean test(Employee employee) {
return employee.getAge()>25;
}
}
package LambdaExpre;
//TestLambda类要使用到的实现MyPredicate接口的类
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
@Override
public boolean test(Employee employee) {
return employee.getSalary()>7000;
}
}
package LambdaExpre;
import java.util.*;
public class TestLambda {
//原来的匿名内部类
public static void test1(){
Comparator<String> com = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
TreeSet<String> treeSet = new TreeSet<>(com);
}
//Lambda表达式
public static void test2(){
Comparator<String> com = (x,y) -> x.compareTo(y);
TreeSet<String> treeSet = new TreeSet<>(com);
}
static List<Employee> employees = Arrays.asList(
new Employee("张三",18,10000),
new Employee("李四",24,15000),
new Employee("王五",14,8000),
new Employee("赵六",30,5000),
new Employee("田七",29,7000)
);
//原方法,此方法代码冗余,对其进行优化
public static void test3(){
List<Employee> employeeList = filterEmployees1(employees);
System.out.println(employeeList);
employeeList = filterEmployees2(employees);
System.out.println(employeeList);
}
//需求:获取当前公司员工年龄大于25的员工信息
public static List<Employee> filterEmployees1(List<Employee> employees){
List<Employee> employeeList = new ArrayList<>();
for (Employee employee : employees) {
if(employee.getAge()>25){
employeeList.add(employee);
}
}
return employeeList;
}
//需求:获取当前公司员工工资大于7000的员工信息
public static List<Employee> filterEmployees2(List<Employee> employees){
List<Employee> employeeList = new ArrayList<>();
for (Employee employee : employees) {
if(employee.getSalary()>7000){
employeeList.add(employee);
}
}
return employeeList;
}
//优化方式一:策略设计模式
public static void test4(){
List<Employee> employeeList = filterEmployees(employees,new FilterEmployeeByAge());
System.out.println(employeeList);
employeeList = filterEmployees(employees,new FilterEmployeeBySalary());
System.out.println(employeeList);
}
public static List<Employee> filterEmployees(List<Employee> employees,MyPredicate<Employee> predicate){
List<Employee> employeeList = new ArrayList<>();
for (Employee employee : employees) {
if(predicate.test(employee)){
employeeList.add(employee);
}
}
return employeeList;
}
//优化方式二:匿名内部类
public static void test5(){
List<Employee> employeeList = new ArrayList<>();
employeeList = filterEmployees(employees, new MyPredicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getAge()>25;
}
});
System.out.println(employeeList);
employeeList = filterEmployees(employees, new MyPredicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary()>7000;
}
});
System.out.println(employeeList);
}
//优化方式三:Lambda表达式
public static void test6(){
List<Employee> employeeList = new ArrayList<>();
employeeList = filterEmployees(employees,(x) -> x.getAge()>25);
System.out.println(employeeList);
employeeList = filterEmployees(employees,(x) -> x.getSalary()>7000);
System.out.println(employeeList);
}
//优化方式四:Stream API
public static void test7(){
employees.stream()
.filter((e) -> e.getAge()>25)
.forEach(System.out::println);
System.out.println("=====================================");
employees.stream()
.filter((e) -> e.getSalary()>7000)
.limit(2)
.forEach(System.out::println);
System.out.println("=====================================");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
public static void main(String[] args) {
test1();
test2();
test3();
test4();
test5();
test6();
test7();
}
}
Lambda表达式的格式
一、Lambda表达式的基础语法:
Java8中引入了一个新的操作符"->"该操作符称为箭头操作符或Lambda操作符。
箭头操作符将Lambda表达式拆分成两部分
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,即Lambda体
语法格式一:无参数,无返回值
() -> System.out.println(“Lambda”);
语法格式二:有一个参数,无返回值
(x) -> System.out.println(x);
语法格式三:若只有一个参数,小括号可以省略不写
y -> System.out.println(y);
语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句
Comparator com = (x,y) -> {
System.out.println(“Lambda语法格式四”);
return Integer.compare(x,y);
};
语法格式五:若Lambda体中只有一条语句,return和大括号都可以省略不写
(x,y) -> Integer.compare(x,y);
语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即"类型推断"
(Integer x,Integer y) -> Integer.compare(x,y);
上联:左右遇一括号省
下联:左侧推断类型省
横批:能省则省
二、Lambda表达式需要"函数式接口"的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰,此注释可以检查是否是函数式接口
package LambdaExpre;
//TestLambda2 类用到的接口
@FunctionalInterface
public interface MyFun {
public Integer getValue(Integer num);
}
package LambdaExpre;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
public class TestLambda2 {
@Test
public void test1() {
/*
* 局部内部类访问局部变量必须用final修饰
* 局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。
* 为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。
* JDK1.8之后,final会默认加上,你不用手动去加。
*/
int num = 0;
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类" + num);
}
};
r.run();
System.out.println("==========================");
r = () -> System.out.println("Lambda语法格式一");
r.run();
}
@Test
public void test2() {
Consumer<String> con = (x) -> System.out.println(x);
con.accept("Lambda语法格式二");
con = y -> System.out.println(y);
con.accept("Lambda语法格式三");
}
@Test
public void test3() {
Comparator<Integer> com = (x, y) -> {
System.out.println("Lambda语法格式四");
return Integer.compare(x, y);
};
}
@Test
public void test4() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}
@Test
public void test5() {
Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x,y);
// String[] str = {"aaa","bbb","ccc"};一块写时可以通过上下文进行类型推断,下面分开写的方式无法通过上下文进行类型推断
// String[] str;
// str = {"aaa","bbb","ccc"};
// 等号右边的泛型之所以能省略参数是因为进行了类型推断
// List<String> list = new ArrayList<>();
}
//需求:对一个数进行运算
@Test
public void test6(){
Integer num = Opration(5,x -> x*x);
System.out.println(num);
System.out.println(Opration(50,x -> x+500));
}
public Integer Opration(Integer num ,MyFun myFun){
return myFun.getValue(num);
}
}
Lambda表达式的练习
package LambdaExpre;
//TestLambda3用到的接口
@FunctionalInterface
public interface MyFunction {
public String getValue(String str);
}
package LambdaExpre;
//TestLambda3用到的接口
@FunctionalInterface
public interface MyFunction2<T,R> {
public R getValue(T t,T t1);
}
package LambdaExpre;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/*
* 1.调用Collections.sort()方法,通过定制排序比较两个Employee(先按年龄比,年龄相同按姓名比),
* 使用Lambda作为参数传递。
* 2.(1)声明函数式接口,接口中声明抽象方法,public String getValue(String str);
* (2)声明类TestLambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值。
* (3)再将一个字符串的第2个和第4个索引位置进行截取子串。
* 3.(1)声明一个带两个泛型的函数式接口,泛型类型为<T,R> T为参数,R为返回值
* (2)接口中声明对应抽象方法
* (3)在TestLambda类中声明方法,使用接口作为参数,计算两个long型参数的和。
* (4)再计算两个long型参数的乘积
*/
public class TestLambda3 {
List<Employee> employees = Arrays.asList(
new Employee("张三",18,10000),
new Employee("李四",24,15000),
new Employee("王五",14,8000),
new Employee("赵六",30,5000),
new Employee("田七",29,7000)
);
//练习一
@Test
public void test(){
Collections.sort(employees,(x,y) -> {
int num = Integer.compare(x.getAge(),y.getAge());
if(num==0){
return x.getName().compareTo(y.getName());
}
return num;
});
for (Employee employee : employees) {
System.out.println(employee);
}
}
//练习二
@Test
public void test1(){
String str = "i love the new features of jdk8 ";
String newStr = strHandler(str,x -> x.toUpperCase());
System.out.println(newStr);
String newStr1 = strHandler(str,x -> x.substring(2,5));
System.out.println(newStr1);
}
public String strHandler(String str,MyFunction myFunction){
return myFunction.getValue(str);
}
//练习三
@Test
public void test2(){
long num = operater(100L,500L,(x,y) -> x+y);
System.out.println(num);
num = operater(100L,500L,(x,y) -> x*y);
System.out.println(num);
}
public long operater(long x,long y,MyFunction2<Long,Long> myFunction2){
return myFunction2.getValue(x,y);
}
}
内置函数式接口
一、Java内置四大核心函数式接口
二、其他接口
package LambdaExpre;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/*
*Java8内置四大核心函数式接口
*
* Consumer<T>:消费型接口
* void accept(T t);
* Supplier<T>:供给型接口
* T get();
* Function<T,R>:函数型接口
* R apply(T t);
* Predicate<T>:断言型接口
* boolean test(T t);
*/
public class TestLambda4 {
//Consumer<T>
@Test
public void test(){
happy(1500000,(x) -> System.out.println("消费了1500000"));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
//Supplier<T>
@Test
public void test1(){
List<Integer> list = getNumList(15,() -> (int)(Math.random()*100));
System.out.println(list);
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(Integer num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for(int i=0;i<num;i++){
list.add(sup.get());
}
return list;
}
//Function<T,R>
//需求:用于处理字符串
@Test
public void test2(){
String str = "I love lobster,especially Boston lobster";
String newStr = strHandler(str,(x) -> x.toUpperCase());
System.out.println(newStr);
newStr = strHandler(str,(x) -> str.substring(0,8));
System.out.println(newStr);
}
public String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
//Predicate<T>
//需求:将满足条件的字符串放入集合中
@Test
public void test3(){
List<String> str = Arrays.asList("sije","egtgrhr","worjjbgri","fe","e");
List<String> list = filterStr(str,(x) -> x.length()>4);
System.out.println(list);
}
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> newList = new ArrayList<>();
for (String s : list) {
if(pre.test(s)){
newList.add(s);
}
}
return newList;
}
}
方法引用与构造器引用
一、方法引用
若Lambda体中的内容有方法已经实现了,我们可以使用"方法引用"
(可以理解为方法引用是Lambda表达式的另外一种表达形式)
主要有三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
注意:
(1)Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型保持一致
(2)若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
二、构造器引用
格式
ClassName::new
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
三、数组引用
Type::new
package LambdaExpre;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.*;
public class TestLambda5 {
//对象::实例方法名
@Test
public void test(){
Consumer<String> con = (x) -> System.out.println(x);
con.accept("我爱吃龙虾");
con = System.out::println;
con.accept("我爱吃海鲜");
PrintStream out = System.out;
con = out::println;
con.accept("我爱吃螃蟹");
}
@Test
public void test1(){
Employee employee = new Employee();
Supplier<String> sup = () -> employee.getName();
String str = sup.get();
System.out.println(str);
sup = employee::getName;
String s = sup.get();
System.out.println(s);
Supplier<Integer> sup1 = employee::getAge;
System.out.println(sup1.get());
}
//类::静态方法名
@Test
public void test2(){
Comparator<Integer> com = Integer::compare;
System.out.println(com.compare(8,9));
}
//类::实例方法名
@Test
public void test3(){
BiPredicate<Integer,Integer> bip = (x,y) -> x.equals(y);
System.out.println(bip.test(8,8));
BiPredicate<Integer,Integer> bip1 = Integer::equals;
System.out.println(bip1.test(9,7));
}
//构造器引用
@Test
public void test4(){
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
sup = Employee::new;
System.out.println(sup.get());
}
@Test
public void test5(){
Function<String,Employee> fun = (x) -> new Employee(x);
System.out.println(fun.apply("wenyu"));
fun = Employee::new;
System.out.println(fun.apply("yuer"));
BiFunction<String,Integer,Employee> bif = Employee::new;
System.out.println(bif.apply("pingfan",18));
}
//数组引用
@Test
public void test6(){
Function<Integer,Integer[]> fun1 = (x) -> new Integer[x];
System.out.println(fun1.apply(8).length);
Function<Integer,String[]> fun = String[]::new;
System.out.println(fun.apply(10).length);
}
}