【问题标题】:Java anonymous inner class declarationJava匿名内部类声明
【发布时间】:2023-06-21 11:20:01
【问题描述】:

如何将匿名内部类与构造函数块分开定义?

例如在我的代码中,我希望 method2 与 method1 做同样的事情,唯一的区别是 method2 使用 Factory 类来创建 ClosableResultSet。

import java.sql.*;

public class Demo {

    public static void main(String[] args) {
        method1();
        method2();  
    }

    static void method1() {

        Connection conn;
        try {
            conn = DriverManager.getConnection("jdbc:h2:C:/myDB", "sa", "sa");

            String sql = "select * from Customers";

            try (ClosableResultSet rs = new ClosableResultSet(conn, sql) {
                @Override
                public void handleError(SQLException e, String action) {
                    System.out.print(action + ": " + e.getMessage());       
                }               
            }) {
                while (rs.next()) {
                    System.out.print("Name: " + rs.getString("name") + "\n");
                }
            }

        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }               

    }


    static void method2() {

        String sql = "select * from Customers";

        //here has the syntax errors    
        try (ClosableResultSet rs = Factory.createResultSet(sql) {
            @Override
            public void handleError(SQLException e, String action) {
                System.out.print(action + ": " + e.getMessage());           
            }               
        }) {
            while (rs.next()) {
                System.out.print("Name: " + rs.getString("name") + "\n");
            }


        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }           

    }   
}



import java.sql.*;

public class Factory {
    public static ClosableResultSet createResultSet(String sql) throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:h2:C:/myDB", "sa", "sa");

        return new ClosableResultSet(conn, sql);
    }
}


import java.sql.*;

public class ClosableResultSet implements java.io.Closeable {

    private ResultSet rs;

    public ClosableResultSet(Connection conn, String sql) throws SQLException  {
        Statement stmt = conn.createStatement();
        rs = stmt.executeQuery(sql);    
    }

    public Boolean next() {
        try {
            return rs.next();
        } catch (SQLException e) {
            handleError(e, "next");
            return false;
        }
    }

    public String getString(String columnLabel) {
        try {
            return rs.getString(columnLabel);
        } catch (SQLException e) {
            handleError(e, "get " + columnLabel);
            return "";
        }
    }


    @Override
    public void close() {       
        try {
            rs.close();
        } catch (SQLException e) {
            handleError(e, "close");
        }

    }

    public void handleError(SQLException e, String action) {
        // to be override   
    }

}

我不想在Factory类中声明匿名内部类,是否有任何lambda表达式允许我将其放入method2中?

【问题讨论】:

    标签: java anonymous-inner-class


    【解决方案1】:

    除了String sql 之外,您还可以创建另一个Factory 方法,该方法采用BiConsumer。像这样的:

    import java.sql.*;
    import java.util.function.BiConsumer;
    
    public class Factory {
    
        public static ClosableResultSet createResultSet(String sql) throws SQLException {
            Connection conn = DriverManager.getConnection("jdbc:h2:C:/myDB", "sa", "sa");
    
            return new ClosableResultSet(conn, sql);
        }
    
        public static ClosableResultSet createResultSet(String sql, BiConsumer<SQLException, String> handler) throws SQLException {
            Connection conn = DriverManager.getConnection("jdbc:h2:C:/myDB", "sa", "sa");
    
            return new ClosableResultSet(conn, sql) {
                @Override
                public void handleError(SQLException e, String action) {
                    handler.accept(e, action);
                }
            };
        }
    }
    

    然后你的method2 应该是:

    static void method2() {
    
        String sql = "select * from Customers";
    
        try (ClosableResultSet rs = Factory.createResultSet(
                sql,
                (e, action) -> System.out.print(action + ": " + e.getMessage())
        )) {
            while (rs.next()) {
                System.out.print("Name: " + rs.getString("name") + "\n");
            }
    
        } catch (SQLException e) {
            e.printStackTrace();
        }
    
    }
    

    【讨论】:

    • 让Factory覆盖handleError不太好。我只是将 BiConsumer 处理程序传递给 ClosableResultSet 类。
    【解决方案2】:

    是的,你可以这样做:

    import java.sql.*;
    
    public class Demo {
    
        public static void main(String[] args) {
            method1();
            method2();  
        }
    
        static void method1() {
    
            Connection conn;
            try {
                conn = DriverManager.getConnection("jdbc:h2:C:/myDB", "sa", "sa");
    
                String sql = "select * from Customers";
    
                try (ClosableResultSet rs = new ClosableResultSet(conn, sql) {
                    @Override
                    public void handleError(SQLException e, String action) {
                        System.out.print(action + ": " + e.getMessage());       
                    }               
                }) {
                    while (rs.next()) {
                        System.out.print("Name: " + rs.getString("name") + "\n");
                    }
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }               
        }
    
        static void method2() {
    
            String sql = "select * from Customers";
    
            //here has the syntax errors
            try (ClosableResultSet rs = Factory.createResultSet(
                    sql, (e, action) -> System.out.print(action + ": " + e.getMessage())
            )) {
                while (rs.next()) {
                    System.out.print("Name: " + rs.getString("name") + "\n");
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    ...
    
    import java.sql.*;
    
    public class Factory {
            public static ClosableResultSet createResultSet(String sql, final ErrorHandller errorHandller) throws SQLException {
            Connection conn = DriverManager.getConnection("jdbc:h2:C:/myDB", "sa", "sa");
    
            return new ClosableResultSet(conn, sql) {
                @Override
                public void handleError(SQLException e, String action) {
                    errorHandller.handleError(e, action);
                }
            };
        }
    
        interface ErrorHandller {
            void handleError(SQLException e, String action);
        }
    }
    
    ...
    

    如您所见,添加了新接口ErrorHandller。现在Factory::createResultSet 接收ErrorHandller 的实例作为第二个参数。 然后在 Demo::method2 中,我们将 lambda 作为 Factory.createResultSet 方法的第二个参数传递。

    【讨论】: