h-c-g

一、简述String类中的equals方法与Object类中的equals方法的不同点。

答:String类中的equals方法是用来判断两个对象的内容是否相同,而Object 类中的equals方法是用来判断两个对象是否是同一个对象,所谓同一个对象指的是内存中的同一块存储空间。

不运行代码,直接说出打印结果,并解释原因。

public class ToStringTest{
    static int i = 1;
    public static void main(String args[]){
        System.out.println("love " + new ToStringTest());//love java
        ToStringTest a = new ToStringTest();
        a.i++;
        System.out.println("me " + a.i);//me 2
    }
    public String toString(){
        System.out.print("I ");//I
        return "java ";
    }
}
运行结果:I love java    me 2
原因:当执行代码的时候,首先加载静态变量,然后执行main方法,由于main方法内部第一行代码为输出语句,里面new了此类对象,当执行此行代码时会先创建了本类的对象,由于此类重写了toString方法,会先执行toString方法的打印输出,
然后返回“java ”,再执行main方法第一行打印输出。在Java中“System.out.println(类对象名);”实际输出的是该对象的toString()方法返回的字符串,即括号中的内容等价于类对象名.toString(),toString方法的好处是在碰到print
ln方法的时候会被自动调用,不用显示的写出来。

一、看下列程序,不运行说结果,写出答案后,并在IntelliJ IDEA中运行看看自己给的答案与运行结果是否正确,并分析原因。

(1)
        String s1 = new String("abc");
        String s2 = "abc";
        System.out.println(s1 == s2);         //false
        System.out.println(s1.equals(s2));         //true
    (2)
        String s1 = "abc";
              String s2 = "abc";
        System.out.println(s1 == s2);         //true
        System.out.println(s1.equals(s2));     //true
    (3)
        String s1 = "a" + "b" + "c";
              String s2 = "abc";
        System.out.println(s1 == s2);             //true
        System.out.println(s1.equals(s2));     //true
    (4)
        String s1 = "ab";
             String s2 = "abc";
             String s3 = s1 + "c";
        System.out.println(s3 == s2);         //false
              System.out.println(s3.equals(s2));       //true

一、简述StringBuilder类与String类的区别

答:String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象,所以经常改变内容的字符串最好不要用String,因为每次生成对象都会对系统性能产生影响。

StringBuilder又称为可变字符序列,是JDK5.0中新增加的一个类,它是一个类似于String的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。即它是一个容器,容器中可以装很多字符串,并且能够对其中的字符串进行各种

操作。它的内部拥有一个数组用来存放字符串内容,进行字符串拼接时,直接在数组中加入新内容,StringBuilder会自动维护数组的扩容

一、请用代码实现:获取当前的日期,并把这个日期转换为指定格式的字符串,如2088-08-08 08:08:08

public class DateTest {
    public static void main(String[] args) {
        //获取当前日期对象 now;
        Date now = new Date();
        //创建SimpleDateFormat对象 df,并制定日期格式
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //调用df的format(Date  date) 方法,传入now; 接收返回的字符串
        String datestr = df.format(now);
        //打印这个字符串
        System.out.println(datestr);
    }
}

一、使用SimpleDateFormat类,把2018-03-04转换为2018年03月04日

public class DateFormatTest {
    public static void main(String[] args) throws ParseException {
        //创建SimpleDateFormat对象df1,指定日期模式为yyyy-MM-dd
        SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
        //调用df1的parse(String str)方法传入2018-03-04,得到对应日期类型
        Date date = df1.parse("2018-03-04");
        //创建日期格式化对象df2,在获取格式化对象时可以指定风格
        DateFormat df2 = new SimpleDateFormat("yyyy年MM月dd日");
        //调用df2的format(Date date) 传入刚才转换的日期
        String str = df2.format(date);
        System.out.println(str);
    }
}

一、用程序判断2018年2月14日是星期几

public class CalendarTest01 {
    public static void main(String[] args) {
        //创建Calendar对象
        Calendar c = Calendar.getInstance();
        //将给定的日历字段设置到Calendar对象中
        c.set(Calendar.YEAR, 2018);
        c.set(Calendar.MONTH, 1);
        c.set(Calendar.DATE, 14);
        //设置年
        int year = c.get(Calendar.YEAR);
        //设置月
        int month = c.get(Calendar.MONTH)+1;
        //设置日
        int date = c.get(Calendar.DATE);
        //设置星期
        char week = getWeek(c.get(Calendar.DAY_OF_WEEK));
        //输出结果
        System.out.println(year+"年"+month+"月"+date+"日是星期"+week);
    }
    //定义方法,获取星期汉字
    public static char getWeek(int a){
        char[] c = {\' \',\'日\',\'一\',\'二\',\'三\',\'四\',\'五\',\'六\'};
        return c[a];
    }
}

一、现有一个字符数组{\'i\',\'t\',\'c\',\'a\',\'s\',\'a\'},请使用System类中的arraycopy()方法在控制台输出“itcast”。(提示:将[1]号数组元素复制到最后位置并覆盖原有元素。)

public class ArraycopyTest {
    public static void main(String[] args) {
        char[] cha ={\'i\',\'t\',\'c\',\'a\',\'s\',\'a\'};
        //将cha数组中第2个元素,复制到目标数组最后一位数组上
        System.arraycopy(cha, 1, cha, 5, 1);
        //遍历目标数组,在控制台输出字符串
        for (int i = 0; i < cha.length; i++) {
            System.out.print(cha[i]);
    }
    }
}

一、请使用代码实现

分别使用String的 += 和StringBuilder的append方法对字符串做100000次拼接,计算String拼接100000次花费时间与StringBuilder拼接100000次所花费时间并打印。

public class StringBuilder01 {
    public static void main(String[] args) {
        //使用System的currentTimeMillis()方法获取当前操作系统的毫秒值,作用程序执行的开始时间,使用start变量接收
        long start = System.currentTimeMillis();
        //需要测试执行性能的代码
        //testString(); //消耗时间: 29295毫秒
        testStringBuilder();//消耗时间:6毫秒
        //使用System的currentTimeMillis()方法获取当前操作系统的毫秒值,作用程序执行的结束时间,使用end变量接收
        long end = System.currentTimeMillis();
        //计算代码执行花费的时间 end - start,输出代码执行消耗的时间
        System.out.println("所花费的时间为:"+(end-start));
    }

    //写一个静态方法: testString(),在该方法中
    public static void  testString(){
        //定义一个字符串 str,内容随意
        String str = "hello";
        //写一个循环100000次for循环,在循环中写上
        for(int i = 0; i<100000;i++){
      //str +=”随机内容” ; 这里不要写str += (str+”xxx”) 这样会导致堆内存溢出错误.
            str += "world";
        }
    }
    //写一个静态方法:testStringBuilder(),在方法中
    public static void testStringBuilder(){
        //创建一个StringBuilder对象sb,初始内容与testString()中的字符串相同
        StringBuilder sb = new StringBuilder("hello");
        //写一个循环100000次for循环,在循环中写上
        for(int i = 0; i<100000;i++){
            //调用sb.append()方法,传入的内容与testString()方法中+=后面的内容一样
            sb.append("world");
        }
        //循环结束调用sb.toString()方法转换为字符串
        String newStr = sb.toString();
    }
}

一、分析以下需求,并用代码实现:

       (1)定义数字字符串数组{"010","3223","666","7890987","123123"};

       (2)判断该数字字符串数组中的数字字符串是否是对称(第一个数字和最后一个数字相等,第二个数字和倒数第二个数字是相等的,依次类推)的,并逐个输出;

       (3)如:010 是对称的,3223 是对称的,123123 不是对称的;

       (4)最终打印该数组中对称字符串的个数。

注:判断对称可用reverse(),将此字符序列用其反转形式取代。

public class StringBuilderTest02 {
    public static void main(String[] args) throws IOException {
        //定义数字字符串数组
        String[] str = {"010","3223","666","7890987","123123"};
        SBTest(str);
    }

    public static void SBTest(String[] str) {
        int count = 0;
        //遍历定义的字符串数组
        for (String string : str) {
            //创建StringBuilder对象
            StringBuilder sb = new StringBuilder(string);
            //调用reverse()方法,将遍历的数字进行反转,然后用equals()方法对比是否与原数字相同
            if (sb.reverse().toString().equals(string)) {
                count++;
                System.out.println(string + "是对称的");
            }
        }
        System.out.println("总数为" + count);
    }
}

一、分析以下需求,并用代码实现:

              (1)打印由7,8,9三个数组成的三位数,要求该三位数中任意两位数字不能相同;

              (2)打印格式最后的三位数字以空格分隔,如789 798 879 897 978 987。

注:要求使用StringBuilder来完成

public class StringBuilderTest03 {
    public static void main(String[] args) throws IOException, Exception {
        SBTest();
    }

    public static void SBTest() {
        //定义由7、8、9组成的字符串
        String s = "789";
        //创建StringBuilder对象
        StringBuilder sb = new StringBuilder();
        //采用嵌套for循环,遍历字符串
        for (int i = 0; i < 3; i++) {
            //遍历字符串s,把字符依次添加到StringBuilder内,组成一个元素
            for (int j = 0; j < s.length(); j++) {
                sb.append(s.charAt(j));
            }
            //当StringBuilder内元素为一个和两个时,需要加空格来隔开元素
            if (i != 2) {
                sb.append(" ");
            }
            //把字符串s的第一个元素切割,添加到字符串末位,组成新的字符串
            s = s.substring(1).concat(s.substring(0, 1));
        }
        // 把StringBuilder内元素反转,组成新的数字
        s = sb.toString() + " " + sb.reverse().toString();
        System.out.println(s);
    }
}

一、请简述集合框架。

集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection和双列集合java.util.Map。

Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是java.util.List和java.util.Set。其中,List的特点是元素有序、元素可重复。Set的特点是元素无序,而且不可重复。List接口的主要实现类有java.util.ArrayList和java.util.LinkedList,Set接口的主要实现类有java.util.HashSet和java.util.TreeSet。

一、给定以下代码,请定义方法listTest()统计集合中指定元素出现的次数,如"a": 2,"b": 2,"c" :1, "xxx":0。

              Collection<String> list = new ArrayList<>();

                     list.add("a");

                     list.add("a");

                     list.add("b");

                     list.add("b");

                     list.add("c");

                     System.out.println("a:"+listTest(list, "a"));

                     System.out.println("b:"+listTest(list, "b"));      

                     System.out.println("c:"+listTest(list, "c"));

                     System.out.println("xxx:"+listTest(list, "xxx"));            

public class CollectionTest01{
    public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();
        list.add("a");
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        System.out.println("a:"+listTest(list, "a"));
        System.out.println("b:"+listTest(list, "b"));
        System.out.println("c:"+listTest(list, "c"));
        System.out.println("xxx:"+listTest(list, "xxx"));
    }

    //定义方法统计集合中指定元素出现的次数
    public static int listTest(Collection<String> list,String s){
        //定义计数器,初始化为0
        int count = 0;
        //增强for遍历集合
        for (String string : list) {
            //判断传入方法的字符与遍历集合的是否一致
            if (s.equals(string)) {
                //如果一致,加1
                count++;
            }
        }
        return count;
    }
}

一、定义一个方法,要求此方法把int数组转成存有相同元素的集合(集合里面的元素是Integer),并返回。

public class CollectionTest02 {
    public static void main(String[] args) {
        //定义int数组
        int[] arr = {1,2,3,4,5};
        ArrayList<Integer> list = listTest(arr);
        System.out.println(list);
    }

    public static ArrayList<Integer> listTest(int[] arr) {
        //定义集合
        ArrayList<Integer> list = new ArrayList<Integer>();
        //遍历数组,把元素依次添加到集合当中
        for (int a : arr) {
            list.add(a);
        }
        return list;
    }
}

一、定义一个集合,并把集合(集合里面的元素是Integer)转成存有相同元素的数组,并将结果输出在控制台。(可以使用Object[]数组类型接收转换的数组)

public class CollectionTest03 {
    public static void main(String[] args) {
        //定义集合,添加数据
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(100);
        list.add(200);
        list.add(300);
        //Object[] toArray()转换成一个Object数组
        Object[] obj =  list.toArray();
        // 遍历数组
        for (int i = 0; i < obj.length; i++) {
            System.out.println(obj[i]);
        }
    }
}

一、定义一个方法listTest(ArrayList<String> al, String s),要求使用contains()方法判断al集合里面是否包含s。

public class CollectionTest04 {
    public static void main(String[] args) {
        //定义集合,添加数据
        ArrayList<String> list = new ArrayList<String>();
        list.add("itcast");
        list.add("itheima");
        list.add("java");
        System.out.println(listTest(list,"java"));
    }

    public static boolean listTest(ArrayList<String> al, String s) {
        //判断s是否在集合中存在,存在返回true,不存在返回false
        if (al.contains(s)) {
            return true;
        }
       return false;
    }
}

一、定义一个方法listTest(ArrayList<String> al), 要求使用isEmpty()判断al里面是否有元素

public class CollectionTest05 {
    public static void main(String[] args) {
        //定义集合,添加数据
        ArrayList<String> list = new ArrayList<String>();
        list.add("1");
        System.out.println(listTest(list));
    }

    public static boolean listTest(ArrayList<String> al) {
        //判断al集合是否为空,为空返回true,不为空返回false
        if(al.isEmpty()){
            return true;
        }
        return false;
    }
}

一、请简述迭代器的实现原理

当遍历集合时,首先通过调用集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。

Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,在调用Iterator的next()方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。

一、定义一个方法listTest(ArrayList<Integer> al, Integer s),要求返回s在al里面第一次出现的索引,如果s没出现过返回-1。

public class CollectionTest06 {
    public static void main(String[] args) {
        //定义集合,添加数据
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println(listTest(list, 5));
    }

    public static int listTest(ArrayList<Integer> al, Integer s) {
        //遍历集合,获取元素,判断元素是否与s相等,相等返回索引
        for (int i = 0; i < al.size(); i++) {
            if (al.get(i).equals(s)) {
                return i;
            }
        }
        return -1;
    }
}

一、(复杂,并不难)定义一个学生类Student,包含三个属性姓名、年龄、性别,创建三个学生对象存入ArrayList集合中。

A:遍历集合遍历输出。

B:求出年龄最大的学生,然后将该对象的姓名变为:小猪佩奇。

public class CollectionTest07 {
    public static void main(String[] args) {
        //定义集合,向集合中添加student对象
        ArrayList<Student> list = new ArrayList<Student>();
        list.add(new Student("张三", 23, "男"));
        list.add(new Student("王五", 28, "男"));
        list.add(new Student("李四", 25, "男"));
        print(list);
        System.out.println("--------------");
        change(list);
        System.out.println("--------------");
        System.out.println(list);
    }
    //
    public static void change(ArrayList<Student> list) {
        //定义变量存放年龄
        int a = 0;
        //定义变量存放最大年龄的索引值
        int index = 0;
        //遍历集合获取年龄值,与a相比较
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getAge() > a) {
                //如果年龄大于a,记录次数
                index = i;
                //并把年龄的最大值赋予a
                a = list.get(i).getAge();
            }
        }
        System.out.println("年龄最大的学生是" + list.get(index).getName());
        //将年龄最大的学生姓名变为:小猪佩奇
        list.get(index).setName("小猪佩奇");
    }
    //定义方法,遍历集合输出
    public static void print(ArrayList<Student> list) {
        for (Student student : list) {
            System.out.println(student);
        }
    }
}

一、产生101-100的随机数,并放到一个数组中,把数组中大于等于10的数字放到一个list集合中,并打印到控制台。

public class CollectionTest08 {
    public static void main(String[] args) {
        //1.产生10个1-100的随机数,把数组中大于等于10的数字放到一个list集合中,并打印到控制台。
        //(1)定义长度为10的int数组
        int[] arr = new int[10];
        //(2)创建产生随机数的对象
        Random r = new Random();
        //(3)产生随机数,并存入数组中
        for (int i = 0; i < arr.length; i++) {
            arr[i] = r.nextInt(100) + 1;
        }
        //(4)把数组中大于等于10的数字放到一个list集合中,并打印到控制台。
        //定义List集合
        ArrayList<Integer> list = new ArrayList<>();
        //遍历arr数组,将>=10的元素存入到list集合中
        for (Integer thisNum : arr) {
            if (thisNum >= 10) {
                list.add(thisNum);
            }
        }
        System.out.println("产生的随机数是:" + list);
    }
}

一、编写一个泛型方法,实现任意引用类型数组指定位置元素交换。

public class Demo09 {
    public static void main(String[] args) {
        Integer[] a = {1,2,3,4,5,6};
        method(a,0,1);
    }
    //编写泛型方法
    public static <E> void method( E[] e,int a,int b){
        //元素互换
        E temp = e[a];
        e[a] = e[b];
        e[b] = temp;
        for (int i = 0; i < e.length; i++) {
            System.out.println(e[i]);
        }
    }
}

 

一、编写一个泛型方法,接收一个任意引用类型的数组,并反转数组中的所有元素

public class Demo13 {
    public static void main(String[] args) {
        Integer[] a = {1,2,3,4,5,6};
        method(a);
    }
    //编写泛型方法
    public static <E> void method( E[] e){
        //元素反转
        for (int min = 0,max = e.length - 1; min < max; min++,max--) {
            E temp = e[min];
            e[min] = e[max];
            e[max] = temp;
        }
        for (int i = 0; i < e.length; i++) {
            System.out.println(e[i]);
        }
    }
}

一、请简述List接口的特点。

v  它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。

v  它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。

v  集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

一、请简述HashSet去除重复元素的原理。

v  调用被添加元素的hashCode(),和HashSet中已有元素的hashCode比较是否相同

v  如果不相同,直接存储

v  如果相同,调用equals方法比较是否相同

v  不相同,直接存储元素

v  相同,认为是同一元素.不存储

一、简述常见的数据结构中元素的存取特点。

