如何在java中创建自定义编译器警告?

如何在java中创建自定义编译器警告?,java,concurrency,semaphore,compiler-warnings,Java,Concurrency,Semaphore,Compiler Warnings,我正在寻找类似于实现java.lang.AutoCloseable接口的东西,其中会生成一个编译器警告,指示资源泄漏:“xxxx”从未关闭 这个用例在java中的同步集合的包装器中。包装器有一个内部信号量来防止并发修改集合 它允许对集合进行原子操作,在这种情况下,信号量是在内部获取和释放的。它还允许从外部获取锁,从而提供一个唯一的密钥,可以使用该密钥对集合执行操作。必须在“交易”结束时释放密钥 我的目标是在同一方法中获取锁而不是释放锁时创建编译器警告,以防止死锁。也可接受可防止出现这种情况的替代

我正在寻找类似于实现java.lang.AutoCloseable接口的东西,其中会生成一个编译器警告,指示
资源泄漏:“xxxx”从未关闭

这个用例在java中的同步集合的包装器中。包装器有一个内部信号量来防止并发修改集合

它允许对集合进行原子操作,在这种情况下,信号量是在内部获取和释放的。它还允许从外部获取锁,从而提供一个唯一的密钥,可以使用该密钥对集合执行操作。必须在“交易”结束时释放密钥

我的目标是在同一方法中获取锁而不是释放锁时创建编译器警告,以防止死锁。也可接受可防止出现这种情况的替代设计解决方案


这是一个有趣的小问题,因此我非常感谢您对它的深入了解。

为了创建编译器警告,您需要扩展Eclipse编译器


另一种解决方案是在软件质量分析系统中创建自定义检查,如TeamscaleSonarQube。自定义检查对代码执行静态分析(通常基于富含语义信息的抽象语法树),并在检测到可疑代码时产生问题。这些问题显示在质量分析系统的用户界面上。Eclipse插件允许在Eclipse中集成系统,以便也可以在那里列出问题。

为了创建编译器警告,您需要扩展Eclipse编译器

另一种解决方案是在软件质量分析系统中创建自定义检查,如TeamscaleSonarQube。自定义检查对代码执行静态分析(通常基于富含语义信息的抽象语法树),并在检测到可疑代码时产生问题。这些问题显示在质量分析系统的用户界面上。Eclipse插件允许在Eclipse中集成系统,这样问题也可以列在那里。

如您所说

也可接受可防止出现这种情况的替代设计解决方案

这就是:作为替代设计解决方案,使用函数式编程

与其找出错误,为什么不首先阻止错误的发生

由于缺乏源代码,我对您的代码做了一些假设:

  • Semaphore
    是向
    SynchronizedCollection
    提供信号量的类(或接口)
  • Semaphore
    提供了两种方法
    get()
    release()
你实际上面临的问题是国家责任的问题。导致时间耦合的状态变化<代码>获取()
发布()
必须按顺序调用。您可以使用函数式编程中的元素作为替代设计

信号灯当前看起来如下所示:

public class Sempahore {
    // ...
    public void obtain() {
        // Lock code
    }
    public void release() {
        // Release code
    }
}
semaphore.obtain();
// Code protected by the Sempahore.
semaphore.release();
public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V> void protect(final Callable<V> c) throws Exception {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
semaphore.protect(() -> {
    // Code protected by the Semaphore.
});
public interface ProtectedCode<V,E> {
    V call() throws E;
}

public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V, E> void protect(final ProtectedCode<V, E> c) throws E {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
信号灯
用户当前的外观如下:

public class Sempahore {
    // ...
    public void obtain() {
        // Lock code
    }
    public void release() {
        // Release code
    }
}
semaphore.obtain();
// Code protected by the Sempahore.
semaphore.release();
public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V> void protect(final Callable<V> c) throws Exception {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
semaphore.protect(() -> {
    // Code protected by the Semaphore.
});
public interface ProtectedCode<V,E> {
    V call() throws E;
}

public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V, E> void protect(final ProtectedCode<V, E> c) throws E {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
解决方案是将
get()
release()
组合到一个函数中,该函数将要保护的代码作为其参数。这种技术也被称为传递一个块,或者更正式地称为一个高阶函数——一个将另一个函数作为参数或返回另一个函数的函数

Java也有函数指针,不是直接的,而是通过接口引用间接的。自Java 8以来,只有一个抽象方法的接口甚至被称为Functional interface,Java 8为此提供了可选的注释
@Functional interface

因此,您的
类Sempahore
可以如下所示:

public class Sempahore {
    // ...
    public void obtain() {
        // Lock code
    }
    public void release() {
        // Release code
    }
}
semaphore.obtain();
// Code protected by the Sempahore.
semaphore.release();
public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V> void protect(final Callable<V> c) throws Exception {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
semaphore.protect(() -> {
    // Code protected by the Semaphore.
});
public interface ProtectedCode<V,E> {
    V call() throws E;
}

public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V, E> void protect(final ProtectedCode<V, E> c) throws E {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
关于这个解决方案的怪癖 Java在这个上下文中有一个方面非常糟糕:异常处理。对于函数式编程,迫切需要解决这个问题,但Oracle没有。我仍然希望使用Java9,但这并不能帮助像
Java.util.stream
这样已经存在于野外的破API。Java8仍然维护已检查异常的句柄或声明规则,但函数式编程没有很好地考虑到这一点

有几种解决方法:

  • 如果不需要返回值,请使用
    Runnable
  • 使用您自己的
    Callable
    接口,该接口为异常声明一个类型参数
我打赌使用
Runnable
是直截了当的,不言自明的,因此我不会详细说明

使用您自己版本的
Callable
界面如下所示:

public class Sempahore {
    // ...
    public void obtain() {
        // Lock code
    }
    public void release() {
        // Release code
    }
}
semaphore.obtain();
// Code protected by the Sempahore.
semaphore.release();
public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V> void protect(final Callable<V> c) throws Exception {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
semaphore.protect(() -> {
    // Code protected by the Semaphore.
});
public interface ProtectedCode<V,E> {
    V call() throws E;
}

public class Semaphore {
    // ...
    private void obtain() {
        // Lock code
    } 
    private void release() {
        // Release code
    }
    public <V, E> void protect(final ProtectedCode<V, E> c) throws E {
        obtain();
        try {
            return c.call();
        } finally {
            release();
        }
    }
}
公共接口受保护的代码{
V call()抛出E;
}
公共类信号量{
// ...
私有无效获取(){
//锁码
} 
私人无效释放(){
//发布代码
}
公共无效保护(最终保护代码c)抛出E{
获得();
试一试{
返回c.call();
}最后{
释放();
}
}
}
现在,只要类型参数
E
的有限类型推断(因为它只能反映一种类型,而不是一个类型集)在编译器中产生合理的结果,就不需要处理异常

如果您想对用户非常友好,实际上可以提供三种
protect
方法:

  • 公共无效保护(最终可运行r)
  • public V protect(最终可调用c)引发异常
  • public V protect(最终保护代码c)抛出E
  • 正如你所说的

    替代品