java面向对象(4)

1、Lambda表达式

    Lambda表达式就是简化的匿名内部类,它可以部分取代匿名内部类的作用,用来创建只有一个抽象方法的接口的实例。只有一个抽象方法的接口称为函数式接口,函数式接口可以包含默认方法和类方法。

    Lambda表达式由形参列表()、箭头->、代码块{}组成:参数类型可以省略;如果只有一个参数那么形参列表的圆括号可以省略;如果代码块中只有一条语句,那么可以省略花括号;如果代码块中只有一条return语句,可以省略return标识符。

    Lambda表达式的本质就是使用比匿名内部类更简洁的语法来创建函数式接口的实例。

interface Product  
{  
    public String getName(int No);  
}  
  
class Bar  
{  
    public void test(Product p)  
    {  
        p.getName(100);  
    }  
    public void func1() //使用普通内部类  
    {  
        class GoodProduct implements Product  
        {  
            public String getName(int No)  
            {  
                return "name";  
            }  
        }  
        test(new GoodProduct());  
    }  
    public void func2() //使用匿名内部类  
    {  
        test(new Product()  
        {  
            public String getName(int No)  
            {  
                return "name";  
            }  
        });  
    }  
	public void func3() //使用Lambda表达式
	{
		test((int No)->{return "name";}); //省略写法:test(No->"name");
	}
}  

    因为Lambda表达式的结果就是对象实例,所以可以使用Lambda表达式进行赋值:

Runnable r = ()->{}; //Runnable是java中一个函数式接口

    Lambda表达式的目标类型必须是明确的函数式接口,如上面的Bar类中func3方法中将Lambda表达式赋给函数式接口Product类型的参数,编译器就知道传入的Lambda表达式的目标类型就是函数式接口。再如上面将Lambda表达式赋值给函数式接口Runnable类型,编译器就知道传入的Lambda表达式的目标类型就是函数式接口。而如果将Lambda表达式直接赋值给Object对象则会失败,因为Lambda表达式的目标类型必须是明确的函数式接口,而此时编译器不知道该Lambda表达式哪个函数式接口,解决方法是使用函数式接口对Lambda表达式进行强制类型抓换:

Object o = ()->{}; //错误
Object o = (Runnable)()->{};

    Lambda表达式常见的用法就是将Lambda表达式赋值给函数式接口类型的变量或参数,以及使用函数式接口对Lambda表达式进行强制类型转换。

    java 8在java.util.function包下定义了大量的函数式接口,包含有:

        xxxFunction:通常包含一个apply()抽象方法,该方法对参数进行处理或转换,然后返回一个新的值,当然处理的逻辑由Lambda表达式来实现。
        xxxConsumer:通常包含一个accept()抽象方法,与xxxFunction接口不同的是它不会返回新的值,只是对参数进行处理。
        xxxPredicate:通常包含一个test()抽象方法,用来判断参数是否满足指定条件,返回一个boolean值。

        xxxSupplier:通常包含一个getAsXXX()的抽象方法,该方法不用输入参数,只是实现特定的计算返回一个数据。

    只有一个参数那么形参列表的圆括号可以省略。
    代码块中只有一条语句,那么可以省略花括号。
    代码块中只有一条return语句,可以省略return标识符。

2、方法引用

    方法引用相当于简化的Lambda表达式,可以有指向静态方法的引用、指向某个对象的实例方法的引用、指向某个类型的实例方法的引用、指向构造方法的引用,通过双冒号来实现:

package xu;
import java.util.*;  
import java.util.stream.*; 
import javax.swing.*;

interface Converter  
{  
    Integer convert(String str);  
}  

interface MySubstring  
{  
    String Substring(String str, int start, int end);  
}  

interface Print
{
	void func();
}

interface MyTest  
{  
    JFrame win(String title);  
}  