v  栈:stack,又称堆栈,对元素的存取特点是:先进后出。即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素。

v  队列:queue,简称队,对元素的存取特点是:先进先出。即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素。

v  数组:Array,是有序的元素序列,对元素的存取特点是:

1、查找元素快:通过索引,可以快速访问指定位置的元素

2、增删元素慢

(1)指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索                    引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。

(2)指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复                 制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。

v  链表:linked list,对元素的存取有如下的特点:

1、多个结点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的             右手拉住下个人的左手,依次类推,这样多个人就连在一起了。

2、查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素。

3、增删元素快:

增加元素:只需要修改连接下个元素的地址即可。

删除元素:只需要修改连接下个元素的地址即可。

一、简述Comparable和Comparator两个接口的区别。

v  Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

v  Comparator强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。

一、根据要求练习LinkedList方法:

(1)基本方法:add, set, get, remove, clear, size等方法;

(2)特有方法:addFirst, addLast, getFirst, getLast, removeFirst, removeLast, push, pop, clear等方法。

(1)基本方法:

public class LinkedListTest01 {
    public static void main(String[] args) {
        // 1.创建LinkedList
        LinkedList<String> arr = new LinkedList<String>();

        // 2.使用add方法添加元素
        arr.add("西门吹雪");
        arr.add("西门吹雪");
        arr.add("西门吹雪");
        arr.add("西门吹风");
        arr.add("西门吹水");

        // 3.使用add方法在指定索引添加元素
        arr.add(2, "西门吹雨");

        // 4.使用set方法修改指定位置索引
        arr.set(0, "东门");

        for (String str : arr) {
            System.out.println(str);
        }
        System.out.println("--------------");
        // 5.使用get方法获取指定索引的元素
        System.out.println(arr.get(1));

        // 6.使用size方法获取集合大小
        System.out.println(arr.size());

        // 7.使用remove方法删除指定索引的元素
        arr.remove(3);

        // 8.使用clear清空集合中的元素
        arr.clear();
        System.out.println(arr);
    }
}

(2)特有方法

public class LinkedListTest02 {
    public static void main(String[] args) {
        // 1.创建LinkedList
        LinkedList<String> linked = new LinkedList<String>();

        // 2.使用add方法添加元素
        linked.add("周杰伦");
        linked.add("周星驰");
        linked.add("周华健");
        linked.add("周润发");

        // 3.使用addFirst添加元素到集合最前面
        linked.addFirst("周传雄");

        // 4.使用addLast添加元素到集合最后面
        linked.addLast("周渝民");

        System.out.println(linked);

        // 5.使用getFirst获取集合第一个元素
        System.out.println(linked.getFirst());

        // 6.使用getLast获取集合最后一个元素
        System.out.println(linked.getLast());

        // 7.使用removeLast删除集合第一个元素
        String first = linked.removeFirst();
        System.out.println(first);

        // 8.使用removeLast删除集合最后一个元素
        String last = linked.removeLast();
        System.out.println(last);
        System.out.println(linked);


        // 9.使用pop弹出第一个元素
        String p = linked.pop();
        System.out.println(p);

        // 10.使用push在集合开头插入元素
        linked.push("周立波");
        System.out.println(linked);

        // 11.使用clear清空集合
        linked.clear();
        System.out.println(linked);
    }
}

一、定义人类,包含姓名和年龄属性。创建4个人存储到HashSet中,姓名和年龄相同的人看做同一人不存储。

Person类:

// 1.定义Person类.包好姓名年龄属性,重写hashCode()和equals()方法
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name=\'" + name + \'\\'\' +
                ", age=" + age +
                \'}\';
    }
}

测试类

public class HashSetTest01 {
    public static void main(String[] args) {
        // 2.创建HashSet用于存储Person类型
        HashSet<Person> hashSet = new HashSet<Person>();

        // 3.添加多个Person到HashSet中
        hashSet.add(new Person("王昭君", 21));
        hashSet.add(new Person("西施", 21));
        hashSet.add(new Person("杨玉环", 20));
        hashSet.add(new Person("貂蝉", 19));
        hashSet.add(new Person("杨玉环", 20));
        hashSet.add(new Person("貂蝉", 19));

        // 4.遍历获取HashSet中的内容
        for (Person p : hashSet) {
            System.out.println(p);
        }
    }
}

一、向list集合添加姓名{张三,李四,王五,二丫,钱六,孙七},将二丫替换为王小丫。

public class ListTest01 {
    public static void main(String[] args) {
        //1.创建List集合对象
        List<String> list = new ArrayList<>();
        //2.存入数据
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("二丫");
        list.add("钱六");
        list.add("孙七");
        //3.遍历集合,找到"二丫",便将其替换为"王小丫"
        //利用普通for循环遍历List集合
        for(int i = 0;i<list.size();i++) {
            //获取当前元素
            String thisName = list.get(i);
            //如果当前元素是"二丫"
            if("二丫".equals(thisName)) {
                //将其改为"王小丫"
                list.set(i, "王小丫");
            }
        }
        System.out.println(list);
    }
}

一、使用LinkedHashSet存储以下元素:"王昭君","王昭君","西施","杨玉环","貂蝉"。使用迭代器和增强for循环遍历LinkedHashSet。

public class LinkedHashSetTest01 {
    public static void main(String[] args) {
        // 1.创建LinkedHashSet
        LinkedHashSet<String> lhSet = new LinkedHashSet<String>();

        // 2.使用add方法添加元素到LinkedHashSet
        lhSet.add("王昭君");
        lhSet.add("王昭君");
        lhSet.add("王昭君");
        lhSet.add("西施");
        lhSet.add("杨玉环");
        lhSet.add("貂蝉");

        // 3.使用迭代器获取LinkedHashSet中的元素
        Iterator<String> iterator = lhSet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        // 4.使用增强for获取LinkedHashSet中的元素
        System.out.println("---------------------");
        for (String string : lhSet) {
            System.out.println(string);
        }
    }
}

一、ArrayList集合中有如下内容: {33,11,77,55},使用Collections.sort()对ArrayList集合中的数据进行排序,并打印出排序后的结果。

public class CollectionsTest01 {
    public static void main(String[] args) {
        // 1.创建ArrayList
        ArrayList<Integer> arr = new ArrayList<Integer>();

        // 2.使用add方法添加{33,11,77,55}四个元素
        arr.add(33);
        arr.add(11);
        arr.add(77);
        arr.add(55);

        // 3.调用Collections的sort方法,对集合排序
        Collections.sort(arr);

        // 4.使用增强for遍历ArrayList集合
        for (Integer integer : arr) {
            System.out.println(integer);
        }
    }
}

一、已知数组存放一批QQ号码,QQ号码最长为11位,最短为5位String[] strs = {"12345","67891","12347809933","98765432102","67891","12347809933"}。

将该数组里面的所有qq号都存放在LinkedList中,将list中重复元素删除,将list中所有元素分别用迭代器和增强for循环打印出来。

public class LinkedListTest03 {
    public static void main(String[] args) {
        // 1.定义QQ号码数组String[] strs = {"12345","67891",1"2347809933","98765432102","67891","12347809933"}
        String[] strs = { "12345", "67891", "2347809933", "98765432102", "67891", "12347809933" };

        // 2.创建LinkedList
        LinkedList<String> qqList = new LinkedList<>();

        // 3.遍历strs获取每个qq号码
        for (String qq : strs) {
            // 4.判断LinkedList是否已经存在这个qq号码
            if (!qqList.contains(qq)) {
                // 5.不存在这个qq号码则添加到LinkedList中
                qqList.add(qq);
            }
        }

        // 6.增强for遍历
        for (String qq : qqList) {
            System.out.println(qq);
        }
        System.out.println("------------------");

        // 7.迭代器遍历
        Iterator<String> iterator = qqList.iterator();
        while (iterator.hasNext()) {
            String string = iterator.next();
            System.out.println(string);
        }
    }
}

一、键盘录入一个字符串,去掉其中重复字符,打印出不同的那些字符,必须保证顺序。例如输入:aaaabbbcccddd,打印结果为:abcd。

public class LinkedHashSetTest02 {
    public static void main(String[] args) {
        // 1.创建Scanner对象,用于键盘录入
        Scanner sc = new Scanner(System.in);

        System.out.println("请输入一个字符串");

        // 2.调用Scanner的nextLine()方法,让用户输入一个字符串
        String line = sc.nextLine();

        // 3.创建LinkedHashSet.用于去除重复的字符串,并保证迭代顺序
        LinkedHashSet<Character> chs = new LinkedHashSet<>();

        // 4.将字符串串转成char[]
        char[] charArray = line.toCharArray();

        // 5.使用增强for循环遍历每个字符
        for (char c : charArray) {
            // 6.将每个字符添加到LinkedHashSet中
            chs.add(c);
        }

        // 7.使用增强for打印LinkedHashSet中的内容
        for (char c : chs) {
            System.out.print(c);
        }
    }
}

一、双色球规则:双色球每注投注号码由6个红色球号码和1个蓝色球号码组成。红色球号码从1—33中选择;蓝色球号码从1—16中选择;请随机生成一注双色球号码。(要求同色号码不重复)

public class HashSetTest02 {
    public static void main(String[] args) {
        // 1.创建Random随机数对象
        Random ran = new Random();

        // 2.创建HashSet用于保存不重复的红球
        HashSet<Integer> hs = new HashSet<>();

        // 3.循环判断红球数量是否小于6个
        while (hs.size() < 6) {
            // 4.球数量小于6个就产生一个红球.添加到HashSet中
            // 5.如果产生重复号码,往HashSet里添加不进去,所以会再次生成号码
            int num = ran.nextInt(33) + 1;
            hs.add(num);
        }

        // 6.再生成一个篮球
        int blueBall = ran.nextInt(16) + 1;

        // 7.打印中奖号码
        System.out.println("双色球中奖号码:");
        System.out.print("红球是: ");

        for (Integer redBall : hs) {
            System.out.print(redBall + " ");
        }
        System.out.println();
        System.out.println("蓝球是: " + blueBall);
    }
}

一、分别用ComparableComparator两个接口对下列四位同学的成绩做降序排序如果成绩一样那在成绩排序的基础上按照年龄由小到大排序。

姓名(String

年龄(int

分数(float

liusan

20

90.0F

lisi

22

90.0F

wangwu

20

99.0F

sunliu

22

100.0F

(1)Comparable

 

Student

public class Student implements Comparable<Student>{
    private String name;
    private int age;
    private float score;

    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String toString() {
        return name+"\t\t"+age+"\t\t"+score;
    }

    @Override
    public int compareTo(Student o) {
        if(this.score>o.score){
            //由高到底排序
            return -1;
        }else if(this.score<o.score) {
            return 1;
        }else{
            if(this.age>o.age) {
                //由底到高排序
                return 1;
            }else if(this.age<o.age) {
                return -1;
            }else {
                return 0;
            }
        }
    }
}

测试类

public class ComparableTest {
    public static void main(String[] args) {
        Student stu[]={new Student("liusan",20,90.0f),
                new Student("lisi",22,90.0f),
                new Student("wangwu",20,99.0f),
                new Student("sunliu",22,100.0f)};
        java.util.Arrays.sort(stu);
        for(Student s:stu){
            System.out.println(s);
        }
    }
}

(1)Comparator

 

Student

public class Student {
    private String name;
    private int age;
    private float score;

    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    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 float getScore() {
        return score;
    }
    public void setScore(float score) {
        this.score = score;
    }

    public String toString() {
        return name+"\t\t"+age+"\t\t"+score;
    }
}

Comparator比较器

public class StudentComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        if(o1.getScore()>o2.getScore()) {
            return -1;
        }else if(o1.getScore()<o2.getScore()) {
            return 1;
        }else{
            if(o1.getAge() > o2.getAge()) {
                return 1;
            }else if(o1.getAge() < o2.getAge()) {
                return -1;
            }else{
                return 0;
            }
        }
    }
}

测试类

public class ComparatorTest {
    public static void main(String[] args) {
        Student stu[]={new Student("liusan",20,90.0f),
                new Student("lisi",22,90.0f),
                new Student("wangwu",20,99.0f),
                new Student("sunliu",22,100.0f)};
        java.util.Arrays.sort(stu,new StudentComparator());
        for(Student s:stu) {
            System.out.println(s);
        }
    }
}

 

一、请简述Map 的特点。

v  Map每个元素由键与值两部分组成

v  Map键不能重复,每个键对应一个值

v  键和值可以为null

一、说出Entry键值对对象遍历Map集合的原理。

 

Map中存放的是两种对象,一种称为key(),一种称为value(),它们在在Map中是一一对应关系,这一对对象又称做Map 中的一个Entry()Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。

 

一、请使用Map集合的方法完成添加元素,根据键删除,以及根据键获取值操作。

public class MapTest01{
public static void main(String[] args) {
// 1.创建HashMap
HashMap<String, String> hm = new HashMap<String, String>();

// 2.使用put添加元素
hm.put("黄晓明", "Baby");
        hm.put("邓超", "孙俪");
        hm.put("李晨", "范冰冰");
        hm.put("大黑牛", "范冰冰");

// 3.使用put修改元素
String v1 = hm.put("李晨", "白百合");

// 4.使用get获取元素
String string = hm.get("大黑牛");

// 5.使用remove删除元素
String v2 = hm.remove("大黑牛");
        System.out.println(v2);

// 6.打印集合中的元素
System.out.println(hm);
    }
}

一、往一个Map集合中添加若干元素。获取Map中的所有value,并使用增强for和迭代器遍历输出每个value

public class MapTest02 {
public static void main(String[] args) {
// 1.创建HashMap
HashMap<String, String> hm = new HashMap<String, String>();

// 2.使用put添加元素
hm.put("黄晓明", "Baby");
        hm.put("邓超", "孙俪");
        hm.put("李晨", "范冰冰");
        hm.put("大黑牛", "范冰冰");

// 3.使用Map的values方法获取到所有的value
Collection<String> values = hm.values();

// 4.使用增强for获取每个value
for (String value : values) {
            System.out.println(value);
        }

        System.out.println("----------------");
// 5.使用迭代器获取每个value
Iterator<String> itr = values.iterator();
while (itr.hasNext()) {
            System.out.println(itr.next());
        }
    }
}

一、请使用Map集合存储自定义数据类型Car做键,对应的价格做值。并使用keySetentrySet两种方式遍历Map集合。

汽车类:
// 1.定义汽车类.包含名称和价格属性,重写hashCode和equals方法
public class Car {

private String name;

private String color;

public Car() {
    }

public Car(String name, String color) {
this.name = name;
this.color = color;
    }

public String getName() {
return name;
    }

public void setName(String name) {
this.name = name;
    }

public String getColor() {
return color;
    }

public void setColor(String color) {
this.color = color;
    }

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Car)) return false;

        Car car = (Car) o;

if (name != null ? !name.equals(car.name) : car.name != null) return false;
return color != null ? color.equals(car.color) : car.color == null;
    }

@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (color != null ? color.hashCode() : 0);
return result;
    }
}
测试类:
public class MapTest03 {
public static void main(String[] args) {
// 2.创建HashMapkey保存汽车对象,value是汽车价格
HashMap<Car, Integer> hm = new HashMap<>();

// 3.添加汽车到HashMap中
Car c1 = new Car("长安奔奔", "黄色");
        Car c3 = new Car("奇瑞QQ", "黑色");
        Car c2 = new Car("铃木奥拓", "白色");

        hm.put(c1, 10000);
        hm.put(c2, 20000);
        hm.put(c3, 30000);

// 4.使用keySet方式遍历Map
Set<Car> keySet = hm.keySet();
for (Car c : keySet) {
// 根据key获取value
Integer value = hm.get(c);
            System.out.println(c.getName() + ","+ c.getPrice() + " - "+ value);
        }

        System.out.println("-------------");

// 5.使用entrySet方式遍历Map
Set<Map.Entry<Car, Integer>> entrySet = hm.entrySet();
for (Map.Entry<Car, Integer> entry : entrySet) {
            Car key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key.getName() + ","+ key.getPrice() + " - "+ value);
        }
    }
}

一、现在有一个map集合如下:

Map<Integer,String> map = new HashMap<Integer, String>();
        map.put(1, "
张三丰");
        map.put(2, "
周芷若");
        map.put(3, "
汪峰");
        map.put(4, "
灭绝师太");

要求:

1.遍历集合,并将序号与对应人名打印。

2.向该map集合中插入一个编码为5姓名为李晓红的信息

       3.移除该map中的编号为1的信息

 

       4.map集合中编号为2的姓名信息修改为"周林"

public class MapTest04 {
public static void main(String[] args) {
// 1.定义HashMap,编号作为key,姓名作为value
Map<Integer,String> map = new HashMap<Integer, String>();

// 2.使用put方法添加元素
map.put(1, "张三丰");
        map.put(2, "周芷若");
        map.put(3, "汪峰");
        map.put(4, "灭绝师太");

// 3.使用keySet+增强for迭代map中的元素,并打印
Set<Integer> keySet = map.keySet();
for (Integer key : keySet) {
            String value = map.get(key);
            System.out.println(key + " -- "+ value);
        }

// 4.使用put向该map集合中插入一个编码为5姓名为李晓红的信息
map.put(5, "李晓红");

// 5.使用remove移除该map中的编号为1的信息
map.remove(1);

// 6.使用put将map集合中编号为2的姓名信息修改为"周林"
map.put(2, "周林");
        System.out.println(map);
    }
}

一、2个数组,第一个数组内容为:[黑龙江省,浙江省,江西省,广东省,福建省],第二个数组为:[哈尔滨,杭州,南昌,广州,福州],将第一个数组元素作为key,第二个数组元素作为value存储到Map集合中。如{黑龙江省=哈尔滨, 浙江省=杭州, …}

public class MapTest05 {
public static void main(String[] args) {
// 1.定义第一个数组arr1
String[] arr1 = {"黑龙江省", "浙江省", "江西省", "广东省", "福建省"};
// 2.定义第二个数组arr2
String[] arr2 = {"哈尔滨", "杭州", "南昌", "广州", "福州"};

// 3.创建HashMap,key存放省,value存放市
HashMap<String, String> hm = new HashMap<>();

// 4.使用普通for循环遍历arr1
for (int i = 0; i < arr1.length; i++) {
// 5.根据索引到arr1中获取到省
String key = arr1[i];
// 6.根据索引到arr2中获取到省会城市
String value = arr2[i];

// 7.将省和省会城市添加到HashMap中
hm.put(key, value);
        }
// 8.输出HashMap中的内容
System.out.println(hm);
    }
}

一、定义一个泛型为String类型的List集合,统计该集合中每个字符(注意,不是字符串)出现的次数。例如:集合中有”abc””bcd”两个元素,程序最终输出结果为:“a = 1,b = 2,c = 2,d = 1”

public class MapTest06 {
public static void main(String[] args) {
// 1.定义ArrayList存放元素
ArrayList<String> arr = new ArrayList<String>();

// 2.使用add方法添加需要的元素
arr.add("abc");
        arr.add("bcd");

// 3.定义HashMap,key是字符,value是字符对应的次数
HashMap<Character, Integer> hm = new HashMap<>();

// 4.使用增强for获取ArrayList中的每个字符串
for (String str : arr) {

// 5.将每个字符串转成字符数组
char[] charArray = str.toCharArray();

// 6.使用增强for遍历字符数组
for (char ch : charArray) {
// 7.获取拿到每个字符,使用字符去HashMap中查找次数
Integer num = hm.get(ch);
// 8.如果为空,说明该字符第一次出现
if (num == null) {
// 9.放入字符作为key,把次数设置为1
hm.put(ch, 1);
                } else {
// 10.如果之前,已经有字符了,就把字符的次数+1
hm.put(ch, num + 1);
                }
            }
        }
// 11.输出map中的内容
System.out.println(hm);
    }
}

一、利用Map,完成下面的功能:

从命令行读入一个字符串,表示一个年份,输出该年的世界杯冠军是哪支球队。如果该 年没有举办世界杯,则输出:没有举办世界杯。

//tips:参阅Map接口containsKey(Object key)方法 

 

二、在原有世界杯Map 的基础上,增加如下功能: 读入一支球队的名字,输出该球队夺冠的年份列表。 例如,读入巴西,应当输出 1958 1962 1970 1994 2002 读入荷兰,应当输出 没有获得过世界杯 

//tips:参阅Map接口containsValue(Object value)方法

 

附:历届世界杯冠军

 

 

届数    举办年份    举办地点    冠军
第一届
1930年    乌拉圭    乌拉圭
第二届    1934年    意大利    意大利
第三届    1938年    法国    意大利
第四届    1950年    巴西    乌拉圭
第五届    1954年    瑞士    西德
第六届    1958年    瑞典    巴西
第七届    1962年    智利    巴西
第八届    1966年    英格兰    英格兰
第九届    1970年    墨西哥    巴西
第十届    1974年    前西德    西德
第十一届    1978年    阿根廷    阿根廷
第十二届    1982年    西班牙    意大利
第十三届    1986年    墨西哥    阿根廷
第十四届    1990年    意大利    西德
第十五届    1994年    美国    巴西
第十六届    1998年    法国    法国
第十七届    2002年    韩日    巴西
第十八届    2006年    德国    意大利
第十九届    2010年    南非    西班牙
第二十届    2014年    巴西    德国
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class MapTest09 {

    public static void main(String[] args) {

        Map<Integer, String> m = new HashMap<>();

        m.put(1930, "乌拉圭");
        m.put(1934, "意大利");
        m.put(1938, "意大利");
        m.put(1950, "乌拉圭");
        m.put(1954, "西德");
        m.put(1958, "巴西");
        m.put(1962, "巴西");
        m.put(1966, "英格兰");
        m.put(1970, "巴西");
        m.put(1974, "西德");
        m.put(1978, "阿根廷");
        m.put(1982, "意大利");
        m.put(1986, "阿根廷");
        m.put(1990, "西德");
        m.put(1994, "巴西");
        m.put(1998, "法国");
        m.put(2002, "巴西");
        m.put(2006, "意大利");
        m.put(2010, "西班牙");
        m.put(2014, "德国");

        System.out.println("请输入一个年份");
        Scanner s = new Scanner(System.in);
        int key = s.nextInt();

        if (m.containsKey(key)) {
            System.out.println(key + "年,获得世界杯冠军的是:" + m.get(key));
        } else {
            System.out.println("该年没有举办世界杯!");
        }

        System.out.println("请输入一个国家名称");
        Scanner g = new Scanner(System.in);
        String val = g.nextLine();

        if (m.containsValue(val)) {
            for (Integer year : m.keySet()) {
                if (m.get(year).equals(val)) {
                    System.out.println(year + "、\n");
                }
            }
        } else {
            System.out.println("该国家没有获得世界杯冠军");
        }

    }

}

 

 

一、问题:

  1. 请描述异常的继承体系
  2. 请描述你对错误(Error)的理解
  3. 请描述你对异常(Expection的理解)
  4. 请描述你对运行时异常(RuntimeException)的理解

 

答:

 
1.   异常继承体系为:异常的根类是 java.lang.Throwable,其下有两个子类:
java.lang.Error 与 java.util.Exception 。而Exception又分为编译时期异常:checked异常,与运行时期异常:runtime异常。 
  1. Error:表示不可修复的恶性的错误,只能通过修改代码规避错误的产生,通常是系统级别的,所以很严重。
  2. Exception:表示可修复的良性(相对于错误)的异常,异常产生后程序员可以并且应该通过代码的方式纠正,使程序继续运行,是必须要处理的。
  3. 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。

 

问题:

1. 请描述throw的使用位置,作用是什么?

2. 请描述throws的使用位置,作用是什么?

 

答:

  1. throw关键字通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行。
  2. throws关键字通常被应用在声明方法时,用来指定可能抛出的异常。多个异常可以使用逗号隔开。当在主函数中调用该方法时,如果发生异常,就会将异常对象抛给方法调用处。

问题:

      1. 异常处理方式有几种,分别是什么?

      2. 详细阐述每种方式对异常是如何处理的

答:

  1. 异常的处理方式有两种,分别是使用throws和try...catch...finally
  2. throws用在方法的声明上后接异常类名,是把异常抛给调用者进行处理
  3. try...catch...finally是捕获异常,自己处理,处理完毕后面的程序可以继续运行

a)       try代码块中是可能出现异常的代码

b)       catch代码块,是遇到异常,对异常进行处理的代码

c)        finally代码块是无论是否发生异常,都必须执行的代码,用于释放资源.

 

问题:请列举常见异常,并说明产生原因。

 

答:

NullPointerException:空指针异常。

         当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度等等。

ArrayIndexOutOfBoundsException:数组索引越界异常。

当对数组的索引值为负数或大于等于数组大小时抛出此异常。

ArithmeticException:算术运算异常。

         程序中出现了除以零这样的运算就会出这样的异常,对这种异常,大家就要好好检查一下自己程序中涉及到数学运算的地方,公式是不是有不妥了。

NumberFormatException:数字格式异常。

         当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。

 

注意:答案不唯一,合理即可。

问题:根据给出的相应代码,分析可能产生的结果。

1.举例:
public static void main(String[]args){

 String str=null;
System.out.println(str.length());

}

答:变量str的值为null,调用方法时,报空指针异常NullPointerException



2.举例:
public static void main(String[]args){
int arr[]={1,2};
System.out.println(arr[2]);
}

答:索引值2大于等于数组arr的长度时,报数组索引越界异常ArrayIndexOutOfBoundsException



3.举例:
public static void main(String[]args){

System.out.println(1/0);
}

答:整数0做了分母,报算术运算异常ArithmeticException:/by zero



4.举例:
public static void main(String[]args){

System.out.println(Integer.parseInt("itcast"));

}

答:
把字符串“itcast”转换为Integer类型时,当然会报数字格式化异常啦NumberFormatException


5.举例:
public static void main(String[] args) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
    
    try {
        Date date = format.parse("2018-04-03");
        System.out.println("程序正常");
        
    } catch (ParseException e) {
        System.out.println("程序异常");
    }
}


答:
    打印结果“程序正常”.try代码块中并没有产生异常,catch代码块中的代码不会执行。date为2018年1月3日00点04分00秒。

问题:请简单描述什么是并行,什么是并发?

答:

并行:指两个或多个事件在同一时刻发生(同时发生)。

并发:指两个或多个事件在同一个时间段内发生。

通俗易懂版:

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不    支持并行。
    你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
    你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

并发的关键是你有处理多个任务的能力,不一定要同时。
    并行的关键是你有同时处理多个任务的能力。

所以它们最关键的点就是:是否是『同时』。

问题:请描述什么是进程,什么是线程,进程与线程之间的关系,并举例说明。

答:

进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。

线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

一个程序运行后至少有一个进程,一个进程中可以包含多个线程,但一个进程中至少包含一个线程。比如使用迅雷软件下载网络文件时,同时下载多个文件,就使用到了多线程下载。

问题:

请使用代码实现

每一个学生(Student)都有学号,姓名和分数,分数永远不能为负数

如果老师给学生赋值一个负数,抛出一个自定异常

答:

/*
 1.
定义异常类NoScoreException,继承RuntimeException
a)
提供空参和有参构造方法
 */

public
class NoScoreException extends RuntimeException { // 空参构造 public NoScoreException() { super(); } // 有参构造 public NoScoreException(String message) { super(message); } }
/*
  2.
定义学生类(Student)
 a)
属性:name,score
 b)
提供空参构造
 c)
提供有参构造;
  i.
使用setXxx方法给名称和score赋值
 d)
提供settergetter方法
  i.
setScore(int score)方法中
   1.
首先判断,如果score为负数,就抛出NoScoreException,异常信息为:分数不能为负数:xxx.
   2.
然后在给成员score赋值.
 */

public
class Student { private String name; private int score; // 空参构造 public Student() { super(); } // c)提供有参构造; // i.使用setXxx方法给名称和score赋值 public Student(String name,int score){ setName(name); setScore(score); } // d)提供setter和getter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getScore() { return score; } // i.在setScore(int score)方法中 public void setScore(int score) { // 1.首先判断,如果score为负数,就抛出NoScoreException,异常信息为:分数不能为负数:xxx. if(score <0){ throw new NoScoreException(":分数不能为负数:"+score); } // 2.然后在给成员score赋值. this.score = score; } }
/*
3.定义测试类Test9
 a)提供main方法,在main方法中
  i.使用满参构造方法创建Student对象,分数传入一个负数,运行程序
  ii.由于一旦遇到异常,后面的代码的将不在执行,所以需要注释掉上面的代码
  iii.使用空参构造创建Student对象
  iv.调用setScore(int score)方法,传入一个正数,运行程序
  v.调用setScore(int score)方法,传入一个负数,运行程序
 */

public class Test9 {
public static void main(String[] args) {
//  i.使用满参构造方法创建Student对象,分数传入一个负数,运行程序
//  Student s = new Student("景甜", -10);
//  ii.由于一旦遇到异常,后面的代码的将不在执行,所以需要注释掉上面的代码

//  iii.使用空参构造创建Student对象
Student s = new Student();
//  iv.调用setScore(int score)方法,传入一个正数,运行程序
s.setScore(100);
//  v.调用setScore(int score)方法,传入一个负数,运行程序
s.setScore(-5);
 }
}

问题:

创建多线程对象,开启多线程。在子线程中输出1-100之间的偶数,主线程输出1-100之间的奇数。

 

答:

自定义线程类

public class MyThread extends Thread {

/**
  * 重写run方法,完成该线程执行的逻辑
*/
@Override
public void run() {
    for (int i = 1; i <= 100; i++) {
        if (i % 2 == 0) {
            System.out.println("子线程打印输出偶数:" + i);
        }
    }
}


}

测试类

public class Test11 {
public static void main(String[] args) {
//创建自定义线程对象
MyThread mt = new MyThread();
//开启线程
mt.start();
//在主方法中执行for循环
for (int i = 1; i <= 100; i++) {
    if (i % 2 == 1) {
        System.out.println("主线程打印输出奇数:" + i);
    }
}

 }
}

问题:

请用代码描述:

在一款角色扮演游戏中,每一个人都会有名字和生命值;角色的生命值不能为负数

要求:当一个人物的生命值为负数的时候需要抛出自定的异常

 

 

答:

操作步骤描述

1. 创建包com.itheima.level2

2. 自定义异常类NoLifeValueExption继承RuntimeException

a)       提供空参和有参构造

b)       在有参构造中,需要调用父类的有参构造,把异常信息传入

3. 定义Person类

a)       属性:名称(name)和生命值(lifeValue)

a)       提供空参构造

b)       提供有参构造;

  1. 使用setXxx方法给name和lifeValue赋值

c)        提供setter和getter方法

  1. 在setLifeValue(int lifeValue)方法中
    1. 首先判断,如果 lifeValue为负数,就抛出NoLifeValueException,异常信息为:生命值不能为负数:xxx.
    2. 然后在给成员lifeValue赋值.

3. 定义测试类Test10

d)       提供main方法,在main方法中

  1. 使用满参构造方法创建Person对象,分数传入一个负数,运行程序
  2. 由于一旦遇到异常,后面的代码的将不在执行,所以需要注释掉上面的代码
  3. 使用空参构造创建Person对象
  4. 调用setLifeValue(int lifeValue)方法,传入一个正数,运行程序
  5. 调用setLifeValue(int lifeValue)方法,传入一个负数,运行程序

操作步骤答案

/*
  1.自定义异常类NoLifeValueExption继承RuntimeException
 a)提供空参和有参构造
 b)在有参构造中,需要调用父类的有参构造,把异常信息传入
 */

public class NoLifeValueExption extends RuntimeException {
public NoLifeValueExption() {
super();
 }

public NoLifeValueExption(String message) {
super(message);
 }
}


/*
 2.定义Person类
 a)属性:名称(name)和生命值(lifeValue)
  b)提供空参构造
  c)提供有参构造;
   i.使用setXxx方法给name和lifeValue赋值
 d)提供setter和getter方法
  i.在setLifeValue(int lifeValue)方法中
   1.首先判断,如果 lifeValue为负数,就抛出NoLifeValueException,异常信息为:生命值不能为负数:xxx.
   2.然后在给成员lifeValue赋值.
 */

public class Person {
// 名称(name)
private String name;
// 生命值(lifeValue)
private int lifeValue;

// 空参构造
public Person() {
super();
 }

// c)提供有参构造;
public Person(String name, int lifeValue) {
super();
// i.使用setXxx方法给name和lifeValue赋值
setName(name);
  setLifeValue(lifeValue);
 }

//d)提供setter和getter方法
public String getName() {
return name;
 }

public void setName(String name) {
this.name = name;
 }

public int getLifeValue() {
return lifeValue;
 }

// i.在setLifeValue(int lifeValue)方法中
public void setLifeValue(int lifeValue) {
// 1.首先判断,如果 lifeValue为负数,就抛出NoLifeValueException,异常信息为:生命值不能为负数:xxx.
if (lifeValue <0) {
throw new NoLifeValueExption("生命值不能为负数:" + lifeValue);
  }
// 2.然后在给成员lifeValue赋值.
this.lifeValue = lifeValue;
 }
}


/*
3.定义测试类Test10
 a)提供main方法,在main方法中
  i.使用满参构造方法创建Person对象,分数传入一个负数,运行程序
  ii.由于一旦遇到异常,后面的代码的将不在执行,所以需要注释掉上面的代码
  iii.使用空参构造创建Person对象
  iv.调用setLifeValue(int lifeValue)方法,传入一个正数,运行程序
  v.调用setLifeValue(int lifeValue)方法,传入一个负数,运行程序
 */

public class Test10 {
public static void main(String[] args) {
//  i.使用满参构造方法创建Person对象,分数传入一个负数,运行程序
//  Person p = new Person("林思意", -100);
//  ii.由于一旦遇到异常,后面的代码的将不在执行,所以需要注释掉上面的代码
//  iii.使用空参构造创建Person对象
Person p = new Person();
//  iv.调用setLifeValue(int lifeValue)方法,传入一个正数,运行程序
p.setLifeValue(1000);
//  v.调用setLifeValue(int lifeValue)方法,传入一个负数,运行程序
p.setLifeValue(-100);
 }
}

问题:

创建三个子线程,在每个线程中开启10万次的循环,线程1循环中将循环自增变量i赋值给Integer类型变量 a,线程2循环中将字符串"黑马程序员"赋值给String类型变量b,线程3循环中将字符串"黑马程序员"和循环自增变量i拼接后赋值给String类型变量c

分别计算三个线程完成任务所用的毫秒值

答:

线程1
public class Thread1 extends Thread{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            Integer a = i;
        }
        long end = System.currentTimeMillis();
        System.out.println("线程1执行时间:"+(end-start));
    }
}


线程2
public class Thread2 extends Thread{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            String b = "黑马程序员";
        }
        long end = System.currentTimeMillis();
        System.out.println("线程2执行时间:"+(end-start));
    }
}

线程3
public class Thread3 extends Thread{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            String c = "黑马程序员"+i;
        }
        long end = System.currentTimeMillis();
        System.out.println("========线程3执行时间:"+(end-start));
    }
}

测试类
public class TestThread {
    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
        new Thread3().start();
    }
}

问题:

请描述Thread类中的start()方法与run()方法的区别。

答:

线程对象调用run()方法不开启线程,仅是对象调用方法。线程对象调用start()方法开启线程,并让jvm调用run()方法在开启的线程中执行。


问题:


请描述创建线程的两种方式。

答:

第一种方式是将类声明为 Thread 的子类。

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  2. 创建Thread子类的实例,即创建了线程对象。
  3. 调用线程对象的start()方法来启动该线程。

第二种方式是声明一个类实现Runnable 接口。

