Java8-新特性

Posted 钢铁-程序猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8-新特性相关的知识,希望对你有一定的参考价值。

Java8新特性

  • 1、Lambda表达式
  • 2、函数式接口
  • 3、方法引用与构造器引用
  • 4、Stream API
  • 5、接口中的默认方法与静态方法
  • 6、新时间日期API
  • 7、其它新特性

一、Lambda表达式

Lambda表达式可以理解为作为实现类对象传入函数

Lambda表达式是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样进行传递),可以写出更加简洁、更加灵活的代码。作为一种更紧凑的代码风格,使Java语言表达能力得到了提升。

匿名内部类

abstract class Person {
    public abstract void eat();
}
//匿名内部类
public class Demo {
    public static void main(String[] args) {
    	//实现类并没具体名称
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

Lambda表达式

import org.junit.Test;

import java.util.Comparator;
import java.util.TreeSet;

public class Lambda {
    //原来的匿名内部类
    @Test
    public void test1()
    {
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        TreeSet<Integer> ts = new TreeSet<>(com);
    }

    //Lambda表达式
    //使用Lambda使用的代码量少了
    @Test
    public void test2()
    {
        Comparator<Integer> com = (x,y)->Integer.compare(x,y);
        TreeSet<Integer> ts = new TreeSet<>(com);
    }

} 

例子

import org.junit.Test;

import java.util.*;

public class Lambda {
    List<Employee> employees = Arrays.asList(
        new Employee("张三",18,9999.99),
        new Employee("李四",38,5555.55),
        new Employee("王五",50,6666.66),
        new Employee("赵六",16,3333.33),
        new Employee("田七",8,7777.77)
    );

    //需求:获取当前公司中员工年龄大于35的员工信息
    public List<Employee> filterEmployees(List<Employee> list)
    {
        List<Employee> emps = new ArrayList<>();
        for (Employee emp:list)
        {
            if(emp.getAge()>=35)
            {
                emps.add(emp);
            }
        }
        return emps;
    }

    //需求:获取当前公司员工工资大于5000的员工信息
    public List<Employee> filterEmployees2(List<Employee> list)
    {
        List<Employee> emps = new ArrayList<>();
        for (Employee emp:list)
        {
            //唯一和上面一个函数不同的一行,需求变动可能对代码的影响很小,但是要重新写一个函数
            //比较复杂
            if(emp.getSalary()>=5000)
            {
                emps.add(emp);
            }
        }
        return emps;
    }
}

优化一:使用策略设计模式

import org.junit.Test;

import java.util.*;

public class Lambda {
    //优化方式一:

    public interface MyPredicate<Employee> {
        public boolean test(Employee employee);
    }

    class FilterEmployeeByAge implements MyPredicate<Employee>
    {

        @Override
        public boolean test(Employee employee) {
            return employee.getAge()>=35;
        }
    }

    //将Java类按照MyPredicate的方式进行过滤
    //方法只要写这一个,传入不同的类,即可按照不同的实现方式进行过滤
    public List<Employee> filterEmployee(List<Employee> list,MyPredicate<Employee> mp)
    {
        List<Employee> emps = new ArrayList<>();
        for (Employee employee:list)
        {
            if (mp.test(employee))
            {
                emps.add(employee);
            }
        }
        return emps;
    }

}

优化方式二:匿名内部类

import org.junit.Test;

import java.util.*;

public class Lambda {
    //优化方式二:匿名内部类
    @Test
    public void test5()
    {
        List<Employee> list = filterEmployee(employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary()<=5000;
            }
        });

        for (Employee employee:list)
        {
            System.out.println(employee);
        }
    }

}

优化方式三:Lambda表达式

public class Lambda {
    //优化方式三:Lambda表达式
    @Test
    public void test6()
    {
    	List<Employee> list = filterEmployee(employees,(e)->e.getSalary()<=5000);
    }
}

优化方式四:Stream API

public class Lambda {
    //优化方式四:
    @Test
    public void test7()
    {
    	//限制输出前两个
    	employees.stream()
    		     .filter((e)->e.getSalary()>=5000)
    		     .limit(2)
    		     .forEach(System.out::println);
    	//将所有人的名字提取出
    	employees.stream()
    		     .map(Employee::getName)
    		     .forEach(System.out::println);
    }
}

Lambda表达式的基本语法

Java8引入了一个新的操作符“->”,该操作符称为箭头操作符或Lambda操作符
箭头操作符将Lambda表达式拆分成两个部分:

  • 1、左侧:Lambda表达式的参数列表
  • 2、右侧:Lambda表达式中所需要执行的功能,即Lambda体

Lambda表达式需要一个函数式接口的支持,所谓的函数式接口指的是接口中只有一个抽象方法的接口

语法格式一

无参数,无返回值

()->System.out.println(“Hello Lambda!”);

import org.junit.Test;

public class TestLambda1 {

	//无参数并且无返回值
    @Test
    public void test1()
    {
        //匿名内部类
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world!");
            }
        };
        r.run();
        System.out.println("-------------");

        //Lambda表达式
        Runnable r1 = ()-> System.out.println("Hello Lambda");
        r1.run();
    }
}

语法格式二

语法格式二:有一个参数,但是没有返回值。
(x)-> System.out.println(x);
若只有一个参数,小括号可以省略不写,
x-> System.out.println(x);