public class Test
{
	public static void main(String[] args)
	{	
		//指向类方法(静态成员方法)的引用
		Converter conv1 = Integer::valueOf; //valueOf是类方法,该语句相当于 Converter conv1 = str->Integer.valueOf(str);  
        Integer i = conv1.convert("99"); // i为99

		Integer[] ary = new Integer[]{3, 5, 0, 8, 1};
		Arrays.parallelSort(ary, Integer::compare); //该语句与下面的语句等价
		Arrays.parallelSort(ary, (n1, n2)->{
			if(n1 > n2)
				return 1;
			else if(n1 < n2)
				return -1;
			else
				return 0;
		}); 
		System.out.println(Arrays.toString(ary)); //输出为[0, 1, 3, 5, 8]
		
		
		//指向某个对象的实例方法的引用
		class Bar
		{
			void func()
			{
				System.out.println("Bar func start");
			}
		}
		Bar b = new Bar();
		Print p = b::func;
		p.func();
		
		IntStream is = IntStream.builder().add(10).add(13).add(-1).build();
		is.forEach(System.out::println);//out是静态成员,该语句等价于 is.forEach(item->System.out.println(item));
		
		
		//指向某个类型的实例方法的引用, 下面语句的特点是:Lambda表达式函数体内语句都可以使用第一个参数的方法来替换实现
		MySubstring ms = String::substring;//相当于 MySubstring ms = (str, start, end)->str.substring(start, end);  
        String s = ms.Substring("hello world", 0, 5); //str为hello
		
		String str = Stream.of("A", "is", "a", "dog").reduce("", String::concat); //该语句相当于String str = Stream.of("A", "is", "a", "dog").reduce("", (s1, s2)->s1 + s2)
		System.out.println(str); //输出为"Aisadog"
		
	
		//指向构造方法的引用
		MyTest mt = JFrame::new;//因为接口MyTest中声明的抽象函数与JFrame的构造函数原型一致,相当于MyTest mt = (String str)->new JFrame(str);
        JFrame jf = mt.win("窗口");  
		
		String[] sAry = Stream.of("A", "is", "a", "dog").toArray(String[]::new); //toArray方法的参数类型是IntFunction接口对象,该接口的抽象函数与String数组的构造函数一致
		System.out.println(Arrays.toString(sAry)); //输出为[A, is, a, dog]
	}
}

3、Arrays与Lambda表达式的应用

package xu;
import java.util.Arrays;  
import java.util.Comparator;  
  
public class Test      
{      
    public static void main(String[] args)  
    {  
        //根据元素大小倒叙排序  
        Integer[] ary1 = new Integer[]{9, 4, 6, -1, -2, 3, 10, 0};  
        Comparator<Integer> cmp = (o1, o2)->  
        {  
            if(o1 < o2)  
                return 1;  
            else if(o1 > o2)  
                return -1;  
            else  
                return 0;  
        };  
        Arrays.sort(ary1, cmp);  
        System.out.println(Arrays.toString(ary1));  
		
  
        //根据元素长度排序  
        String[] ary2 = new String[]{"1234", "123", "12", "12345", "123", "12"};  
        Arrays.parallelSort(ary2, (o1, o2)->o1.length() - o2.length());  
        System.out.println(Arrays.toString(ary2));  
          
        //给数组元素赋值  
        int[] ary4 = new int[5];  
        Arrays.setAll(ary4, index->index * 5); //元素值是: 元素索引 * 5
	Arrays.parallelSetAll(ary4, index->ary4[index] * 5); //元素值是: 原元素值 * 5		
        System.out.println(Arrays.toString(ary4));  
		
          
        //根据当前元素和前一元素给数组元素赋值  
        int[] ary3 = new int[]{3, -4, 25, 16, 30, 18};  
        Arrays.parallelPrefix(ary3, (left, right)->left * right);//left为数组中前一索引的元素,right为当前索引元素,right为第一个元素时,left值为1  
        System.out.println(Arrays.toString(ary3));  
    }  
}

猜你喜欢

转载自blog.csdn.net/milanleon/article/details/80591951
今日推荐