1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,Thread对象才是真正的线程对象。

3. 调用线程对象的start()方法来启动线程。

问题:

         请编写程序,分别打印主线程的名称和子线程的名称。

         要求使用两种方式实现:

                  第一种方式:继承Thread类。

                  第二种方法:实现Runnable接口。

答:

操作步骤描述


第一种方式:继承Thread

                1.定义一个子线程的类,继承Thread类;

                2.在子线程类中重写run方法,在run方法中打印子线程的名称;

                3.定义一个测试类;

                4.在main方法中打印主线程的名称;

                5.在main方法中创建子线程对象;

                6.调用子线程对象的start方法,开启子线程;

第二种方式:实现Runnable接口

1.定义一个子任务类,实现Runnable接口;

2.在子任务类中重写run方法,在run方法中打印子线程的名称;

3.定义一个测试类;

4.在main方法中打印主线程的名称;

5.在main方法中创建一个子任务对象;

6.在main方法中创建一个Thread类的对象,并把子任务对象传递给Thread类的构造方法;

7.调用Thread类对象的start方法开启子线程;

操作步骤答案

第一种方式:继承Thread

/*
 * 1.定义一个子线程的类,继承Thread类;
 */
public class SubThread extends Thread {
 /*
  *2.在子线程类中重写run方法,在run方法中打印子线程的名称;
  */
 public void run() {
  // 打印子线程的名称
  System.out.println("subThread:" + Thread.currentThread().getName());
 }
}



/*
 * 3.定义一个测试类
 */
public class ThreadDemo {
 public static void main(String[] args) {
  // 4.在main方法中打印主线程的名称;
  System.out.println("main:" + Thread.currentThread().getName());
  // 5.在main方法中创建子线程对象;
  SubThread st = new SubThread();
  // 6.调用子线程对象的start方法,开启子线程。
  st.start();
 }
}

第二种方式:实现Runnable接口


/*
 * 1.定义一个子任务类,实现Runnable接口。
 */
public class SubRunnable implements Runnable {
 @Override
 public void run() {
  // 2.在子任务类中重写run方法,在run方法中打印子线程的名称。
  System.out.println("SubRunnable:"+ Thread.currentThread().getName());
 }
}


/*
 * 3.定义一个测试类。
 */
public class RunnableDemo {
 public static void main(String[] args) {
  // 4.在main方法中打印主线程的名称。
  System.out.println("RunnableDemo:"+ Thread.currentThread().getName());
  // 5.在main方法中创建一个子任务对象。
  SubRunnable r = new SubRunnable();
  // 6.在main方法中创建一个Thread类的对象,并把子任务对象传递给Thread类的                         构造方法。
  Thread t = new Thread(r);
  // 7.调用Thread类对象的start方法开启子线程。
  t.start();
 }
}

问题:

请描述实现Runnable接口比继承Thread类所具有的优势:

答:

1. 适合多个相同的程序代码的线程去共享同一个资源。

2. 可以避免java中的单继承的局限性。

3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立。

4. 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类。


问题:请描述在线程的生命周期中, 有几种状态呢 

答:

  1. NEW(新建) 线程刚被创建,但是并未启动。
  2. Runnable(可运行)

线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。

  1. Blocked(锁阻塞)

当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。

  1. Waiting(无限等待)

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

  1. Timed Waiting(计时等待)

同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。

  1. Teminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

问题:

编写程序,在主线程中,循环输出“主线程执行”;在一条新线程中,循环输出“子线程执行”

答:        

//1.创建一个子线程类

public class Son implements Runnable {

 public void run() {
  while (true) {
   System.out.println("子线程执行....");
  }
 }

}

//2.创建一个测试类

public class Test06 {
 public static void main(String[] args) {
  //创建一个子线程对象
  Thread son = new Thread(new Son());
  son.start();//开启子线程
  while (true) {
   System.out.println("主线程执行");
  }
 }
}

问题:

编写程序,创建两个线程对象,一根线程循环输出“播放背景音乐”,另一根线程循环输出“显示画面”,要求线程实现Runnable接口,且使用匿名内部类实现

答:

  //1.定义一个测试类

public class Test07 {

 public static void main(String[] args) {

  //1.新建第一条线程并开启
  new Thread(new Runnable() {
   @Override
   public void run() {
    while (true) {
     System.out.println("播放背景音乐");
    }
   }
  }).start();


  //2.新建第二条线程并开启
  new Thread(new Runnable() {
   @Override
   public void run() {
    while (true) {
     System.out.println("显示画面");
    }
   }
  }).start();
 }
}

问题:

编写一个Java程序,要求在同一个类中除main线程外,再开启一个线程,2个线程都循环执行20次。

答:

  //1.定义一个测试类

public class Test08 extends Thread {

 int a = 1;

 public static void main(String[] args) {
  Test08 thread = new Test08();
  thread.start();
  for (int i = 1; i <= 20; i++) {
   System.out.println(Thread.currentThread().getName() + "执行第:" + i + "次");
  }
 }

 @Override
 public void run() {
  for (; a <= 20; a++) {
   System.out.println(Thread.currentThread().getName() + "执行第:" + a + "次");
  }
 }
}

问题:

         请按要求编写多线程应用程序,模拟多个人通过一个山洞:

              1.这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒;

2.随机生成10个人,同时准备过此山洞,并且定义一个变量用于记录通过隧道的人数。显示每次通过山洞人的姓名,和通过顺序;

答:

操作步骤描述

         1.定义一个隧道类,实现Runnable接口:

                  1.1 定义一个变量,用来记录通过隧道的人数;

                  1.2 重写Runnable的run方法;

                  1.3 定义一个同步方法,模拟每个人通过隧道需要5秒钟:

                           1.3.1 子线程睡眠5秒钟,模拟每个人通过隧道需要5秒钟;

                           1.3.2 改变通过的人次;

                           1.3.3 打印线程名称及其通过隧道的顺序,模拟人通过隧道及其顺序;

                  1.4 调用通过隧道的方法;

         2.定义一个测试类:

                  2.1 在main方法中创建一个隧道类对象;

                  2.2 在main方法中,循环创建10个子线程对象,通过构造方法把隧道对象

                      和线程名(作为人的姓名)传递进去,并开启子线程;

操作步骤答案

/*
 * 1.定义一个隧道类,实现Runnable接口
 */
public class Tunnel implements Runnable {

 // 1.1 定义一个变量,用来记录通过隧道的人数
 private int crossNum = 0;

 /*
  * 1.2 重写Runnable的run方法
  */
 @Override
 public void run() {
  // 1.4 调用通过隧道的方法
  cross();
 }

 /*
  * 1.3 定义一个同步方法,模拟每个人通过隧道需要5秒钟
  */
 public synchronized void cross() {
  // 1.3.1 子线程睡眠5秒钟,模拟每个人通过隧道需要5秒钟
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  // 1.3.2 改变通过的人次
  crossNum++;
  // 1.3.3 打印线程名称及其通过隧道的顺序,模拟人通过隧道及其顺序
  System.out.println(Thread.currentThread().getName() + "已经通过隧道,TA是第" + crossNum + "通过的!");
 }
}


/*
 * 2.定义一个测试类
 */
public class TunnelDemo {

 public static void main(String[] args) {
  // 2.1 在main方法中创建一个隧道类对象
  Tunnel tul = new Tunnel();

  // 2.2 在main方法中,循环创建10个子线程对象,通过构造方法把隧道对象和// 线程名(作为人的姓名)传递进去,并开启子线程
  for (int i = 1; i <= 10; i++) {
   Thread t = new Thread(tul, "p" + i);
   t.start();
  }
 }
}

 

问题:

请描述什么是线程池。

答:

线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

问题:

请描述合理利用线程池能够带来的三个好处。

答:

1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

问题:

请列举Lambda语法的省略规则

答:

在Lambda标准格式的基础上,使用省略写法的规则为:

  1. 小括号内参数的类型可以省略;
  2. 如果小括号内有且仅有一个参,则小括号可以省略;
  3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。

问题:

                  请列举Lambda表达式的3个组成部分,并解释说明。

 

 

答:

Lambda标准格式 Lambda省去面向对象的条条框框,格式由3个部分组成:一些参数,一个箭头,一段代码。

Lambda表达式的标准格式为:格式说明:

  1. 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
  2. ->是新引入的语法格式,代表指向动作。

大括号内的语法与传统方法体要求基本一致

问题:

请描述Lambda的使用前提

答:

Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:

1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。

2. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

问题:

请在指定位置插入代码实现打印输出1-99。

public class Test06 {
public int start = 1;
public int end = 99;
public static void main (String[] args) {
new Test06().method();
 }
public void method() {
//请在此处插入代码,实现功能
Thread t = new Thread( a );
  t.start();
 }
}
答:
public class Test06 {
public int start = 1;
public int end = 99;

public static void main(String[] args) {
new Test06().method();
 }

public void method() {
//插入代码处
Runnable a = () -> {
  for (int i = start; i <end; i++) {
    System.out.println(i);
  }
 };
  Thread t = new Thread(a);
  t.start();
 }
}

问题:给出以下代码,请问该程序的运行结果是什么?如有问题,请说明原因。

public class Test07implements Runnable {
public static void main(String[] args) {
  Thread t = new Thread(new Test07());
  t.start();
 }

public void run(int num) {
for (int i = 0; i < num; i++) {
   System.out.println(i);
  }
 }
}

答:

在编译时期就会报错

                           Test类没有重写Runnable接口中的run()方法

                           public void run(int num)不是Runnable接口中的run()方法。

注意:Runnable接口中的run()方法,参数列表为空,不带参数。

问题:

使用线程池创建多线程。模拟同学找老师学习Java。

  1. 创建线程池对象,包含2个线程。从线程池中获取线程对象,然后调用MyRunnable中的run()。

在MyRunnable实现类中,首先在控制台打印需求,“我需要一个老师”。模拟需要2秒钟时间老师可以过来指导学生,并在控制台打印老师的姓名。最后,在控制台打印“教我java,教完后,老师回到了办公室”

答:
/*
 *1.Runnable实现类代码:
 */
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyRunnable implements Runnable {
@Override
public void run() {
  System.out.println("我要一个老师");
try {
   Thread.sleep(2000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("老师来了"+Thread.currentThread().getName());
  System.out.println("教我java,教完后,老师回到了办公室");
 }
}


/*
 *2.线程池测试类:
 */
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
// 创建Runnable实例对象
MyRunnable r = new MyRunnable();
//自己创建线程对象的方式
// Thread t = new Thread(r);
// t.start(); ‐‐‐>调用MyRunnable中的run()
// 从线程池中获取线程对象,然后调用MyRunnable中的run()
service.submit(r);
// 再获取个线程对象,调用MyRunnable中的run()
service.submit(r);
  service.submit(r);
// 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
// 将使用完的线程又归还到了线程池中
// 关闭线程池
//service.shutdown();

}
}
问题:
    给定一个导演 Director接口,内含唯一的抽象方法makeMovie,且无参数、无返回值,使用lambda表达式在Test中完成调用。
public interface Director {
void makeMovie();
}

    在下面的代码中,请使用Lambda的省略格式调用 invokeDirect 方法,打印输出“导演拍电影啦!”字样:
public class Test09InvokeDirect {
public static void main(String[] args) {
// TODO 请使用Lambda【省略格式】调用invokeDirect方法


 }

private static void invokeDirect(Director director) {
  director.makeMovie();
 }
}
问题:
    给定一个导演 Director接口,内含唯一的抽象方法makeMovie,且无参数、无返回值,使用lambda表达式在Test中完成调用。
public interface Director {
void makeMovie();
}

    在下面的代码中,请使用Lambda的省略格式调用 invokeDirect 方法,打印输出“导演拍电影啦!”字样:
public class Test09InvokeDirect {
public static void main(String[] args) {
// TODO 请使用Lambda【省略格式】调用invokeDirect方法


 }

private static void invokeDirect(Director director) {
  director.makeMovie();
 }
}
问题:
给定一个计算器 Calculator 接口,内含抽象方法 calc (减法),其功能是可以将两个数字进行相减,并返回差值。使用Lambda表达式在Test中完成调用。
public interface Calculator {
int calc(int a, int b);
}


    在下面的代码中,请分别使用Lambda的标准格式及省略格式调用 invokeCalc 方法,完成130和120的相减计算:
public class Test10InvokeCalc {
public static void main(String[] args) {
// TODO 请分别使用Lambda【标准格式】及【省略格式】调用invokeCalc方法来计算130-120的结果ß

 }

private static void invokeCalc(int a, int b, Calculator calculator) {
int result = calculator.calc(a, b);
  System.out.println("结果是:" + result);
 }
}
答:

    1.使用Lambda【标准格式】调用invokeCalc方法来计算130-120的结果ß
public class Test10InvokeCalc {
public static void main(String[] args) {
// 1.在此使用Lambda【标准格式】调用invokeCalc方法来计算130-120的结果ß
invokeCalc(130, 120, (int a, int b) -> {
return a - b;
  });
 }

private static void invokeCalc(int a, int b, Calculator calculator) {
int result = calculator.calc(a, b);
  System.out.println("结果是:" + result);
 }
}



    2.使用Lambda【省略格式】调用invokeCalc方法来计算130-120的结果ß
public class Test10InvokeCalc {
public static void main(String[] args) {
// 2.在此使用Lambda【省略格式】调用invokeCalc方法来计算130-120的结果ß
invokeCalc(130, 120, (a, b) -> a - b);
 }

private static void invokeCalc(int a, int b, Calculator calculator) {
int result = calculator.calc(a, b);
  System.out.println("结果是:" + result);
 }
}

问题:对Java基础班学生的考试成绩进行排序

  1. 定义一个学生类,有两个属性。姓名,考试成绩
  2. 在测试类中定义一个学生数组,存储学生信息。
  3. 使用Lambda省略格式写法对学生数组按照考试成绩由高到低进行排序。
答:
/**
 * 1.定义学生类
*/
public class Student {
private String name;
private int score;
// 省略构造器、toString方法与Getter Setter
}


/**
 * 2.测试类代码
* 按照成绩从大到小排序
*/
import java.util.Arrays;
import java.util.Comparator;

public class Test11Comparator {

public static void main(String[] args) {
// 本来成绩乱序的对象数组
Student[] array = {
new Student("宋远桥", 99),
new Student("俞岱岩", 98),
new Student("张翠山", 100)};

//使用lambda省略格式排序
Arrays.sort(array, (s1, s2) -> s2.getScore() - s1.getScore());

//遍历数组
for (Student student : array) {
   System.out.println(student);
  }
 }

}

 


基础题
练习一:相对路径和绝对路径的使用
描述:创建两个文件对象,分别使用相对路径和绝对路径创建。
答案
操作步骤:
绝对路径创建文件对象:使用File类一个参数的构造方法。
相对路径创建文件对象:使用File类两个参数的构造方法。
代码:
public class Test01_01 {
public static void main(String[] args) {
// 创建文件对象:绝对路径
        File f1 = new File("d:/aaa/a.txt");
        // 创建文件对象:相对路径
        File f2 = new File("a.txt");
    }
}
练习二:检查文件是否存在,文件的创建
描述:检查D盘下是否存在文件a.txt,如果不存在则创建该文件。
答案
操作步骤:
1.    使用绝对路径创建对象关联到D盘的a.txt。
2.    通过文件对象方法判断文件是否存在。
3.    不存在则调用创建文件的方法创建文件。
代码:
public class Test01_02 {
    public static void main(String[] args) throws IOException{
        // 创建文件对象:绝对路径
        File f = new File("d:/a.txt");
        // 如果文件不存在,则创建文件
        if(!f.exists()) {
            f.createNewFile();
        }
    }
}

练习三:单级文件夹的创建
描述:在D盘下创建一个名为bbb的文件夹。
答案
操作步骤:
1.    创建文件对象指定路径为d:/bbb
2.    调用文件对象创建文件夹的方法
代码:
public class Test01_03 {
    public static void main(String[] args) {
        // 创建文件对象
        File f = new File("d:/bbb");
        // 创建单级文件夹
        f.mkdir();
    }
}

练习四:多级文件夹的创建
描述:在D盘下创建一个名为ccc的文件夹,要求如下:
1.ccc文件夹中要求包含bbb子文件夹
2.bbb子文件夹要求包含aaa文件夹
答案:
操作步骤:
1.    创建文件对象关联路径:d:/ccc/bbb/aaa
2.    调用文件对象创建多级文件夹的方法
代码:
public class Test01_04 {
    public static void main(String[] args) {
        // 创建文件对象
        File f = new File("d:/ccc/bbb/aaa");
        // 创建多级文件夹
        f.mkdirs();
    }
}
练习五:删除文件和文件夹
描述:
将D盘下a.txt文件删除
将D盘下aaa文件夹删除,要求文件夹aaa是一个空文件夹。
答案:
操作步骤:
1.    创建文件对象关联路径:d:/a.txt
2.    调用文件对象删除文件的方法
3.    创建文件对象关联路径:d:/aaa
4.    调用文件对象删除文件夹的方法
代码:
public class Test01_05 {
    public static void main(String[] args) {
        // 创建文件对象
        File f = new File("d:/a.txt");
        // 删除文件
        f.delete();
        
        // 创建文件夹对象
        File dir = new File("d:/aaa");
        // 删除文件夹
        dir.delete();
    }
}
练习六:获取文件信息:文件名,文件大小,文件的绝对路径,文件的父路径
描述:
获取D盘aaa文件夹中b.txt文件的文件名,文件大小,文件的绝对路径和父路径等信息,并将信息输出在控制台。
答案:
操作步骤:
1.    在D盘aaa文件夹中创建一个b.txt文件并输入数据
2.    创建文件对象关联路径:d:/aaa/b.txt
3.    调用文件对象的相关方法获得信息并输出。可以通过API帮助文档查询方法。
代码:
public class Test01_06 {
    public static void main(String[] args) {
        // 创建文件对象
        File f = new File("d:/aaa/b.txt");
        // 获得文件名
        String filename = f.getName();
        // 获得文件大小
        longfilesize = f.length();
        // 获得文件的绝对路径
        String path = f.getAbsolutePath();
        // 获得父文件夹路径,返回字符串
        String parentPath = f.getParent();
        // 获得父文件夹路径,返回文件对象
        File parentFile = f.getParentFile();
        // 输出信息
        System.out.println("文件名:" + filename);
        System.out.println("文件大小:" + filesize);
        System.out.println("文件路径:" + path);
        System.out.println("文件父路径:" + parentPath);
        System.out.println("文件父路径:" + parentFile);
    }
}

