Java教程

012—JAVA8新特性(lambda表达式)

本文主要是介绍012—JAVA8新特性(lambda表达式),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

函数式编程(lambda表达式 @FunctionalInterface)

        思想:(函数式编程VS面向对象)

函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。编程中的函数,也有类似的概念,你调用我的时候,给我实参为形参赋值,然后通过运行方法体,给你返回一个结果。对于调用者来做,关注这个方法具备什么样的功能。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做

面向对象的思想:

        做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情.

函数式编程思想:

        只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程

优点:

        目的是简化匿名内部类 

        Lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的匿名内部类。

 冗余的匿名内部类

public class Demo01Runnable {
	public static void main(String[] args) {
    	// 匿名内部类
		Runnable task = new Runnable() {
			@Override
			public void run() { // 覆盖重写抽象方法
				System.out.println("多线程任务执行!");
			}
		};
		new Thread(task).start(); // 启动线程
	}
}

分析弊端:

对于Runnable的匿名内部类用法,可以分析出几点内容:

  • Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心;

  • 为了指定run的方法体,不得不需要Runnable接口的实现类;

  • 为了省去定义一个RunnableImpl实现类的麻烦,不得不使用匿名内部类;

  • 必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;

  • 而实际上,似乎只有方法体才是关键所在

编程思想转换

        做什么,而不是谁来做,怎么做 (关注点不同)

我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将run方法体内的代码传递给Thread类知晓。

传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。那,有没有更加简单的办法?如果我们将关注点从“怎么做”回归到“做什么”的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要。

函数式编程面向的主要场景是,针对于函数式接口(@FunctionalInterface,即接口中只含有一个抽象方法,对于静态方法和default方法没有限制).

了解函数式接口:

写法:

针对于抽象方法,省略方法声明,只要参数,和方法体,如果方法体只有一个语句也可以省略{},否则可以省略。

()->{}
    ():形参
    ->: 语法标识
    {}:方法体

注意:
    1.如果方法重写后 仅有一行代码 可以省略{}
    2.()数据类型可以省略
    3.如果带返回值的方法 只有一行返回语句
      那么可以省略 return {};

 

  • (形参列表)它就是你要赋值的函数式接口的抽象方法的(形参列表),照抄

  • {Lambda体}就是实现这个抽象方法的方法体

  • ->称为Lambda操作符(减号和大于号中间不能有空格,而且必须是英文状态下半角输入方式)

优化:Lambda表达式可以精简

  • 当{Lambda体}中只有一句语句时,可以省略{}和{;}

  • 当{Lambda体}中只有一句语句时,并且这个语句还是一个return语句,那么return也可以省略,但是如果{;}没有省略的话,return是不能省略的

  • (形参列表)的类型可以省略

  • 当(形参列表)的形参个数只有一个,那么可以把数据类型和()一起省略,但是形参名不能省略

  • 当(形参列表)是空参时,()不能省略

 

lambda表达式其实就是实现SAM接口的语法糖,所谓SAM接口就是Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法。为了简化匿名内部类的写的方式

其实只要满足“SAM”特征的接口都可以称为函数式接口,都可以使用Lambda表达式,但是如果要更明确一点,最好在声明接口时,加上@FunctionalInterface。一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。

之前学过的SAM接口中,标记了@FunctionalInterface的函数式接口的有:Runnable,Comparator 。

Java8在java.util.function新增了很多函数式接口:主要分为四大类,消费型、供给型、判断型、功能型。基本可以满足我们的开发需求。当然你也可以定义自己的函数式接口。

函数式编程只关注结果

函数式接口的分类:

(一)自定义函数式接口

系统类的函数式接口:
       @FunctionalInterface
       public interface Runnable {}
       @FunctionalInterface
       public interface Comparator<T> {}

       public interface Comparable<T> {}只有一个抽象方法

系统函数式接口的分类:
   消费型           貔貅   只进不出      只接受数据 不返回数据
   供给型接口        雷锋  只奉献不索取   只返回数据 不接受数据
   判断/断言型接口   法官   判断对错      无论接受什么数据 都只返回 boolean

   功能型接口       普通人    有来有往    既接受数据  也返回数据

只要确保接口中有且仅有一个抽象方法即可。

