《Java编程入门官方教程》第十四章练习答案

【练习14-1(LambdaArgumentDemo.java)】作为实参传递lambda表达式

lambda表达式可用在任何提供了目标类型的上下文中。前面示例中使用的上下文是赋值和初始化。另一种情况就是作为实参传递lambda表达式。事实上,这是lambda表达式的一种常见且强大的用途,因为可将可执行代码作为实参传递给方法,这极大地增强了Java的表达力。

为了演示过程,本练习中创建了三个字符串函数,它们执行以下操作:颠倒字符串、颠倒字符串中字母的大小写、用连字符替代空格。这些函数作为函数式接口StringFunc的lambda表达式实现。之和它们作为第一个实参传递给changeStr()方法。changeStr()方法将字符串函数应用于第二个实参传递给changeStr()的字符串并返回结果。因此,changeStr()方法可用于各种不同的字符串函数。

java 复制代码
package javaone.a.beginners.guide.chapterfourteen;

// Use a lambda expression as an argument to a method.
interface StringFunc{
    String func(String str);
}

public class ChapterFourteenProgramOne {

    // This method has a functional interface as the type of its
    // first parameter. Thus, it can be passed a reference to any
    // instance of that interface, including an instance created
    // by a lambda expression. The second parameter specifies the
    // string to operate on.
    static String changeStr(StringFunc sf, String s){
        return sf.func(s);
    }

    public static void main(String[] args) {
        String inStr = "Lambda Expressions Expand Java";
        String outStr;

        System.out.println("Here is input string: " + inStr);

        // Define a lambda expression that reverses the contents
        // of a string and assign it to a StringFunc reference varible.
        StringFunc reverse = (str) -> {
            String result = "";
            for (int i = str.length() - 1; i >= 0 ; i--) {
                result += str.charAt(i);
            }
            return result;
        };

        // Pass reverse to the first argument to changeStr().
        // Pass the input string as the second argument.
        outStr = changeStr(reverse, inStr);
        System.out.println("The string reversed: " + outStr);

        // This lambda expression replace spaces with hyphens.
        // It is embedded directly in the call to changeStr().
        outStr = changeStr((str)->str.replace(' ','-'), inStr);
        System.out.println("The string with spaces replaced: " + outStr);

        // This block lambda invert the case of the characters in the
        // string. It is also embedded directly in the call to changeStr().
        outStr = changeStr((str) -> {
            String result = "";
            char ch;
            for (int i = 0; i < str.length(); i++) {
                ch = str.charAt(i);
                if(Character.isUpperCase(ch)){
                    result += Character.toLowerCase(ch);
                }else{
                    result += Character.toUpperCase(ch);
                }
            }
            return result;
        }, inStr);
        System.out.println("The string in reversed case: " + outStr);
    }

}

14.9 自测题

  1. 什么是lambda运算符?

答案:lambda运算符是->。

  1. 什么是函数式接口?

答案: 函数式接口是指仅指定一个抽象方法的接口。

  1. 函数式接口和lambda表达式是如何关联的?

答案:lambda表达式提供函数式接口定义的抽象方法的实现。函数式接口定义目标类型。

  1. lambda表达式的两种常见类型是什么?

答案:lambda表达式的两种类型是表达式lambda和块lambda。表达式lambda指定单一的表达式,其值由lambda返回。而块lambda包含一个代码块,其值由return语句指定。

  1. 给出一个lambda表达式,如果某个数字在10和20之间(包括10和20),该表达式返回的结果为true。

答案:(n) -> (9 < n && n < 21);

  1. 创建一个函数式接口,使之支持习题5中所创建的lambda表达式。调用接口MyTest及其抽象方法testing()。

答案:

interface MyTest{

boolean testing(int n);

}

  1. 创建一个计算某个整数值的阶乘的块lambda。演示其用法,对于该函数式接口使用本章介绍的NumericFunc。
java 复制代码
package javaone.a.beginners.guide.chapterfourteen;

interface NumericFuncOne{
    int func(int n);
}
public class ChapterFourteenExerciseSeven {

    public static void main(String[] args) {
        // This block lambda computes the factorial of an int value.
        NumericFuncOne factorial = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++) {
                result *= i;
            }
            return result;
        };
        System.out.println("The factorial of 3 is " + factorial.func(3));
        System.out.println("The factorial of 5 is " + factorial.func(5));
        System.out.println("The factorial of 9 is " + factorial.func(9));
    }

}
  1. 创建一个名为MyFunc<T>的泛型函数式接口。调用它的抽象方法func()。让func()返回一个T类型的引用,并让它接受T类型的形参(因此,MyFunc将是本章中所介绍的NumericFunc的泛型版本)。重写习题7的答案,演示其用法,这样就可以使用MyFunc<T>而不使用NumericFunc。