练习七:文件夹或文件的判断
描述:
1.判断File对象是否是文件,是文件则输出:xxx是一个文件,否则输出:xxx不是一个文件。
2.判断File对象是否是文件夹,是文件夹则输出:xxx是一个文件夹,否则输出:xxx不是一个文件夹。(xxx是文件名或文件夹名)
答案:
操作步骤:
1.    创建两个文件对象分别关联到不同的文件,比如:d:/a.txt,d:/aaa
2.    调用文件对象的判断是否是文件或是否是文件夹的方法
3.    获得文件名,根据判断结果输出信息。
代码:
public class Test01_07 {
    public static void main(String[] args) {
        // 创建文件对象
        File f1 = new File("d:/b.txt");
        // 判断是否是一个文件
        if(f1.isFile()) {
            System.out.println(f1.getName()+"是一个文件");
        }  else {
            System.out.println(f1.getName()+"不是一个文件");
        }
        // 创建文件对象
        File f2 = new File("d:/aaaa");
        // 判断是否是一个文件夹
        if(f2.isDirectory()) {
            System.out.println(f2.getName()+"是一个文件夹");
        }  else {
            System.out.println(f2.getName()+"不是一个文件夹");
        }
    }
}

练习八:文件夹的获取方法
描述:
获取指定文件夹下所有的文件,并将所有文件的名字输出到控制台。
注意:不包含子文件夹下的文件
答案
操作步骤:
1.    创建文件对象关联到指定文件夹,比如:c:/aaa
2.    调用文件对象的listFiles方法获得文件数组
3.    遍历文件数组将每一个文件的名字输出到控制台
代码:
public class Test01_08 {
    public static void main(String[] args) {
        // 创建文件对象
        File f = new File("d:/aaa");
        // 获得文件夹下所有文件
        File[] files = f.listFiles();
        // 遍历文件数组
        for (File file :files) {
            // 将文件的名字打印到控制台
            System.out.println(file.getName());
        }
    }
扩展题
练习一:文件创建、判断功能、获取功能
描述:
键盘录入一个文件路径,根据文件路径创建文件对象,判断是文件还是文件夹
如果是文件,则输出文件的大小
如果是文件夹,则计算该文件夹下所有文件大小之和并输出(不包含子文件夹)。
答案
操作步骤:
1.    创建键盘录入对象
2.    接收键盘录入的字符串路径
3.    根据字符串路径创建文件对象
4.    判断文件对象是文件还是文件夹,如果是文件,则直接输出文件大小
5.    如果是文件夹,则获得该文件夹下所有的文件,定义一个求和变量,遍历文件数组获得每一个文件的大小并累加到求和变量中,最后输出求和变量的值。
代码:
public class Test02_01 {
    public static void main(String[] args) {
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        // 提示用户输入一个文件路径
        System.out.println("请输入一个文件路径:");
        // 接收用户输入的文件路径
        String filePath = sc.nextLine();
        // 根据文件路径创建文件对象
        File file = new File(filePath);
        // 判断是否是文件
        if(file.isFile()) {
            // 输出文件大小
            System.out.println("文件大小为:" + file.length());
        } else {
            // 是文件夹
            // 定义变量统计文件大小之和
            longlength = 0;
            // 获得该文件夹下的所有文件
            File[] files = file.listFiles();
            // 遍历文件数组
            for (File f :files) {
                if(f.isFile()) {
                    // 累加文件大小
                    length += f.length();
                }
            }
            // 输出文件夹文件的总大小
            System.out.println("文件总大小为:" + length);
        }
    }
}

练习二:递归的使用(一)
描述:
用递归实现不死神兔
故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。
在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,
再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,没有发生死亡,
问:现有一对刚出生的兔子2年后(24个月)会有多少对兔子?
答案
解题思路:
用递归法求斐波那契数列第n项
斐波那契数列,又称黄金分割数列,指的是这样一个数列:
  1、1、2、3、5、8、13、21、……
这个数列大家很容易的就推算出来后面好几项的值,那么到底有什么规律,简单说,就是前两项的和是第三项的值
代码:
import java.util.Scanner;

public class Test02_02 {
    public static void main(String[] args) {
        // 键盘输入并接收
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        // 调用递归方法并打印
        System.out.println(fun(n));
    }

public static int fun(int n) {
        // 判断如果是第1个或者第2个月就返回1
        if (n == 1 || n == 2) {
            return 1;
        } else {
            // 如果是第3个月就返回前两个月的值
            return fun(n - 1) + fun(n - 2);
        }
    }
}
练习三:递归的使用(二)
描述:猴子吃桃子问题,猴子第一天摘下若干个桃子,当即吃了快一半,还不过瘾,又多吃了一个。第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。以后每天都吃了前一天剩下的一半多一个。到第十天,只剩下一个桃子。试求第一天共摘了多少桃子?
答案
解题思路:采用逆向思维,从后往前推断,发现其中有相同的地方,即出现递推公式,可以采用递归方法。
令S10=1,容易看出S9=2(S10+1),简化一下
S9=2S10+2 
S8=2S9+2 
….. 
Sn=2S(n+1)+2
代码:
public class Test02_03 {
    public static void main(String[] args) {
        // 定义桃子数量调用递归方法
        int sum = sumPeach(1);
        // 调用递归函数并打印
        System.out.println(sum);
    }

    public static int sumPeach(int day) {
        // 判断如果是第10天就返回1
        if (day == 10) {
            return 1;
        } else {
            // 递归计算前一天的数量
            return 2 * sumPeach(day + 1) + 2;
        }
    }
}

练习四:文件过滤器的使用
描述:
获得指定文件夹下所有的java文件(不考虑子文件夹的)并输出到控制台
答案
操作步骤:
1.    创建一个类实现文件过滤器FileFilter接口并重新accept方法,在该方法根据传入的文件判断是否文件Java文件,如果是则返回true,否则返回false。
2.    根据文件夹路径字符串创建文件对象和创建文件过滤器接口实现类对象
3.    调用文件对象的listFiles(FileFilter f) 方法,传递文件过滤器实现类对象。
4.    遍历文件数组,输入每一个文件对象
代码:
public class Test02_04 {
public static void main(String[] args) {
// 创建文件夹对象
File file= new File("d:/aaa");
// 获得该文件夹下的所有java文件
File[] files = file.listFiles(new FileFilter() {
   public boolean accept(File pathname) {
   // 判断文件后缀名是否.java文件
   if (pathname.getName().endsWith(".java")) {
      return true;
   } else {
          return false;
           }
   }
});
//    遍历文件数组,打印所有的Java文件路径
    for (File f : files) {
         System.out.println(f.getAbsolutePath());
    }
  }
}

练习五:文件和文件夹删除
描述:
键盘录入一个文件夹路径,删除该文件夹以及文件夹路径下的所有文件。
要求:录入的文件夹里面要有多个文件,不能包含有子文件夹。
提示:如果文件夹里面有文件,则需要先将文件删除才能删除文件夹。
答案
操作步骤:
1.    创建键盘录入对象Scanner
2.    定义字符串接收用户输入的文件夹路径
3.    根据文件夹路径创建文件对象
4.    调用文件对象的listFiles方法获得文件数组
5.    遍历文件数组,删除每一个文件
6.    最后调用删除方法删除文件夹。
代码:
public class Test02_05 {
    public static void main(String[] args) {
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        // 提示用户输入一个文件路径
        System.out.println("请输入一个文件夹路径:");
        // 接收用户输入的文件夹路径
        String dirPath = sc.nextLine();
        // 根据文件夹路径创建文件对象
        File dir = new File(dirPath);
        // 获得该文件夹下的所有文件
        File[] files = dir.listFiles();
        // 遍历文件数组删除每一个文件
        for (File file :files) {
            // 删除文件
            file.delete();
        }
        // 删除文件夹
        System.out.println(dir.delete()?"删除成功":"删除失败");
    }
}
练习六:文件获取方法,递归的使用
描述:从键盘接收一个文件夹路径,获得该文件夹大小并输出到控制台。
答案
操作步骤:
1.    创建键盘录入对象Scanner
2.    定义字符串接收用户输入的文件夹路径
3.    根据文件夹路径创建文件对象
4.    定义一个方法calculate用来计算指定文件夹的大小,接收文件参数,返回long类型数值表示文件夹的大小。
5.    调用calculate方法传入文件夹对象,在该方法内部获得文件夹中所有文件,得到一个文件数组,定义一个变量size累加每一个文件的大小,遍历文件数组,判断是否是文件,如果是文件则获得文件大小并累加到变量size中,如果是文件夹,继续递归调用当前方法。
代码:
public class Test02_06 {
    public static void main(String[] args) {
        // 创建键盘输入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个文件夹路径:");
        // 接收用户输入的路径
        String filePath = sc.nextLine();
        // 根据路径字符串创建文件对象
        File dir = new File(filePath);
        // 调用calculate方法获得文件大小
        long length = calculate(dir);
        System.out.println("文件夹总大小:" + length); 
    }
    /*
     * 获得文件夹的大小
     */
    public static long calculate(File dir){
        long length = 0;
        // 获得文件数组
        File files[] = dir.listFiles();
        // 遍历数组
        for (File file :files) {
            // 判断是否是文件
            if(file.isFile()) {
                length += file.length();
            } else {
                length += calculate(file);
            }
        }
        return length;
    }
}
基础题
练习一:字节输出流写出字节数据
描述:利用字节输出流一次写一个字节的方式,向D盘的a.txt文件输出字符‘a’。
答案
操作步骤:
1.    创建字节输出流FileOutputStream对象并指定文件路径。
2.    调用字节输出流的write(int byte)方法写出数据
代码:
public class Test01_01 {
public static void main(String[] args) throws IOException {
        // 1.创建字节输出流FileOutputStream对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("d:/a.txt");
        // 2.调用字节输出流的write(int byte)方法写出数据
        fos.write(97);
        // 3.关闭流
        fos.close();
    }
}
练习二:字节输出流写出字节数组数据
描述:利用字节输出流一次写一个字节数组的方式向D盘的b.txt文件输出内容:"i love java"。
答案
操作步骤:
1.    创建字节输出流FileOutputStream对象并指定文件路径。
2.    调用字节输出流的write(byte[] buf)方法写出数据。
代码:
public class Test01_02 {
        public static void main(String[] args) throws IOException {
        // 1.创建字节输出流FileOutputStream对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("d:/b.txt");
        // 2.调用字节输出流的write(byte[] buf)方法写出数据。
        byte[] buf = "i love java".getBytes();
        fos.write(buf);
        // 3.关闭资源
        fos.close();
    }
}
练习三:文件的续写和换行输出
描述:在D盘下,有一c.txt 文件中内容为:HelloWorld 
在c.txt文件原内容基础上,添加五句 I love java,而且要实现一句一行操作(注:原文不可覆盖)。
利用字节输出流对象往C盘下c.txt文件输出5句:”i love java”

答案
操作步骤:
1.    利用两个参数的构造方法创建字节输出流对象,参数一指定文件路径,参数二指定为true
2.    调用字节输出流的write()方法写入数据,在每一行后面加上换行符:”\r\n”
代码:
public class Test01_03 {
    public static void main(String[] args) throws IOException{
        // 1.创建字节输出流FileOutputStream对象并指定文件路径,并追加方式
        FileOutputStream fos = new FileOutputStream("c:/c.txt",true);
        // 2.调用字节输出流的write方法写出数据
        // 2.1 要输出的字符串
        String content = "i love java \r\n";
        for (int i = 0; i< 5; i++) {
            fos.write(content.getBytes());
        }
        // 3.关闭流
        fos.close();
    }
}
练习四:字节输入流一次读取一个字节数据
描述:利用字节输入流读取D盘文件a.txt的内容,文件内容确定都为纯ASCII字符
,使用循环读取,一次读取一个字节,直到读取到文件末尾。将读取的字节输出到控制台
答案
操作步骤:
1.    创建字节输入流对象指定文件路径。
2.    调用read(byte b)方法循环读取文件中的数据
3.    直到读取到-1时结束读取
代码:
public class Test01_04 {
    public static void main(String[] args) throws IOException{
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("d:/a.txt");
        // 定义变量接收读取的字节
        int len = -1;
        // 循环从流中读取数据
        while((len = fis.read()) != -1) {
            System.out.print((char)len);
        }
        // 关闭流
        fis.close();
    }
}
练习五:字节输入流一次读取一个字节数组数据
描述:利用字节输入流读取D盘文件b.txt的内容,文件内容确定都为纯ASCII字符
,使用循环读取,一次读取一个字节数组,直到读取到文件末尾,将读取到的字节数组转换成字符串输出到控制台。
答案
操作步骤:
1.    创建字节输入流对象指定文件路径。
2.    定义一个字节数数组,用来存放读取的字节数
3.    调用read(byte[] buf)方法传入字节数组,循环读取文件中的数据
4.    直到读取到-1时结束读取
代码:
public class Test01_05 {
    public static void main(String[] args) throws IOException{
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("d:/b.txt");
        // 定义字节数组存放读取的字节数
        byte[] buffer = new byte[1024];
        // 定义变量接收读取的字节
        int len = -1;
        // 循环从流中读取数据
        while((len = fis.read(buffer)) != -1) {
            System.out.print(new String(buffer,0,len));
        }
        // 关闭流
        fis.close();
    }
}
练习六:字节流复制文件
描述:利用字节流将E盘下的a.png图片复制到D盘下(文件名保存一致)
要求:
一次读写一个字节的方式
答案
操作步骤:
1.    创建字节输入流对象关联文件路径:E盘下的a.png
2.    创建字节输出流对象关联文件路径:D盘下的a.png
3.    使用循环不断从字节输入流读取一个字节,每读取一个字节就利用输出流写出一个字节。
4.    关闭流,释放资源
代码:
public class Test01_06 {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("e:/a.png");
        // 创建字节输出流对象并关联文件
        FileOutputStream fos = new FileOutputStream("d:/a.png");
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = fis.read()) != -1) {
            // 每读取一个字节的数据就写出到目标文件中
            fos.write(len);
        }
        // 关闭流
        fis.close();
        fos.close();
    }
}
练习七:字符输出流写出字符数据
项目需求:请用户从控制台输入信息,程序将信息存储到文件Info.txt中。可以输入多条信息,每条信息存储一行。当用户输入:”886”时,程序结束。
答案
操作步骤:
1.    创建MainAPP类,并包含main()方法
2.    按照上述要求实现程序
代码:
public class Test01_07 {
    public static void main(String[]args) throws IOException {
        //1. 指定输出流, 对应的文件Info.txt
        FileWriter bw= new  FileWriter("Info.txt");
        //2.采用循环的方式,把每条信息存储一行到Info.txt中
        Scanner sc= new Scanner(System.in);
        while(true){
            //获取键盘输入的一行内容
            System.out.print("请输入内容:");
            String str= sc.nextLine();
            //当用户输入:”886”时,程序结束。
            if ("886".equals(str)) {
                break;//跳出循环
            }
            //把内容写入到Info.txt文件中
            bw.write(str);
            //换行
            bw.write(System.lineSeparator());
        }
        //关闭流
        bw.close();
    }
}
练习八:IO对象Properties结合使用,设置properties文件
描述:
我有一个文本文件score.txt,我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有"lisi"这样的键存在,如果有就改变其实为"100"
score.txt文件内容如下:
zhangsan = 90
lisi = 80
wangwu = 85
答案
操作步骤:
1.    创建一个空的Properties集合
2.    读取数据到集合中
3.    遍历集合,获取到每一个key
4.    判断当前的key 是否为 "lisi",如果是就把"lisi"的值设置为100
5.    把集合中所有的信息,重新存储到文件中
提示信息:
把集合中的信息,存储到文件中,可以用如下方法。
java.util 类 Properties
 void    store(OutputStream out, String comments)
          以适合使用load(InputStream)方法加载到Properties表中的格式,将此Properties表中的属性列表(键和元素对)写入输出流。
参数: 
out - 输出流。 
comments - 属性列表的描述。
代码:
public class Test02_06 {
public static void main(String[] args) throws IOException {
//1:创建一个空的集合
Properties prop = new Properties();
//2:读取数据到集合中
prop.load(new FileInputStream("score.txt"));
//3:遍历集合,获取到每一个key
Set<String> keys = prop.stringPropertyNames();
//获取到每一个key
for (String key : keys) {
//4:判断当前的key 是否为 "lisi"
if ("lisi".equals(key)) {
//把"lisi"的值设置为100
prop.setProperty(key, "100");
   }
  }
//把集合中所有的信息,重新存储到文件中
prop.store(new FileOutputStream("score.txt"), "haha");
 }
}
    
扩展题
练习一:字节输入流使用
描述:
在D盘下有一个文本文件test.txt(里面的内容由数字和字母组成)
定义一个方法统计test.txt文件中’a’字符出现的次数。
比如a字符在文件中出现了10次则调用方法传入a后,方法内部输出:a出现10次
答案
操作步骤:
1.    创建字节输入流对象,循环从文件中读取一个字节
2.    定义一个整数变量用来统计字符出现的次数。
3.    将读取的字节转换字符跟传入的字符进行比较,相同则计数加一。
4.    输出结果。
代码:
import java.io.FileInputStream;
import java.io.IOException;