public class AutoDefination {
    public static void main(String[] args) {
        A a = new A() {
            @Override
            public void add(int a, int b) {
                System.out.println(a + b);
            }
        };
        a.add(100, 200);

    }
    @Test
    public void test02(){
        //lambda表达式只对抽象接口起作用
        testAdd(100, 200, (a,b) -> System.out.println(a + b));
    }
    @Test
    public void test01(){
    testAdd(100, 200, new A() {
        @Override
        public void add(int a, int b) {
            System.out.println(a + b);
        }
    });

    }

    public static void testAdd(int a,int b,A c){
        c.add(a, b);
    }
}

@FunctionalInterface
interface A{
    //创建抽象方法
    void add(int a,int b);
}

(二)消费型接口

消费型接口的抽象方法特点:有形参,但是返回值类型是void

 举例(list遍历和map遍历lambda)

list遍历

public class ConsumerTest {
        ArrayList<String> list = new ArrayList<>();
    @Before
    public void test00(){
        Collections.addAll(list, "A","B","C","D","E");
    }
    @Test
    public void test06(){
    }

    @Test
    public void test05(){
        list.forEach((s) -> System.out.println(s));
        ;
    }
   
    @Test
    public void test03(){
        //会从传入参数的前一个位置开始遍历
        ListIterator<String> listIterator = list.listIterator(list.size());

        while (listIterator.hasPrevious()){
            String current = listIterator.previous();
            System.out.println("current = " + current);
        }


    }

    @Test
    public void test02(){
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println("next = " + next);
        }


    }
    @Test
    public void test01(){
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));

        }
        
    }
}

map遍历

public class TestMap {
        Map<Integer, String> map = new HashMap<>();
    @Before
    public void test00(){
        map.put(1, "A");
        map.put(2, "B");
        map.put(3, "C");
        map.put(4, "D");
        map.put(5, "E");

    }
    @Test
    public void test03(){
        map.forEach(new BiConsumer<Integer, String>() {
            @Override
            public void accept(Integer integer, String s) {
                System.out.println(integer + "--->" + s);
            }
        });

    }
    @Test
    public void test02(){

        map.forEach((k , v) -> System.out.println(k +  "---->" + v));
    }
    @Test
    public void test01(){
        Set<Integer> keys = map.keySet();
        keys.forEach((key) -> System.out.println(key +"---->" + map.get(key)));

    }
}

 (三)供给型接口

这类接口的抽象方法特点:无参,但是有返回值

public class SupplierTest {
    @Test
    public void test03(){
        // //生成数据 将数据进行展示  无限生成
        /*Stream.generate(new Supplier<Object>() {
            @Override
            public Object get() {
                return new Date();
            }
        }).forEach(new Consumer<Object>() {
            @Override
            public void accept(Object o) {
                System.out.println("o = " + o);
            }
        });*/

        Stream.generate(() -> new Date()).forEach(System.out::println);

    }



    @Test
    public void test02(){
        /*Supplier<Double> supplier = new Supplier<Double>() {
            @Override
            public Double get() {
                return Double.valueOf(Math.PI);
            }
        };*/
        Supplier<Double> supplier = () -> Double.valueOf(Math.PI);
        Double aDouble = supplier.get();
        System.out.println("aDouble = " + aDouble);

    }

    @Test
    public void test01(){
        /*//返回一个对象
        Supplier supplier = new Supplier() {
            @Override
            public Object get() {
                return new String("供给型接口作用是返回一个对象");
            }
        };*/
        Supplier supplier = () -> new String("供给型接口作用是返回一个对象");


        Object o = supplier.get();
        System.out.println("o = " + o);

    }
}

 (四)判断型 (用于过滤数据)

这里接口的抽象方法特点:有参,但是返回值类型是boolean结果。

 

public class PredicateTest {
    ArrayList<Integer> list = new ArrayList<Integer>();
    @Before
    public void test00(){
        Collections.addAll(list, 1,2,3,4,5,6,7,8,9,10);
        list.forEach((n)-> System.out.print(n + " "));
        System.out.println();
        System.out.println("-------------数据添加完毕-----------------");

    }
    @Test
    public void test01(){
        //删除 经过检验 返回值为true的值
        /*
        //方式一
        list.removeIf(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                //删除偶数
                if (integer % 2 == 0){
                    return true;
                }else {
                    return false;
                }
            }
        });*/
        //方式二
//        list.removeIf((integer) -> integer % 2 == 0? true:false);
        //方式三
        list.removeIf((integer)->integer%2==0);

    }