java 复制代码
package javaone.a.beginners.guide.chapterfourteen;

interface MyFuncTwo<T>{
    T func(T n);
}

public class ChapterFourteenExerciseEight {
    public static void main(String[] args) {
        // This block lambda computes the factorial of an int value.
        MyFuncTwo<Integer> factorial = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++) {
                result *= i;
            }
            return result;
        };
        System.out.println("The factorial of 3 is " + factorial.func(3));
        System.out.println("The factorial of 5 is " + factorial.func(5));
        System.out.println("The factorial of 9 is " + factorial.func(9));
    }
}
  1. 使用练习14-1所示的程序创建一个lambda表达式,删除字符串中的所有的空格并返回结果。通过将其传递给changeStr()演示该方法。
java 复制代码
package javaone.a.beginners.guide.chapterfourteen;

interface StringFuncOne{
    String func(String str);
}
public class ChapterFourteenExerciseNine {

    static String changeStr(StringFuncOne sf, String s){
        return sf.func(s);
    }

    public static void main(String[] args) {
        String inStr = "Lambda Expressions Expand Java";
        String outStr;

        System.out.println("Here is input string: " + inStr);
        outStr = changeStr((str)->str.replace(" ",""), inStr);
        System.out.println("The string with spaces replaced: " + outStr);
    }

}
  1. lambda表达式可使用局部变量吗?如果可以,必须满足什么约束条件?

答案:可以,但变量必须是有效的final。

  1. 如果lambda表达式抛出了经检查的异常,函数式接口中的抽象方法必须有一条包含该异常的throws子句。这种说法正确吗?

答案: 正确。

  1. 什么是方法引用?

答案:方法引用是指引用某个方法但不执行它的一种方法。

  1. 当被计算时,方法引用会创建一个由其上下文提供的_________的实例。

答案:函数式接口。

  1. 假定名为MyClass的类包含静态的抽象方法myStaticMethod(),请说明如何指定对该抽象方法的方法引用。

答案:myClass::myStaticMethod。

  1. 假定名为MyClass的类包含实例方法myInstMethod(),并假定MyClass的一个对象称为mcObj,请说明如何创建对mcObj对象的myInstMethod()方法的引用。

答案:mcObj::myInstMethod。

  1. 在MethodRefDemoTwo程序中,将新方法hasCommonFactor()添加到MyIntNum中。如果方法hasCommonFactor()的int实参和存储在调用对象MyIntNum中的值至少有一个公有因子,该方法就返回true。例如,9和12就有公有因子3,9和16就没有公有因子。请通过方法引用演示hasCommonFactor()的用法。
java 复制代码
package javaone.a.beginners.guide.chapterfourteen;

interface IntPredicateTwo{
    boolean test(int n);
}

class MyIntNumTwo{
    private int v;
    MyIntNumTwo(int x){
        v = x;
    }
    int getNum(){
        return v;
    }
    // Return true if n is a Factor of v.
    boolean isFactor(int n){
        return (v % n) == 0;
    }
    boolean hasCommonFactor(int n){
        for (int i = 2; i < v/i; i++) {
            if(((v % i) == 0) && ((n % i) == 0)){
                return true;
            }
        }
        return false;
    }
}
public class ChapterFourteenExerciseSixteen {

    public static void main(String[] args) {
        boolean result;
        MyIntNumTwo myIntNum = new MyIntNumTwo(12);
        IntPredicateTwo ip = myIntNum::hasCommonFactor;
        result = ip.test(9);
        if(result){
            System.out.println("Common factor found.");
        }
    }

}
  1. 如何指定构造函数引用?

答案:通过指定类名后紧随::,之后紧跟new可以创建构造函数引用。例如,MyClass::new。

  1. Java定义的几个预定义函数式接口都位于哪个包中?

答案:java.util.function。

相关推荐
司马相楠2 分钟前
嵌入式开发 的软件开发技能
开发语言·后端·golang
superCleanCoder3 分钟前
spring-boot启动源码分析(二)之SpringApplicationRunListener
java·spring boot
大卫小东(Sheldon)15 分钟前
在jooq的POJO类中使用Lombok的Data注解
java
java_t_t19 分钟前
安卓触摸事件的传递
android·java
fruge22 分钟前
【Cesium】九、Cesium点击地图获取点击位置的坐标,并在地图上添加图标
开发语言·javascript·ecmascript
BMG-Princess25 分钟前
SpringMVC
java·开发语言·前端
ac-er888825 分钟前
Go work stealing 机制
java·数据库·golang
小王不会写code26 分钟前
Spring MVC 的@GetMapping和@PostMapping和@PutMapping
java·spring·mvc
故里有青山37 分钟前
静态初始化块与非静态初始化块
java·开发语言
晴空๓38 分钟前
Java反射详解(三)
java·开发语言·python