public class Test02_01{
    public static void main(String[] args) throws IOException {
        // 调用方法
        calcuteCount(\'a\');
    }
    /*
    * 统计字符在文件中出现的次数
    */
    public static void calcuteCount(char ch) throws IOException {
        // 创建字节输入流
        final FileInputStream fis = new FileInputStream("d:/test.txt");
        try (fis) {
            // 定义一个计数变量,统计字符出现的次数
            int count = 0;
            // 循环读取数据
            int len = -1;
            while ((len = fis.read()) != -1) {
                // 判断字符c和外界传入的字符是否相同
                if (len == ch) {
                    count++;
                }
            }
            System.out.println(ch + "出现了" + count + "次");
        } catch (IOExceptione) {
            e.printStackTrace();
        }
    }
}
练习二:字节输出流写出数据
描述:
从控制台循环接收用户录入的学生信息,输入格式为:学号-学生名字
将学生信息保存到D盘下面的stu.txt文件中,一个学生信息占据一行数据。
当用户输入end时停止输入。
答案
操作步骤:
1.    使用Scanner类进行键盘录入数据
2.    创建字节输入流对象关联目标文件
3.    使用死循环不停的接收用户输入的学生数据
4.    接收用户输入的学生数据
5.    判断输入的内容是否是end,是则终止循环,停止输入。否则就数据写出到文件中。
代码:
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Test02_02{
    public static void main(String[] args) throws IOException {
        // 创建字节输出流对象
        final FileOutputStream fos = new FileOutputStream("d:/stu.txt");
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入学生信息,格式:学号-姓名");
        try (fos; sc) {
            // 使用死循环不停的接收用户输入的学生数据
            while (true) {
                // 接收用户输入的学生数据
                String line = sc.nextLine();
                // 判断输入的内容是否是end,是则终止循环
                if ("end".equals(line)) {
                    break;
                }
                // 将数据写出到文件中。
                fos.write(line.getBytes());
                // 写出换行符号
                fos.write(System.lineSeparator().getBytes());
            }
        } catch (IOExceptione) {
            e.printStackTrace();
        }
    }
}
练习三:字符输出流写出字符数据并存到集合中
需求说明:从控制台接收3名学员的信息,每条信息存储到一个Student对象中,将多个Student对象存储到一个集合中。输入完毕后,将所有学员信息存储到文件Student.txt中。每名学员信息存储一行,多个属性值中间用逗号隔开。
答案
    操作步骤:
1.    创建Student类,有如下属性:
学号、姓名、性别、年龄
全部属性使用String类型。要求有无参,全参构造方法。所有属性私有,并提供公有get/set方法。
2.    创建MainApp类,包含main()方法
3.    在main()方法中:
1)    定义一个存储Student对象的集合;
2)    循环3次,从控制台接收3名学员信息,每条信息封装一个Student对象,将每个Student对象存储到集合中。
3)    遍历集合,获取每个Student对象,取出所有属性值,输出到文件Test2_2.txt中。每名学员信息占一行。
代码:
public class Task02_03 {
    public static void main(String[] args) throws IOException {
        // 1.定义学生类, 定义存学生的集合
        ArrayList<Student> list = new ArrayList<Student>();
        // 2.通过3次循环,完成如下操作
        Scanner sc = new Scanner(System.in);
        for (int i = 1; i<= 3; i++) {
            // 键盘输入学生的信息,
            System.out.print("请输入第" + i + "名学生的学号:");
            String id = sc.next();
            System.out.print("请输入第" + i + "名学生的姓名:");
            String name = sc.next();
            System.out.print("请输入第" + i + "名学生的性别:");
            String sex = sc.next();
            System.out.print("请输入第" + i + "名学生的年龄:");
            String age = sc.next();
            // 把信息封装到Student对象中
            Student s = new Student(id, name, sex, age);
            // 把Student对象存到集合里
            list.add(s);
        }
        // 3.将所有学员信息存储到文件Student.txt中。
        FileWriter out = new FileWriter("Student.txt");
        // 每名学员信息存储一行,多个属性值中间用逗号隔开。
        for (int i = 0; i<list.size(); i++) {
            // 1.获取集合中每一个学生对象
            Student s = list.get(i);
            // 2.获取对象中的每一个属性值,多个属性值中间用逗号隔开
            String line = s.getId() + "," + s.getName() + "," + s.getSex() + "," + s.getAge();
            // 3.按照指定的格式把对象的属性值,写入到文件中
            out.write(line);
            out.write(System.lineSeparator());
        }
        out.close();// 关闭流
    }
}
基础题
练习一:高效字节输出流写出字节数据
描述:利用高效字节输出流往C盘下的d.txt文件输出一个字节数。
答案
操作步骤:
1.    创建字节输出流对象关联文件路径
2.    利用字节输出流对象创建高效字节输出流对象
3.    调用高效字节输出流对象的write方法写出一个字节
4.    关闭高效流,释放资源。
代码:
public class Test01_01 {
    public static void main(String[] args) throws IOException {
        // 创建字节输出流FileOutputStream对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("c:\\d.txt");
        // 利用字节输出流创建高效字节输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 调用高效字节输出流对象的write(int byte)方法写出一个字节数据
        bos.write(97);
        // 关闭流
        bos.close();
    }
}
练习二:高效字节输出流写出字节数组数据
描述:利用高效字节输出流往C盘下的e.txt文件写出一个字节数组数据,如写出:”i love java”
答案
操作步骤:
1.    创建字节输出流对象关联文件路径
2.    利用字节输出流对象创建高效字节输出流对象
3.    定义字符串存放要输出的数据,然后将字符串转换为字节数组。
4.    调用高效字节输出流对象的write方法将字节数组输出。
5.    关闭高效流。
代码:
public class Test01_02 {
    public static void main(String[] args) throws IOException {
        // 创建字节输出流FileOutputStream对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("c:\\e.txt");
        // 利用字节输出流创建高效字节输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 调用高效字节输出流对象的write(byte[] buff)方法写出一个字节数据
        bos.write("i love java".getBytes());
        // 关闭流
        bos.close();
    }
}
练习三:高效流文件复制
描述:利用高效字节输入流和高效字节输出流完成文件的复制。
要求:
1.将C盘下的c.png文件复制到D盘下
2.一次读写一个字节数组方式复制
答案
操作步骤:
1.    创建字节输入流对象并关联文件路径
2.    利用字节输入流对象创建高效字节输入流对象
3.    创建字节输出流对象并关联文件路径
4.    利用字节输出流对象创建高效字节输出流对象
5.    创建字节数组用来存放读取的字节数
6.    利用高效字节输入流循环读取文件数据,每读取一个字节数组,利用高效字节输出流对象将字节数组的内容输出到目标文件中。直到读取到文件末尾。
7.    关闭高效流对象
代码:
public class Test01_03 {
    public static void main(String[] args) throws IOException{
        // 创建字节输入流对象并关联文件路径
        FileInputStream fis = new FileInputStream("c:\\c.png");
        // 利用字节输出流对象创建高效字节输出流对象
        BufferedInputStream bis = new BufferedInputStream(fis);
        // 创建字节输出流对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("d:\\c.png");
        // 利用字节输出流创建高效字节输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 定义字节数组接收读取的字节
        byte[] buffer = new byte[1024];
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = bis.read(buffer)) != -1) {
            // 每读取一个字节的数据就写出到目标文件中
            bos.write(buffer,0,len);
        }
        // 关闭流
        bis.close();
        bos.close();
    }
}
练习四:高效字符流和集合的综合使用
描述:
分析以下需求,并用代码实现
    实现一个验证码小程序,要求如下:
    1. 在项目根目录下新建一个文件:data.txt,键盘录入3个字符串验证码,并存入data.txt中,要求一个验证码占一行;
    2. 键盘录入一个需要被校验的验证码,如果输入的验证码在data.txt中存在:在控制台提示验证成功,如果不存在控制台提示验证失败
答案代码
public class Test01_04 {
    public static void main(String[] args) throws Exception {
        //键盘录入3个字符串并写入项目根路径下的data.txt文件中
        writeString2File();
        //验证码验证
        verifyCode();
    }
    /**
    * 验证码验证
    * @throws Exception 
    */
    private static void verifyCode() throws Exception {
        //创建ArrayList集合,用于存储文件中的3个验证码
        ArrayList<String>list = new ArrayList<>();
        //创建高效字符缓冲输入流对象,并和data.txt文件关联
        BufferedReader br = new BufferedReader(new FileReader(new File("data.txt")));
        String line = null;
        //循环读取每一行
        while(null!=(line = br.readLine())) {
            //将读到的每一行信息存入到list集合中
            list.add(line);
        }
        //关闭流对象
        br.close();
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        //提示用户输入验证码
        System.out.println("请输入一个验证码");
        String code = sc.nextLine();
        if(list.contains(code)) {
            System.out.println("验证成功");
        } else {
            System.out.println("验证失败");
        }
    }
    /**
    * 键盘录入3个字符串并写入项目根路径下的data.txt文件中
    * @throws Exception 
    */
    private staticvoid writeString2File() throws Exception {
        //创建高效字符缓冲输出流对象并和data.txt文件关联
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("data.txt")));
        String line = null;
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        for(inti = 0;i<3;i++) {
            System.out.println("请输入第"+(i+1)+"个字符串验证码");
            //读取用户键盘录入的一行验证码信息
            line = sc.nextLine();
            //将读取到的一行验证码写入到文件中
            bw.write(line);
            //写入换行符
            bw.newLine();
        }
        //关闭流对象
        bw.close();
    }
}
练习五:转换输出流的使用
描述:现有一字符串:”我爱Java”。将该字符串保存到当前项目根目录下的a.txt文件中。
要求:使用gbk编码保存。
注意:idea的默认编码是utf-8,所以可以通过filesettingsfile encodings设置为gbk格式,否则打开a.txt文件看到的将会是乱码。
答案
操作步骤:
1.    创建文件字节输出流关联目标文件
2.    根据文件字节输出流创建转换输出流对象,并指定编码字符集为:gbk
3.    调用流对象的方法将字符串写出到文件中。
4.    关闭流并释放资源。
代码:
public class Test01_05 {
    public static void main(String[] args) throws IOException{
        // 要保存的字符串
        String content = "我爱Java";
        // 创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("a.txt");
        // 创建转换输出流对象
        OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
        // 调用方法写出数据
        osw.write(content);
        // 关闭流释放资源
        osw.close();
    }
}
练习六:转换输入流的使用
描述:利用转换输入流将当前项目根目录下使用gbk编码的a.txt文件的内容读取出来,并打印在控制台上。
要求:不能出现乱码的情况。
答案
操作步骤:
1.    创建字节输入流对象指定文件路径。
2.    根据字节输入流对象创建转换输入流对象并指定字符集编码为:gbk
3.    调用转换输入流对象的读取方法读取内容
4.    关闭流释放资源
代码:
public class Test01_06 {
    public static void main(String[] args) throws IOException{
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("a.txt");
        // 创建转换输入流对象
        InputStreamReader isr = new InputStreamReader(fis,"gbk");
        // 定义字符数组存放读取的内容
        char[] buffer = newchar[1024];
        // 定义变量接收读取的字符个数
        intlen = -1;
        while((len = isr.read(buffer)) != -1) {
            System.out.print(new String(buffer,0,len));
        }
        // 关闭流
        isr.close();
    }
}
扩展题
练习一:对象的序列化
描述:定义一个学生类,包含姓名,年龄,性别等成员变量,提供setters和getters方法以及构造方法。在测试类中创建一个学生对象,给学生对象的三个成员变量赋值。然后将该对象保存到当前项目根目录下的stu.txt文件中。
答案
操作步骤:
1.    定义学生类并实现序列化接口和测试类
2.    在测试类中创建学生对象
3.    创建文件字节输出流对象并关联目标文件
4.    根据文件字节输出流对象创建对象输出流对象
5.    调用对象输出流对象的方法将学生对象保存到文件中
6.    关闭流释放资源
代码:
public class Test02_01 {
    public static void main(String[] args) throws IOException {
        // 创建学生对象
        Student s = new Student("jack",20,"男");
        // 创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("stu.txt"));
        // 将学生对象保存文件中
        oos.writeObject(s);
        // 关闭流并释放资源
        oos.close();
    }
}

class Student implements Serializable{
    Private static final long serialVersionUID = 4983659706961705248L;
    private String name;
    privateint age;
    private String gender;
    
    public Student() {
    }
    public Student(String name, intage, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    public String getName() {
        returnname;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        returnage;
    }
    public void setAge(intage) {
        this.age = age;
    }
    public String getGender() {
        returngender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
}
练习二:对象的反序列化
描述:将上一题保存到stu.txt文件中的学生对象读取出来。
答案
操作步骤:
1.    创建文件字节输入流对象关联目标文件
2.    根据文件字节输入流对象创建对象输入流对象
3.    调用对象输入流对象的方法从文件中获取学生对象
4.    关闭流释放资源。
代码:
public class Test02_02 {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("stu.txt");
        // 创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(fis);
        // 读取学生对象
        Student s = (Student) ois.readObject();
        System.out.println(s);
        // 关闭流
        ois.close();
    }
}
练习三:字节打印流的使用
描述:从键盘录入一行字符串,利用字节打印流将该行字符串保存到当前项目根目录下的d.txt文件中
答案
操作步骤:
1.创建字节打印流对象并关联文件路径
2.调用字节打印流对象的打印方法将内容输入到目标文件中
3.关闭流释放资源
代码:
public class Test02_03 {
    public static void main(String[] args) throws IOException {
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一行字符串:");
        // 接收用户输入的数据
        String line = sc.nextLine();
        // 创建字节打印流对象
        PrintStream ps = new PrintStream("d.txt");
        // 将字符串写出到文件中
        ps.println(line);
        // 关流
        ps.close();
    }
}
练习四:高效字符流读写数据
描述:
项目根路径下有text.txt文件,内容如下:
    我爱黑马
    123456
利用IO流的知识读取text.txt文件的内容反转后写入text1.txt文件中,内容如下:
    123456
我爱黑马    

提示:List集合反转元素的顺序时,用到了如下API。
java.util类 Collections
static void    reverse(List<?> list) 
          反转指定列表中元素的顺序。


答案代码
public class Test02_04 {
    public static void main(String[] args) throws IOException {
        //创建集合
        ArrayList<String> list = new ArrayList<>();
        //读取关联文件
        BufferedReader br = new BufferedReader(new FileReader("text.txt"));
        String line;
        while((line = br.readLine()) != null) {
            //每读取一行放入集合
            list.add(line);
        }
        //关闭流
        br.close();
        //反转集合
        Collections.reverse(list);
        //写入关联文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("text1.txt"));
        for(inti = 0; i<list.size(); i++) {
            //逐行写入
            bw.write(list.get(i));
            bw.newLine();//换行
            bw.flush();//刷新
        }
        bw.close();//关闭流
    }
}
练习五:对象的序列化,对象输出流的使用
描述:
定义一个学生类,成员变量有姓名,年龄,性别,提供setters和getters方法以及构造方法
定义一个测试类,在测试类创建多个学生对象保存到集合中,然后将集合存储到当前项目根目录下的stus.txt文件中。
答案
操作步骤:
1.    创建集合对象用来存放学生
2.    创建多个学生对象添加到集合中
3.    创建对象输出流关联目标文件
4.    调用对象输出流的方法将集合对象保存到文件中
5.    关闭流并释放资源
代码:
public class Test02_05 {
    public static void main(String[] args) {
        // 创建集合对象,存放学生对象
        List<Student> stus = new ArrayList<Student>();
        // 添加学生对象
        stus.add(new Student("jack",20,"男"));
        stus.add(new Student("rose",18,"女"));
        stus.add(new Student("laowang",20,"男"));
        // 创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("stus.txt"));
        // 将学生对象保存文件中
        oos.writeObject(stus);
        // 关闭流并释放资源
        oos.close();
}
}
基础题
练习一:ip地址和端口号概念
描述:
一、    请写出IP地址的概念:
二、    请写出端口号的概念:
答案:
IP地址:互联网协议地址(Internet Protocol Address),俗称IP.IP地址用来给一个网络中的计算机设备做唯一的编号.

端口号:端口号用来给计算机里的应用程序(进程)做唯一的标识,用2个字节表示的整数,取值范围0~65535.
练习二:UDP协议
判断下列说法是否正确
由于UDP面向无连接的协议,可以保证数据完整性,因此在传输重要数据时采用UDP协议.
答案
判断错误,因为面向无连接,容易丢失包,所以不能保证数据完整.
练习三:TCP协议
TCP协议中”三次握手”,第一次握手指的是什么:

答案
第一次握手:客户端向服务器发送请求,等待服务器确认
练习四:ServerSocket
以下哪个方法是ServerSocket类用于接收来自客户端请求:
A.    receive()
B.    accept()
C.    set()
D.    send()
答案
B
练习五:TCP网络程序
需求说明:创建新项目,按以下要求编写代码:
在项目下创建TCP 服务器端 端口号为8888 
1:等待客户端连接   如果有客户端连接  获取到客户端对象
2:获取到客户端对象之后 当前在服务器读取数据客户端传送数据  
答案
public class TCPServer {
   public static void main(String[] args) throws Exception {
      //1创建服务器对象 
      ServerSocket  ss = new ServerSocket(8888);
      //2等待客户端连接   如果有客户端连接  获取到客户端对象 
      Socket socket = ss.accept();
      //3当前在服务器中  要读取数据  需要输入流  流由谁提供 客户端
      InputStream in = socket.getInputStream();//获取输入流
      //4:读数据
      int len;
      byte[] buffer = new byte[1024];
      while((len=in.read(buffer))!=-1){
          System.out.println(new String(buffer, 0, len));
      }
      //释放资源
      in.close();
//       ss.close();服务器一般不会关闭
   }
}
练习六:TCP网络程序
需求说明:创建新项目,按以下要求编写代码:
在项目下创建TCP 客户端 
访问之前创建的服务器端,服务器端ip127.0.0.1 端口号8888
1:客户端连接服务器,并发送 hello.服务器,我是客户端.
2:开启上一题服务器,等待客户端连接,客户端连接并发送数据  
答案:
public class TCPClient {
  public static void main(String[] args) throws Exception {
    //创建 Socket客户端对象
      Socket  socket = new Socket("127.0.0.1", 8888);
      //写数据  需要输出流  谁提供 客户端
      OutputStream out = socket.getOutputStream();
      //写数据
      out.write("hello.服务器,我是客户端.".getBytes());
      //释放资源
      out.close();
      socket.close();
  }
}
扩展题
练习一:TCP程序
需求说明:使用TCP编写一个网络程序,设置服务器程序监听端口为8002,当于客户端建立后,向客户端发送”hello world”,客户端将信息输出
答案
操作步骤:
1.    建立项目
2.    创建TCPServer类,包含main()方法
 使用ServerSocket创建服务器对象,监听8002端口,调用accept()方法等待客户端连接,当于客户端连接上之后,获取输出流对象,输出”hello world”
3.    创建TCPClient类,包含main()方法
使用Socket创建客户端对象,指定服务器IP和端口号,与服务器端建立连接后,获取输入流对象,读取数据,并打印.
代码:
public class TCPClient {
  public static void main(String[] args) throws Exception {
    //创建 Socket客户端对象
      Socket  socket = new Socket("127.0.0.1", 8002);      
      //读服务器数据  
      InputStream in = socket.getInputStream();//获取输入流
      //读数据       
      byte[] buffer = new byte[1024];
      int len = in.read(buffer); 
      System.out.println(new String(buffer, 0, len));
      //释放资源      
      in.close();
      socket.close();
  }
}
public class TCPServer {
   public static void main(String[] args) throws Exception {
      //1创建服务器对象 
      ServerSocket  ss = new ServerSocket(8002);
      //2等待客户端连接   如果有客户端连接  获取到客户端对象 
      Socket socket = ss.accept();
      //3当前在服务器中  将数据写到流中
      OutputStream out = socket.getOutputStream();
      out.write("hello world".getBytes());       
      //释放资源
      out.close();
//       ss.close();服务器一般不会关闭
   }
}
练习二:TCP上传案例
需求说明:我们来做一个“文件上传案例”,有以下要求:
将项目中的一个图片,通过客户端上传至服务器

答案
操作步骤:
1,创建服务器,等待客户端连接
2,创建客户端Socket,连接服务器
3,获取Socket流中的输出流,功能:用来把数据写到服务器
4,创建字节输入流,功能:用来读取数据源(图片)的字节
5,把图片数据写到Socket的输出流中(把数据传给服务器)
6,客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端
7,获取Socket的输入流
8,创建目的地的字节输出流
9,把Socket输入流中的数据,写入目的地的字节输出流中
10,获取Socket的输出流, 作用:写反馈信息给客户端
11,写反馈信息给客户端
12,获取Socket的输入流  作用: 读反馈信息
13,读反馈信息
代码:
public class TCPServer {
    public static void main(String[] args)throws IOException {
        //1创建服务器对象 
        ServerSocket server = new ServerSocket(9898);
        //2等待客户端连接   如果有客户端连接  获取到客户端对象 
        Socket s = server.accept();
        //3当前在服务器中  读取数据
        InputStream in = s.getInputStream();
        //4当前在服务器中  将数据写到流中
        FileOutputStream fos = new FileOutputStream("/Users/apple/Documents/复制品.JPG");
        byte[] bytes = new byte[1024];
        int len = 0 ;
        while((len = in.read(bytes))!=-1){
            fos.write(bytes, 0, len);
        }
        //5写完数据提示上传成功
        s.getOutputStream().write("上传成功".getBytes());
        //6释放资源
        fos.close();
        s.close();
        server.close();
    }
}

public class TCPCleint {
    public static void main(String[] args)throws IOException {
        //1创建服务器对象 
        Socket s = new Socket("127.0.0.1", 9898);
        //2指定路径
        FileInputStream fis = new FileInputStream("/Users/apple/Desktop/1.JPG");
        //3读取服务器数据
        OutputStream out = s.getOutputStream();
        byte[] bytes = new byte[1024];
        int len = 0;
        while((len = fis.read(bytes))!=-1) {
            out.write(bytes,0,len);
        }
        //4告知书写完毕
        s.shutdownOutput();
        //5书写到服务器
        InputStream in = s.getInputStream();
        len = in.read(bytes);
        System.out.println("服务器:"+new String(bytes,0,len));
        //6释放资源
        fis.close();
        s.close();
    }
}
练习三:上传图片文件
客户端需求:把一个图片文件发送到服务端并读取回馈信息。要求判断文件是否存在及格式是否为jpg并要求文件小于2M。
服务端需求:接收客户端发送过来的图片数据。进行存储后,回馈一个“上传成功”字样。支持多用户的并发访问。
客户端代码:    
public class MyClient {