    @After
    public void test000(){
        System.out.println("------------数据处理完打印----------------");
        list.forEach((n)-> System.out.print(n+ " "));


    }


}

 

(五)功能型

这类接口的抽象方法特点:既有参数又有返回值

public class FunctionTest {
    HashMap<Integer, String> map = new HashMap<>();

    @Before
    public void test00() {

        map.put(1, "李白");
        map.put(2, "安琪拉");
        map.put(3, "白居易");
        map.put(4, "李商隐");
        map.put(5, "嬴政");
        map.forEach((k, v) -> System.out.println(k + "--->" + v));

    }
    @Test
    public void test04() {
        map.replaceAll((k,v)-> v.contains("李")?"妲己":v);
    }

    @Test
    public void test03() {
        map.replaceAll((k,v) -> {
          return v.contains("李")?"妲己":v;
        });



    }
    @Test
    public void test02() {
        map.replaceAll((k, v) -> {
            if (v.contains("李")) {
                return "妲己";
            } else {
                return v;
            }
        });
    }


    @Test
    public void test01() {


        map.replaceAll(new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer key, String value) {
//                System.out.println(key + "------>" + value);
                //只要value中有白 ,就要将此value替换成妲己
                if (value.contains("白")) {
                    return "妲己";
                }
                //返回值会替换原有的value
                return value;
            }
        });

    }

    @After
    public void test000() {
        System.out.println("-----------------");

        map.forEach((k, v) -> System.out.println(k + "--->" + v));


    }
}

判断型接口 练习

public class Employee {
    private int id;
    private String name;
    private char gender;
    private int age;
    private double salary;

    public Employee(int id, String name, char gender, int age, double salary) {
        super();
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.salary = salary;
    }
    public Employee() {
        super();
    }
    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 char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    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 [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", salary=" + salary
                + "]";
    }
}

 

public class EmployeeSerice {
    ArrayList<Employee> all;

    public EmployeeSerice() {
        all = new ArrayList<Employee>();
        all.add(new Employee(1, "张三", '男', 33, 8000));
        all.add(new Employee(2, "翠花", '女', 23, 18000));
        all.add(new Employee(3, "无能", '男', 46, 8000));
        all.add(new Employee(4, "李四", '女', 23, 9000));
        all.add(new Employee(5, "老王", '男', 23, 15000));
        all.add(new Employee(6, "大嘴", '男', 23, 11000));
    }

    ArrayList<Employee> get(Predicate<Employee> p) {
        //在EmployeeSerice员工管理类中,声明一个方法:
        // ArrayList<Employee> get(Predicate<Employee> p),
        // 即将满足p指定的条件的员工,添加到一个新的ArrayList<Employee> 集合中返回。
        ArrayList<Employee> emp = new ArrayList<>();
        for (Employee employee : all) {
            //底层Predicate接口中有个抽象方法  boolean test(T t); 推断型接口返回类型为Boolean
            if (p.test(employee)) {
                emp.add(employee);
            }
        }
        return emp;
    }


}
class EmployeeTest {
    public static void main(String[] args) {
        EmployeeSerice es = new EmployeeSerice();
       /* es.get(new Predicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                System.out.println(employee);
                return true;
            }
        });*/
        //- 所有员工对象
        es.get((e)-> true).forEach((s) -> System.out.println(s));
        System.out.println("-----------");
        //        - 所有年龄超过35的员工
        es.get((e) -> e.getAge() > 35 ).forEach(System.out::println);
        //        - 所有薪资高于15000的女员工
        System.out.println("-------------------");
        es.get((e) -> e.getSalary()>15000).forEach(System.out::println);
        //        - 所有编号是偶数的员工
        es.get((e) -> e.getId() % 2 == 0).forEach(System.out::println);
        //        - 名字是“张三”的员工
        es.get((e) -> e.getName().equals("张三")).forEach(System.out::println);
        //        - 年龄超过25,薪资低于10000的男员工
        es.get((e) -> e.getAge()>25 && e.getSalary()<10000).forEach(System.out::println);



    }


}

这篇关于012—JAVA8新特性(lambda表达式)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!