【Java基础16】不可变集合、Stream流和异常

1. 不可变集合

不可以改变的集合,在整个使用的生命周期中,自创建后集合就不变,尝试修改会报错
。实现的原因,更好的防御和被不信任库调用时,不可变的形式会更安全。

1.1 创建

在List、Set和Map这些接口中都提供了静态方法of来进行创建,创建出的集合不可修
改、新增和删除。

public class Demo {
    public static void main(String[] args) {
        // 创建不可变List
        List<Integer> lisOf = List.of(1, 2, 3, 4);
        // 只可以获取,不可以删,改和增
        System.out.println(lisOf.get(0));

        // 2、不可变的Set集合,jdk版本需要高于8
        // Set<String> names = Set.of("迪丽热巴", "迪丽热九", "马尔扎哈", "卡尔眨巴" );
        // names.add("三少爷");
        // System.out.println(names);

        // 3、不可变的Map集合,jdk版本需要高于8
        // Map<String, Integer> maps = Map.of("huawei",2, "Java开发", 1 , "手表", 1);
        // maps.put("衣服", 3);
        // System.out.println(maps);

    }
}

复制代码

2. Stream流

在JDK8之后,得益于Lambda表达式的函数式编程,引入了Stream流。它简化了集合
和数值的操作。

// 示例
public class StreamTest {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "李小龙", "成龙", "李连杰", "李莲英", "叶问", "沈腾");

        // 传统方法
        System.out.println("传统方法");
        for (int i = 0; i < arrayList.size(); i++) {
            String s = arrayList.get(i);
            if (s.startsWith("李") && s.length() >= 3) {
                System.out.println(s);
            }
        }

        // Stream流方法
        System.out.println("Stream流方式");
        Stream<String> stream = arrayList.stream();
        stream.filter(s -> s.startsWith("李")).filter(s -> s.length() >= 3).forEach(s -> System.out.println(s));
    }
}

复制代码

2.1 Stream流的创建

流在使用过成功,总共有三个阶段:

  • 获得流:获得操作集合和数值的’流水线’
  • 中间操作:类似’流水线’上的操作,操作之后还可以继续后面的操作
  • 终结方法:一个流水线只有一个终结方法,此方法一旦执行,流水线就会停止。

2.1.1 获得Stream流

获得数组和集合的Stream流

  1. 获得集合流
// 在集合中Collection默认方法,此方法1.8之后加入
default Stream<E> stream()

复制代码
public class StreamDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        HashSet<String> set = new HashSet<>();
        HashMap<Object, Object> map = new HashMap<>();
        
        // 获得集合Stream流
        Stream<String> stream = list.stream();
        Stream<String> stream1 = set.stream();
        Stream<Object> stream2 = map.keySet().stream();
        Stream<Object> stream3 = map.values().stream();
    }
}

复制代码
  1. 获得数组流
public class StreamDemo2 {
    public static void main(String[] args) {
        String[] str = {"张三", "李四", "王二"};

        // 获得数组流
        Stream<String> stream1 = Arrays.stream(str);
        Stream<String> stream2 = Stream.of("张三", "李四", "王二");
    }
}

复制代码

2.1.2 中间操作

// 常用方法

// 去除流中重复元素
Stream<T> distinct()
// 获取流前指定元素
Stream<T> limit(long maxSize)
// 跳过指定元素
Stream<T> skip(long n)
// 过滤流指定数据
Stream<T> filter(Predicate<? super T> predicate)
// 合并两个流
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
// 对流进行加工 
<R> Stream<R> map(Function<? super T,? extends R> mapper)

复制代码
// 示例
public class StreamDemo3 {
    public static void main(String[] args) {
        // 创建数组
        Integer[] x = {0, 1, 3, 5, 7, 9, 11}, y = {9, 2, 4, 6, 8};

        // 创建数组流
        Stream<Integer> x1 = Stream.of(x);
        Stream<Integer> y1 = Stream.of(y);

        Stream<Integer> concat = Stream.concat(x1, y1);
        // 跳过前4个、取前6个、过滤数值大于等于5、去重和结果值乘10,然后打印流内容结束
        concat.skip(4).limit(6)
                .filter(i -> i >= 5)
                .distinct()
                .map(i -> i * 10)
                .forEach(i -> System.out.println(i));
    }
}

复制代码
  • 以上方法为非终结方法,操作流后不会被关闭,流支持链式编程
  • 在Stream流中无法修改集合或者数组数据,但是可以通过类似map方法进行加工

2.1.3 终结方法

可以通过终结方法终结流的操作,非终结方法可以继续链式操作,终结方法不支持。

// 常用方法

// 循环流元素
void forEach(Consumer<? super T> action)
// 统计流大小
long count()

复制代码

2.1.4 Stream流数据收集

一些操作后需要获得流中数据,转换成集合或数组。

// 常用方法

// 转换成数组
<A> A[] toArray(IntFunction<A[]> generator)
// 转换成集合 
<R,A> R collect(Collector<? super T,A,R> collector)