    public static void main(String[] args) throws Exception {

        File file = new File("D:\\aa.jpg");
        if(!file.exists()){
            return;
        }
        if (!file.getName().endsWith(".jpg")){
            return;
        }
        if (file.length()>=1024*1024*2){

            return;
        }

        Socket socket = new Socket("127.0.0.1",9999);

        //输出流
        OutputStream outputStream = socket.getOutputStream();
        FileInputStream fileInputStream = new FileInputStream(file);
        int len;
        byte[] arr = new byte[1024];

        while ((len=fileInputStream.read(arr))!=-1){
            outputStream.write(arr,0,len);
        }
        socket.shutdownOutput();

        InputStream inputStream = socket.getInputStream();
        int i = inputStream.read(arr);
        System.out.println(new String(arr,0,i));

        fileInputStream.close();
        outputStream.close();
        socket.close();

    }

}




服务端代码:
    public class MyServer {

    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket(9999);


        while (true){

            Socket socket = serverSocket.accept();

            new Thread(){

                @Override
                public void run() {

                    try {

                        InputStream inputStream = socket.getInputStream();

                        FileOutputStream fileOutputStream = new FileOutputStream(System.currentTimeMillis()+".jpg");

                        int len;
                        byte[] arr = new byte[1024];

                        while ((len=inputStream.read(arr))!=-1){

                            fileOutputStream.write(arr,0,len);
                        }

                        OutputStream outputStream = socket.getOutputStream();
                        outputStream.write("上传成功".getBytes());

                        outputStream.close();
                        fileOutputStream.close();
                        inputStream.close();
                        socket.close();

                    }catch (Exception e){

                        e.printStackTrace();
                    }

                }
            }.start();

        }
    }
}
基础题 
练习一:函数式接口
1.    定义一个函数式接口CurrentTimePrinter,其中抽象方法void printCurrentTime(),使用注解@FunctionalInterface
2.    在测试类中定义static void showLongTime(CurrentTimePrinter timePrinter),该方法的预期行为是使用timePrinter打印系统当前毫秒值
3.    测试showLongTime(),通过lambda表达式完成需求

答案
TimePrinter接口:
@FunctionalInterface
public interface CurrentTimePrinter
{
    void printCurrenTime();
}
测试类:
public class Test01 {
    public static void main(String[] args) {
        showLongTime(()->System.out.println(System.currentTimeMillis()));
    }

    public static void showLongTime(CurrentTimePrinter timePrinter){
        timePrinter.printCurrentTime();
    }
}

练习二:函数式接口
1.    定义一个函数式接口IntCalc,其中抽象方法int calc(int a , int b),使用注解@FunctionalInterface
2.    在测试类中定义static void getProduct(int a , int b ,IntCalc calc), 该方法的预期行为是使用calc得到a和b的乘积并打印结果
3.    测试getProduct(),通过lambda表达式完成需求

答案
IntCalc接口:
@FunctionalInterface
public interface IntCalc {
    int calc(int a, int b);
}
测试类:
public class Test02 {
    public static void main(String[] args) {
        getProduct(2,3,(a,b)->a*b);
    }
    public static void getProduct(int a, int b, IntCalc intCalc){
        int product = intCalc.calc(a,b);
        System.out.println(product);

    }
}
练习三:静态方法引用
1.    定义一个函数式接口NumberToString,其中抽象方法String convert(int num),使用注解@FunctionalInterface
2.    在测试类中定义static void decToHex(int num ,NumberToString nts), 该方法的预期行为是使用nts将一个十进制整数转换成十六进制表示的字符串,tips:已知该行为与Integer类中的toHexString方法一致
3.    测试decToHex (),使用方法引用完成需求

答案
NumberToString接口:
@FunctionalInterface
public interface NumberToString {
    String convert(int num);
}
测试类:
public class Test03 {
    public static void main(String[] args) {
        decToHex(999, Integer::toHexString);
    }
    public static void decToHex(int num ,NumberToString nts){
        String convert = nts.convert(num);
        System.out.println(convert);
    }
}

练习四:成员方法引用、可变参数
1.    已知有随机数工具类如下:
import java.util.Random;
public class RandomUtil {
    private Random random = new Random();

    public int nextInt(int... nums) {
        if (nums == null || nums.length == 0) {
            throw new RuntimeException("pls认真一点!");
        }
       //生成1到nums[0](包含1和nums[0])之间的随机数
        if (nums.length == 1) return random.nextInt(nums[0]) + 1;

        //生成nums[0]到nums[1](包含nums[0]和nums[1])之间的随机数
        if (nums.length == 2) return random.nextInt(nums[1] + 1 - nums[0]) + nums[0];
        
       //从数组nums中取出一个随机元素
       return nums[random.nextInt(nums.length)];
    }
}
2.    定义一个函数式接口NumberSupplier,其中抽象方法int getNum(int...nums),使用注解@FunctionalInterface
3.    在测试类中定义static void getRandomNumFromOneToNum(int num , NumberSupplier ns), 该方法的预期行为是使用ns得到一个从1到num(包含1和num)之间的随机数并打印
4.    在测试类中定义static void getRandomNumFromAToB(int a ,int b, NumberSupplier ns), 该方法的预期行为是使用ns得到一个从a到b(包含a和b)之间的随机数并打印
5.    在测试类中定义static void getRandomNumFromArray(int[] nums, NumberSupplier ns), 该方法的预期行为是使用ns从数组nums中获取一个随机元素并打印
6.    主方法中测试调用以上三个方法,使用方法引用完成需求

答案
NumberFactory接口:
@FunctionalInterface
public interface NumberSupplier{
    int getNum(int...nums);
}
测试类:
public class Test04 {
    public static void main(String[] args) {
        RandomUtil randomUtil = new RandomUtil();
        getRandomNumFromOneToNum(10, randomUtil::nextInt);
        getRandomNumFromAToB(10, 20, randomUtil::nextInt);
        int[] arr = {2, 4, 6, 8};
        getRandomNumFromArray(arr, randomUtil::nextInt);
    }

    public static void getRandomNumFromOneToNum(int num, NumberSupplier ns) {
        int result = ns.getNum(num);
        System.out.println(result);

    }

    public static void getRandomNumFromAToB(int a, int b, NumberSupplier ns) {
        int result = ns.getNum(a, b);
        System.out.println(result);
    }

    public static void getRandomNumFromArray(int[] nums, NumberSupplier ns) {
        int result = ns.getNum(nums);
        System.out.println(result);
    }

}

练习五:super引用成员方法
按要求补全代码
1.    有函数式接口Helper如下
@FunctionalInterface
public interface Helper {
    void help();
}
2.    有父类Father如下
public class Father {
    public void askMoney(){
        System.out.println("向家中的财政老大要钱购买家庭物资...");
    }

    public void spendMoney(){
        System.out.println("去村口小卖部付钱给老板打酱油...");
    }
}


3.    有子类Son如下
public class Son extends Father {
    @Override
    public void askMoney() {
        System.out.println("向家中的财政老大要钱交(上)学(网)费(吧)...");
    }
    @Override
    public void spendMoney() {
        System.out.println("去网吧付钱给网管开了一台机器...");
    }
    public void helpFather(Helper helper) {
        helper.help();
    }
    //完成帮助Father打酱油的方法
    public void daJiangYou() {
        _____________________________;
        _____________________________;
    }
}
4.    使用方法引用补全Son类中横线处的代码,帮助Father打酱油


答案
//完成帮助Father打酱油的方法
public void daJiangYou() {
    helpFather(super::askMoney);
    helpFather(super::spendMoney);
}

练习六:this引用成员方法
按要求补全代码
1.    有字符串包装StringWrapper接口如下
public interface StringWrapper {
    String wrap(String str);
}
2.    有Book类如下
public class Book {
    //书名
    private String name;
    //出版社
    private String publishingCompany;

    public Book(String name, String publishingCompany) {
        this.name = name;
        this.publishingCompany = publishingCompany;
    }

    //bookMsg()拼接带书名号的书名
    private String bookMsg(String bookname) {
        return "《" + bookname + "》";
    }

    //publishingMsg()拼接出版信息
    private String publishingMsg(String msg) {
        return "【专柜正品<" + msg + ">原装绝版】";
    }

    //packSaleMsg()使用StringWrapper为上架销售信息包装
    public String packSaleMsg(String msg, StringWrapper wrapper) {
        return wrapper.wrap(msg);
    }

    //sale()上架销售
    public void sale() {
       //开始包装上架销售信息
        String saleMsg = packSaleMsg(             ) + packSaleMsg(             );
        System.out.println(saleMsg);
       //开始售卖
       System.out.println("2元一本,欲练此功,必先购买!");
    }
}
3.    有测试类如下
public class Test05 {
    public static void main(String[] args) {
        Book book = new Book("新华字典","商务印书馆");
        book.sale();
    }
}
4.    填写Book类中空白横线处的代码,要求出现如下结果:






答案
String saleMsg = packSaleMsg(name, this::bookMsg) + packSaleMsg(publishingCompany, this::publishingMsg);

练习七:类的构造器引用
1.    有对象工厂BeanFactory接口如下
@FunctionalInterface
public interface BeanFactory<T> {
    T getBean();
}
2.    有汽车类Car如下
public class Car {
    private String brand;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Car(String brand) {
        this.brand = brand;
    }

    public Car() {

    }
}
3.    有测试类如下
public class Test06 {
    public static void main(String[] args) {
        Car Q7 = getCar(______);
        Q7.setBrand("奥迪");
    }
    public static Car getCar(____________){
        return factory.getBean();
    }
}
4.    补全测试类中横线处的代码,完成原代码的需求

答案
public class Test06 {
    public static void main(String[] args) {
        Car Q7 = getCar(Car::new);
        Q7.setBrand("奥迪");
    }
    public static Car getCar(BeanFactory<Car> factory){
        return factory.getBean();
    }
}
练习八:数组构造器引用
1.    定义一个函数式接口ArrayBuilder<T>,提供带泛型的抽象方法T[] buildArray(int length),使用注解@FunctionalInterface
2.    在测试类中定义static void getIntegerArray(int length , ArrayBuilder<Integer> builder), 该方法的预期行为是使用builder创建一个长度为length的Integer数组并打印其内存地址
3.    测试getIntegerArray (),使用方法引用完成需求

答案
ArrayBuilder接口:
@FunctionalInterface
public interface ArrayBuilder<T> {
     T[] buildArray(int length);
}
测试类
public class Test07 {

    public static void main(String[] args) {
        getintarray(5, Integer[]::new);
    }
    private static void getintarray(int length,ArrayBuilder<Integer> builder){
        Integer[] array = builder.buildArray(length);
        System.out.println(array);

    }
}

练习九:Supplier接口使用
1.    给出测试类中代码如下:
import java.util.function.Supplier;

public class Test01 {
    public static <T> T getObj(Supplier<T> supplier) {
        return supplier.get();
    }

    public static void main(String[] args) {
        
    }
}
2.    分别使用lambda表达式获得以下对象:
a)    长度为5的String数组
b)    包含5个1-20(含1和20)之间随机数的HashSet<Integer>集合
c)    一个代表2018年4月1日的Calendar对象

答案
import java.util.Calendar;
import java.util.HashSet;
import java.util.Random;
import java.util.function.Supplier;

public class Test01 {
    public static <T> T getObj(Supplier<T> supplier) {
        return supplier.get();
    }

    public static void main(String[] args) {
        String[] obj1 = getObj(() -> new String[5]);

        HashSet<Integer> obj2 = getObj(() -> {
            Random random = new Random();
            HashSet<Integer> integers = new HashSet<>();
            while (integers.size() < 5) {
                integers.add(random.nextInt(20) + 1);
            }
            return integers;
        });

        Calendar obj3 = getObj(() -> {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, 2018);
            calendar.set(Calendar.MONTH, 3);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            return calendar;
        });
        System.out.println(obj1);
        System.out.println(obj2);
        System.out.println(obj3.getTime());
    }
}

练习十:Consumer接口使用
1.    给出测试类中代码如下
import java.util.HashMap;
import java.util.function.Consumer;

public class Test02 {
    public static <T> void doJob(T t, Consumer<T> consumer) {
        consumer.accept(t);
    }
    public static <T> void doJob(T t, Consumer<T> consumer1, Consumer<T> consumer2) {
        consumer1.andThen(consumer2).accept(t);
    }

    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();

        //key:姓名 value:成绩
        map.put("岑小村",59);
        map.put("谷天洛",82);
        map.put("渣渣辉",98);
        map.put("蓝小月",65);
        map.put("皮几万",70);
        
    }
}
2.    分别使用lambda表达式完成以下需求
a)    打印谷天洛的分数
b)    打印最高分
c)    分别以60分和70分为及格线,打印及格的人的名字(组合型消费)
答案
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

public class Test02 {
    public static <T> void doJob(T t, Consumer<T> consumer) {
        consumer.accept(t);
    }

    public static <T> void doJob(T t, Consumer<T> consumer1, Consumer<T> consumer2) {
        consumer1.andThen(consumer2).accept(t);
    }

    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();

        //key:姓名 value:成绩
        map.put("岑小村", 59);
        map.put("谷天洛", 82);
        map.put("渣渣辉", 98);
        map.put("蓝小月", 65);
        map.put("皮几万", 70);