public class TestLambda1 {

	@Test
    public void test2()
    {
        Consumer<String> con = (x)-> System.out.println(x);
        //小括号可以不写
        //Consumer<String> con = x-> System.out.println(x);
        con.accept("威武 ");
    }
}

语法格式三

有两个及以上的参数,有返回值,并且Lambda体中有多条语句

@Test
public void test3()
{
	Comparator<Integer> com = (x,y)->{
	            System.out.println("函数式接口");
	            return Integer.compare(x,y);
	        };
}

语法格式四

若Lambda体中只有一条语句,return和大括号都可以省略不写

@Test
public void test4()
{
    Comparator<Integer> com = (x,y)-> Integer.compare(x,y);
}

语法格式五

Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,这个过程称之为“类型推断”。

  • (x,y)-> Integer.compare(x,y);

这个和数组初始化类似,可以通过左边的定义的数组的类型推断出大括号里所给的是字符串类型的数据。

  • String[] strs = {“aaa”,“bbb”,“ccc”};
    但是如果拆分开来写就不可以
  • String[] strs;
  • strs = {“aaa”,“bbb”,“ccc”};
//可以通过函数参数类型,推断出参数类型,则左侧类型可写可不写。
(Integer x,Integer y)->Integer.compare(x,y);

总结

  • 左右遇一括号省(左边只有一个参数则括号可以省略,右边只有一条语句,那么大括号省略)
  • 左侧推断类型省(可以通过函数参数类型,推断出参数类型,则左侧类型可写可不写。)
  • Lambda表达式需要函数式接口的支持,接口中只有一个抽象的方法的接口称为函数式接口,函数式接口可以使用一个注解即@FunctionalInterface修饰一下。

Lambda表达式的使用例子

例子1:使用Lambda表达式对一个数进行操作

import org.junit.Test;
@FunctionalInterface
public interface MyFun {
    public Integer getValue(Integer num);
}

public class TestLambda2 {
    //需求:对一个数进行运算
    @Test
    public void test()
    {
    	//具体什么操作通过Lambda表达式实现
        Integer num = operation(100, x -> x * x);
        System.out.println(num);
    }
    public Integer operation(Integer num,MyFun mf)
    {
        return mf.getValue(num);
    }


}

例子2:使用Lambda进行定制排序

调用Collection.sort()方法,通过定制排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda表达式作为参数传递。

import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class TestLambda3 {

    List<Employee> emps = Arrays.asList(
            new Employee("张三",18,9999.99),
            new Employee("李四",59,6666.66),
            new Employee("王五",28,3333.33),
            new Employee("赵六",8,7777.77),
            new Employee("田七",38,5555.55)
    );

    @Test
    public void test1()
    {
        Collections.sort(emps,(e1,e2)->{
            if(e1.getAge() == e2.getAge())
            {
                return e1.getName().compareTo(e2.getName());
            }
            else
            {
                return Integer.compare(e1.getAge(),e2.getAge());
            }
        });

        for (Employee emp:emps)
        {
            System.out.println(emp);
        }
    }
}

例子三

  • 1、声明函数式接口,接口中声明抽象方法,public String getValue(String str);
  • 2、声明类TestLambda,类中编写方法使用接口作为参数,将一个字符串转化为大写,并作为方法的返回值。
  • 3、再将一个字符串的第2个和第4个索引位置进行截取子串。
import org.junit.Test;
import java.util.Locale;

@FunctionalInterface
interface MyFunction
{
    public String getValue(String str);
}
public class TestLambda4 {
    public String strHandler(String str,MyFunction mf)
    {
        return mf.getValue(str);
    }

    @Test
    public void test()
    {
        String trimStr = strHandler("\\t\\t\\t abcdef",str-> str.trim());
        String upper = strHandler(trimStr,str-> str.toUpperCase());
        String newStr = strHandler(upper,str-> str.substring(2,5));
        System.out.println(newStr);
    }
}

例子四

  • 1、声明一个带两个泛型的函数式接口,泛型类型为<T,R>,T为参数,R为返回值
  • 2、接口中声明对应抽象方法。
  • 3、在TestLambda类中声明方法,使用接口作为参数,计算两个long参数的和。
  • 4、在计算两个long型参数的乘积。
public class TestLambda
{
	@Test
    public void test3()
    {
        op(100L,200L,(x,y)->x+y);
        op(100L,200L,(x,y)->x*y);
    }
    @FunctionalInterface
    interface MyFunction2
    {
        public long getvalue(long l1,long l2);
    }
    public void op(long l1,long l2,MyFunction2 mf)
    {
        System.out.println(mf.getvalue(l1,l2));
    }
}

java内置四大核心函数式接口(Consumer、Supplier、Function、Predicate)

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.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 TestLambda5 {
    //Consumer<T> 消费型接口:
    @Test
    public void test1()
    {
        happy(1000,m-> System.out.println("消费"+m+"元"));
    }
    public void happy(double money以上是关于Java8-新特性的主要内容,如果未能解决你的问题,请参考以下文章

2020了你还不会Java8新特性?Java 8新特性介绍

java8新特性——Lambda表达式

Java8新特性

java8新特性总结

Java8新特性

Java8新特性-官方库新特性