复制代码
public class StreamDemo3 {
    public static void main(String[] args) {
        // 创建数组
        Integer[] x = {0, 1, 3, 5, 7, 9, 11, 9, 2, 4, 6, 8};

        // 获得流
        Stream<Integer> stream = Arrays.stream(x);
        // 流转换成List集合
        List<Integer> list = stream.filter(i -> i >= 5).collect(Collectors.toList());
        // 流转换成Set集合
        Set<Integer> set = stream.collect(Collectors.toSet());
        // 流转换成数组
        Integer[] array = stream.toArray(value -> new Integer[0]);
    }
}

复制代码

3. 异常

异常是程序在’执行’或’编译’期出现的问题,比如越界和空指针问题。一旦出现异常
jvm就会退出执行,所有要提前处理异常,增加程序健壮性和安全性。

3.1 异常体系

异常体系主要如下:

1.png

  1. Error:系统级别异常,代码无序控制
  2. Excrption:
    • RuntimeException及其子类:运行时异常,编译时不会。
    • 除以上异常:编译时异常,必须处理否则程序编译不通过,程序无法进行运行

程序编写在后缀为java的文件中 -> 使用javac命令编译文件成class(有编译异
常此时将不会通过) -> 使用java命令运行字节码文件(如果程序有运行时异常将
终止程序报错) -> 运行结束

3.2 异常处理

3.2.1 系统默认处理

  1. 程序会在出现异常的地方,默认创建一个异常对象:ArithmeticException
  2. 从出现异常的地点将异常抛给调用者,调用者抛给jvm虚拟机
  3. 虚拟机在接收到异常后,将在控制台上显示异常信息
  4. 从出现异常地点将程序终止

这种处理是被动的,出现异常程序就结束。

3.2.2 手动处理

3.2.2.1 throws

此种方法是把可能出现的异常抛给调用者

// 格式一
修饰符 返回值 方法(形参列表) throws 异常类名{
}

// 格式二 
throw new 异常类名(实参);

复制代码

3.2.2.1 try…catch…

此种方法是捕获可能出现的异常,如果出现异常,程序猿可以自己处理。

// 格式一
try{
     ...    
} catch (异常类 变量名) {
     ...
}

// 格式二
try{
    ...
} catch (异常类 变量名1) {
    ...
} catch (异常类 变量名2) {
    ...
}

// 格式二
try{
    ...
} catch (异常类 变量名1) {
    ...
} finally {
    ...
}

复制代码
public class TrcatchTest {
    public static void main(String[] args) {
        try {
            int x = 1 / 0;
        } catch (Exception e) {
            // 获得异常信息
           System.out.println("异常信息:" + e.getMessage());
           // 处理异常代码
        }
        System.out.println("继续后面的的操作...");
    }
}

public class TrcatchTest1 {
   public static void main(String[] args) {
      try {
         int x = 1 / 0;
      } catch (Exception e) {
         // 获得异常信息
         System.out.println("异常信息:" + e.getMessage());
         // 处理异常代码
      }finally {
         System.out.println("这个程序始终会执行");
      }
      System.out.println("继续后面的的操作...");
   }
}

复制代码

3.2.2.2 混合双打

可自己抛出异常,然后自己捕获异常处理。这样就可以集体处理异常。

// 示例
public class TrcatchTest2 {
   public static void main(String[] args) {
      try {
         exceptionTest();
      } catch (Exception e) {
         // 下面是默认处理异常的方法
         // e.printStackTrace();
         System.out.println(e.getMessage());
      }
   }

   // 将异常抛出去
   public static void exceptionTest() throws Exception {
      // 假装出现异常
      throw new Exception("出现异常");
   }
}

复制代码

3.3 自定义异常

程序不可能把全部异常创建出,这时我们就要个性化创建异常。这样的话出现异常,
由于是自定义异常,所有异常处理较好。

3.3.1 自定义编译时异常

  1. 继承Exception
  2. 重写构造器
  3. 在出现异常地方throw new 异常类(实参)
// 示例
public class ExceptioTest extends Exception {
   public ExceptioTest() {
   }
   public ExceptioTest(String message) {
      super(message);
   }
}

public class TrcatchTest3 {
   public static void main(String[] args) {
      try {
         exceptionTest();
      } catch (Exception e) {
         // 下面是默认处理异常的方法
         // e.printStackTrace();
         System.out.println(e.getMessage());
      }
   }
   public static void exceptionTest() throws Exception {
      // 假装出现异常
      throw new ExceptioTest("出现异常");
   }
}

复制代码

3.3.2 自定义运行时异常

  1. 继承RuntimeException
  2. 重写构造器
  3. 在出现异常地方throw new 异常类(实参)
public class RuntimeExceptionTest extends RuntimeException {
   public RuntimeExceptionTest() {
   }

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

public class TrcatchTest3 {
   public static void main(String[] args) {
      try {
         exceptionTest();
      } catch (Exception e) {
         // 下面是默认处理异常的方法
         // e.printStackTrace();
         System.out.println(e.getMessage());
      }
   }
   public static void exceptionTest() throws Exception {
      // 假装出现异常
      throw new ExceptioTest("出现异常");
   }
}

复制代码

本章结束,用于个人学习和小白入门,大佬勿喷!希望大家多多点赞收藏支撑支撑!

源码 【GitHub】 【码云】

おすすめ

転載: juejin.im/post/7047315138289860645