        //打印谷天洛的分数
        doJob(map, (m) -> System.out.println("谷天洛的分数:" + m.get("谷天洛")));

        //打印最高分
        doJob(map, (m) -> {
            Collection<Integer> values = m.values();
            Integer max = 0;
            for (Integer value : values) {
                if (value > max) {
                    max = value;
                }
            }
            System.out.println("最高分:" + max);
        });

        //打印及格的人的名字
        doJob(map, (m) -> {
            System.out.print("60分及格的人:");
            for (Map.Entry<String, Integer> entry : m.entrySet()) {
                if (entry.getValue()>=60){
                    System.out.print(entry.getKey()+" ");
                }
            }
            System.out.println();
        }, (m) -> {
            System.out.print("70分及格的人:");
            for (Map.Entry<String, Integer> entry : m.entrySet()) {
                if (entry.getValue()>=70){
                    System.out.print(entry.getKey()+" ");
                }
            }
            System.out.println();
        });
    }
}

扩展题
练习十一:综合练习
1.    定义学生类:
a)    成员变量 姓名:String name;
b)    成员变量 成绩:int score;
c)    无参及全参构造
d)    重写toString()
2.    学生信息与成绩如下:
姓名    数学
谢霆锋    85
章子怡    63
刘亦菲    77
黄晓明    33
岑小村    92
3.    在测试类中完成如下要求
a)    将五名学生添加到ArrayList集合
b)    使用Collections.sort(List<T> list, Comparator<? super T> c)方法将学生成绩从小到大进行排序(忽略非空判断)
i.    使用匿名内部类
ii.    使用Lambda表达式
iii.    使用方法引用    //tips:借助Comparator接口中静态方法comparingInt()方法
答案
Student类:
public class Student {
    private String name;
    private int score;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    public Student() {
    }
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name=\'" + name + \'\\'\' +
                ", score=" + score +
                \'}\';
    }
}
测试类:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test08 {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("谢霆锋", 85));
        list.add(new Student("章子怡", 63));
        list.add(new Student("刘亦菲", 77));
        list.add(new Student("黄晓明", 33));
        list.add(new Student("岑小村", 92));

        //使用匿名内部类将成绩从小到大排序
        /*Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                //  忽略非空判断
                return o1.getScore() - o2.getScore();
            }
        });*/

        //使用Lambda为英语成绩从小到大排序
        //Collections.sort(list,(o1, o2) -> o1.getScore()-o2.getScore());
        
        //借助comparingInt()使用方法引用
        Collections.sort(list, Comparator.comparingInt(Student::getScore));

System.out.println(list);
        
    }
}
基础题
    练习一:Pedicate接口使用
1.    请在测试类main方法中完成以下需求
已知有Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213}
a)    使用lambda表达式创建Predicate对象p1,p1能判断整数是否是自然数(大于等于0)
b)    使用lambda表达式创建Predicate对象p2,p2能判断整数的绝对值是否大于100
c)    使用lambda表达式创建Predicate对象p3,p3能判断整数是否是偶数
    
    遍历arr,仅利用已创建的Predicate对象(不使用任何逻辑运算符),完成以下需求
i.    打印自然数的个数
ii.    打印负整数的个数
iii.    打印绝对值大于100的偶数的个数
iv.    打印是负整数或偶数的数的个数

答案
import java.util.function.Predicate;
public class Test03 {
    public static void main(String[] args) {
        Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213};

        //a)   使用lambda表达式创建Predicate对象p1,p1能判断整数是否是自然数
        Predicate<Integer> p1 = (s) -> s>=0;
        //b)   使用lambda表达式创建Predicate对象p2,p2能判断整数的绝对值是否大于100
        Predicate<Integer> p2 = (s) -> Math.abs(s)>100;
        //c)   使用lambda表达式创建Predicate对象p3,p3能判断整数是否是偶数
        Predicate<Integer> p3 = (s) -> s%2==0;

        //e)   遍历arr,仅利用已创建的Predicate对象(不使用任何逻辑运算符),完成以下需求
        int count1 = 0;
        int count2 = 0;
        int count3 = 0;
        int count4 = 0;
        for (Integer i : arr) {
            //统计自然数个数
            if (p1.test(i)){
                count1++;
            }
            //统计负整数个数
            if (p1.negate().test(i)){
                count2++;
            }
            //统计绝对值大于100的偶数个数
            if (p2.and(p3).test(i)){
                count3++;
            }
            //统计是负整数或偶数的数的个数
            if (p1.negate().or(p3).test(i)){
                count4++;
            }
        }
        //分别打印结果
        System.out.println("自然数的个数为:"+count1);
        System.out.println("负整数的个数为:"+count2);
        System.out.println("绝对值大于100的偶数的个数为:"+count3);
        System.out.println("是负整数或偶数的数的个数为:"+count4);
    }
}
    练习二:Function接口使用
1.    使用lambda表达式分别将以下功能封装到Function对象中
a)    求Integer类型ArrayList中所有元素的平均数
b)    将Map<String,Integer>中value存到ArrayList<Integer>2.    已知学生成绩如下
姓名    成绩
岑小村    59
谷天洛    82
渣渣辉    98
蓝小月    65
皮几万    70
3.    以学生姓名为key成绩为value创建集合并存储数据,使用刚刚创建的Function对象求学生的平均成绩

答案
import java.util.*;
import java.util.function.Function;
public class Test04 {
    public static void main(String[] args) {
        //1.   使用lambda表达式分别将以下功能封装到Function对象中
        //a)   求Integer类型ArrayList中所有元素的平均数
        Function<ArrayList<Integer>,Integer> f1 = (list)->{
            Integer sum = 0;
            for (Integer i : list) {
                sum+=i;
            }
            return sum/list.size();
        };

        //b)   将Map<String,Integer>中value存到ArrayList<Integer>中
        Function<Map<String,Integer>,ArrayList<Integer>> f2 = (map)->{
            /*ArrayList<Integer> list = new ArrayList<>();
            for (String s : map.keySet()) {
                Integer i = map.get(s);
                list.add(i);
            }*/
            Collection<Integer> values = map.values();
            ArrayList<Integer> list = new ArrayList<>();
            list.addAll(values);
            return list;
        };
        
        //2 将学生姓名和成绩封装到map中
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("岑小村", 59);
        map.put("谷天洛", 82);
        map.put("渣渣辉", 98);
        map.put("蓝小月", 65);
        map.put("皮几万", 70);

        //利用Function求平均成绩
        Integer avg = f2.andThen(f1).apply(map);
        System.out.println("学生平均成绩为:"+avg);
    }
}

    练习三:如何获取流
问题:
简述单列集合、双列集合、数组分别如何获取Stream流对象,并进行演示

答:
1、java.util.Collection接口中加入了default方法stream()获取流对象,因此其所有实现类均可通过此方式获取流。
2、java.util.Map接口想要获取流,先通过keySet()、values()或entrySet()方法获取键、值或键值对的单列集合,再通过stream()获取流对象。
3、数组获取流,使用Stream接口中的的静态方法of(T...values)获取流。
public static void main(String[] args) {
  List<String> list = new ArrayList<>();
  Stream<String> stream1 = list.stream();

  Set<String> set = new HashSet<>();
  Stream<String> stream2 = set.stream();

  Map<String, String> map = new HashMap<>();
  Stream<String> keyStream = map.keySet().stream();
  Stream<String> valueStream = map.values().stream();
  Stream<Map.Entry<String,String>>entryStream = map.entrySet().stream();

  String[] array = {"东邪", "西毒", "南帝", "北丐", "中神通"};
  Stream<String> stream = Stream.of(array);
 }

    练习四:过滤:filter、结果收集(数组)
问题:
有如下7个元素黄药师,冯蘅,郭靖,黄蓉,郭芙,郭襄,郭破虏,使用Stream将以郭字开头的元素存入新数组

答:
import java.util.stream.Stream;
public class Test {
    public static void main(String[] args) {
          Stream<String> stream = Stream.of("黄药师", "冯蘅", "郭靖", "黄蓉", "郭芙", "郭襄", "郭破虏");
        String[] guos = stream.filter(s -> s.startsWith("郭")).toArray(String[]::new);
     }
}

    练习五:取用前几个:limit、跳过前几个:skip
问题:
已知ArrayList集合中有如下元素{陈玄风、梅超风、陆乘风、曲灵风、武眠风、冯默风、罗玉风},使用Stream
1、取出前2个元素并在控制台打印输出。
2、取出后2个元素并在控制台打印输出。

答:
import java.util.ArrayList;
public class Test04 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("陈玄风");
        list.add("梅超风");
        list.add("陆乘风");
        list.add("曲灵风");
        list.add("武眠风");
        list.add("冯默风");
        list.add("罗玉风");

        list.stream().limit(2).forEach(System.out::println);
        list.stream().skip(list.size() - 2).forEach(System.out::println);
    }
}

    练习六:映射:map、逐一消费:forEach
问题:
有如下整数1,-2,-3,4,-5
使用Stream取元素绝对值并打印
    
答:
import java.util.stream.Stream;
public class Test {
    public static void main(String[] args) {
          Stream<Integer> stream = Stream.of(1, -2, -3, 4,-5);
        stream.map(Math::abs).forEach(System.out::println);
     }
}

    练习七:组合:concat、结果收集(list)
问题:
已知数组arr1中有如下元素{郭靖,杨康},arr2中有如下元素{黄蓉,穆念慈},使用Stream将二者合并到List集合

答:
import java.util.stream.Stream;
public class Test {
    public static void main(String[] args) {
          Stream<String> streamA = Stream.of("郭靖", "杨康");
        Stream<String> streamB = Stream.of("黄蓉", "穆念慈");
        List<String> strList = Stream.concat(streamA, streamB).collect(Collectors.toList());
     }
}
    练习八:获取并发流
问题:
请分别写出获取并发流的两种方式。

答:
public class Test {
    public static void main(String[] args) {
          Collection<String> coll = new ArrayList<>();
          Stream<String> parallelStream1 = coll.parallelStream();
        Stream<Integer> parallelStream2 = Stream.of(100, 200, 300, 400).parallel();
     }
}
扩展题
    练习九:Stream综合练习
问题:
现在有两个 ArrayList 集合存储队伍当中的多个成员姓名,要求使用Stream方式进行以
下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前6个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前1个人;
5. 将两个队伍合并为一个队伍;
6. 根据姓名创建Student对象;
7. 打印整个队伍的Student对象信息。

两个队伍(集合)的代码如下: 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class Test {
public static void main(String[] args) {
  List<String> one = new ArrayList<>();
  one.add("陈玄风");
  one.add("梅超风");
  one.add("陆乘风");
  one.add("曲灵风");
  one.add("武眠风");
  one.add("冯默风");
  one.add("罗玉风");
  List<String> two = new ArrayList<>();
  two.add("宋远桥");
  two.add("俞莲舟");
  two.add("俞岱岩");
  two.add("张松溪");
  two.add("张翠山");
  two.add("殷梨亭");
  two.add("莫声谷");
 }
}
而Student类的代码为:
public class Student {
private String name;

public Student() {
 }

public Student(String name) {
this.name = name;
 }

@Override
public String toString() {
return " Student {name=\'" + name + "\'}";
 }

public String getName() {
return name;
 }

public void setName(String name) {
this.name = name;
 }

}




答:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Test {
    public static void main(String[] args) {
          List<String> one = new ArrayList<>();
          one.add("陈玄风");
          one.add("梅超风");
           one.add("陆乘风");
          one.add("曲灵风");
           one.add("武眠风");
          one.add("冯默风");
           one.add("罗玉风");
           List<String> two = new ArrayList<>();
          two.add("宋远桥");
          two.add("俞莲舟");
         two.add("俞岱岩");
          two.add("张松溪");
          two.add("张翠山");
          two.add("殷梨亭");
          two.add("莫声谷");

        // 第一个队伍只要名字为3个字的成员姓名;
        // 第一个队伍筛选之后只要前6个人;
        Stream<String> streamOne = one.stream().filter(s -> s.length() == 3).limit(6);

        // 第二个队伍只要姓张的成员姓名;
        // 第二个队伍筛选之后不要前1个人;
        Stream<String> streamTwo = two.stream().filter(s -> s.startsWith("张")).skip(1);

        // 将两个队伍合并为一个队伍;
        // 根据姓名创建Student对象;
        // 打印整个队伍的Student对象信息。
    Stream.concat(streamOne,streamTwo).map(Student::new).forEach(System.out::println);
 }
}
    练习十:Stream综合练习
问题:
以下是某不知名机构评出的全球最佳影片及华人最佳影片前十名 : 
全球
  1、 《教父》
  2、 《肖申克的救赎》
  3、 《辛德勒的名单》
  4、 《公民凯恩》
  5、 《卡萨布兰卡》 
  6、 《教父续集》
  7、 《七武士》
  8、 《星球大战》
  9、 《美国美人》
  10、 《飞跃疯人院》
 
华人
   1、 《霸王别姬》
  2、 《大闹天宫》
  3、 《鬼子来了》
  4、 《大话西游》
  5、 《活着》
  6、 《饮食男女》
  7、 《无间道》
  8、 《天书奇谭》
  9、 《哪吒脑海》
  10、 《春光乍泄》


1、现将两个榜单中的影片名,分别按排名顺序依次存入两个ArrayList集合
2、通过流的方式
    1)打印全球影片排行榜中的前三甲影片名
    2)打印华人影片排行榜中倒数5名的影片名
    3)将两个排行榜中的前5名挑出来共同存入新的集合
    4)定义电影Film类,以影片名为name创建Film对象并保存至集合


答:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Test03 {
    public static void main(String[] args) {
        //将原始数据存入集合
        ArrayList<String> global = new ArrayList<>();
        global.add("《教父》");
        global.add("《肖申克的救赎》");
        global.add("《辛德勒的名单》");
        global.add("《公民凯恩》");
        global.add("《卡萨布兰卡》");
        global.add("《教父续集》");
        global.add("《七武士》");
        global.add("《星球大战》");
        global.add("《美国美人》");
        global.add("《飞跃疯人院》");
        ArrayList<String> china = new ArrayList<>();
        china.add("《霸王别姬》");
        china.add("《大闹天宫》");
        china.add("《鬼子来了》");
        china.add("《大话西游》");
        china.add("《活着》");
        china.add("《饮食男女》");
        china.add("《无间道》");
        china.add("《天书奇谭》");
        china.add("《哪吒脑海》");
        china.add("《春光乍泄》");

        //1)打印全球影片排行榜中的前三甲影片名
        global.stream().limit(3).forEach(System.out::println);

        //2)打印华人影片排行榜中倒数5名的影片名
        china.stream().skip(china.size()-5).forEach(System.out::println);

        //3)将两个排行榜中的前5名挑出来共同存入新的集合
        List<String> list = Stream.concat(global.stream().limit(5), china.stream().limit(5)).collect(Collectors.toList());

        //4)将所有影片以影片名为name创建Film对象并保存至集合
        List<Film> filmList = Stream.concat(global.stream(), china.stream()).map(Film::new).collect(Collectors.toList());
    }
}

public class Film {
    private String name;
    public Film() {
    }
    public Film(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

    练习十一:Stream综合练习
问题:
我国有34个省级行政区,分别是:
23个省:
河北省、山西省、吉林省、辽宁省、黑龙江省、陕西省、甘肃省、青海省、山东省、福建省、
浙江省、台湾省、河南省、湖北省、湖南省、江西省、江苏省、安徽省、广东省、海南省、四川省、贵州省、云南省。
4个直辖市:
北京市、天津市、上海市、重庆市。
5个自治区:
内蒙古自治区、新疆维吾尔自治区、宁夏回族自治区、广西壮族自治区、西藏自治区。
2个特别行政区:
香港特别行政区、澳门特别行政区。

使用流:
1、统计三个字的省份的个数
2、统计名字中包含方位名词的省份(东西南北)的个数
3、打印名字中包含方位名词的普通省份(非自治区直辖市特别行政区)的名字
4、将所有的特殊省份(自治区直辖市特别行政区)提取出来并放到新数组中

答:
import java.util.Arrays;
import java.util.stream.Stream;
public class Test02 { 
    public static void main(String[] args) {
        String[] provinces = {"河北省", "山西省", "吉林省", "辽宁省",
                "黑龙江省", "陕西省", "甘肃省", "青海省", "山东省", "福建省", "浙江省",
                "台湾省", "河南省", "湖北省", "湖南省", "江西省", "江苏省", "安徽省",
                "广东省", "海南省", "四川省", "贵州省", "云南省", "北京市", "天津市",
                "上海市", "重庆市", "内蒙古自治区", "新疆维吾尔自治区", "宁夏回族自治区",
                "广西壮族自治区", "西藏自治区", "香港特别行政区", "澳门特别行政区"};

        //1、统计三个字的省份的个数
        long threeCount = Stream.of(provinces).filter(s -> s.length() == 3).count();
        System.out.println("三个字的省份的个数:"+threeCount);

        //2、统计名字中包含方位名词的省份(东西南北)的个数
        long count = Stream.of(provinces).filter(s -> s.contains("东") || s.contains("西") || s.contains("南") || s.contains("北")).count();
        System.out.println("包含方位名词的省份(东西南北)的个数:"+count);

        //3、打印名字中包含方位名词的普通省份(非自治区直辖市特别行政区)的名字
        System.out.println("包含方位名词的普通省份有:");
        Stream.of(provinces).filter(s -> s.contains("东") || s.contains("西") || s.contains("南") || s.contains("北")).filter(s->s.contains("省")).forEach(System.out::println);

        //4、将所有的特殊省份(自治区直辖市特别行政区)提取出来并放到新数组中
        String[] pros = Stream.of(provinces).filter(s -> !s.contains("省")).toArray(String[]::new);
        System.out.println("新数组:"+Arrays.toString(pros));
    }
}

 

分类:

技术点:

相关文章: