java compare null,如何简化一个null安全的compareTo()实现?

I'm implementing compareTo() method for a simple class such as this (to be able to use Collections.sort() and other goodies offered by the Java platform):

public class Metadata implements Comparable {

private String name;

private String value;

// Imagine basic constructor and accessors here

// Irrelevant parts omitted

}

I want the natural ordering for these objects to be: 1) sorted by name and 2) sorted by value if name is the same; both comparisons should be case-insensitive. For both fields null values are perfectly acceptable, so compareTo must not break in these cases.

The solution that springs to mind is along the lines of the following (I'm using "guard clauses" here while others might prefer a single return point, but that's beside the point):

// primarily by name, secondarily by value; null-safe; case-insensitive

public int compareTo(Metadata other) {

if (this.name == null && other.name != null){

return -1;

}

else if (this.name != null && other.name == null){

return 1;

}

else if (this.name != null && other.name != null) {

int result = this.name.compareToIgnoreCase(other.name);

if (result != 0){

return result;

}

}

if (this.value == null) {

return other.value == null ? 0 : -1;

}

if (other.value == null){

return 1;

}

return this.value.compareToIgnoreCase(other.value);

}

This does the job, but I'm not perfectly happy with this code. Admittedly it isn't very complex, but is quite verbose and tedious.

The question is, how would you make this less verbose (while retaining the functionality)? Feel free to refer to Java standard libraries or Apache Commons if they help. Would the only option to make this (a little) simpler be to implement my own "NullSafeStringComparator", and apply it for comparing both fields?

Edits 1-3: Eddie's right; fixed the "both names are null" case above

解决方案

I would implement a null safe comparator. There may be an implementation out there, but this is so straightforward to implement that I've always rolled my own.

Note: Your comparator above, if both names are null, won't even compare the value fields. I don't think this is what you want.

I would implement this with something like the following:

// primarily by name, secondarily by value; null-safe; case-insensitive

public int compareTo(final Metadata other) {

if (other == null) {

throw new NullPointerException();

}

int result = nullSafeStringComparator(this.name, other.name);

if (result != 0) {

return result;

}

return nullSafeStringComparator(this.value, other.value);

}

public static int nullSafeStringComparator(final String one, final String two) {

if (one == null ^ two == null) {

return (one == null) ? -1 : 1;

}

if (one == null && two == null) {

return 0;

}

return one.compareToIgnoreCase(two);

}

EDIT: Fixed typos in code sample. That's what I get for not testing it first!

EDIT: Promoted nullSafeStringComparator to static.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.aapoint.util; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; public class LocalDateTimeUtil { /** * 比较 localDateTime2 是否在localDateTime1之前(比较大小) * @param localDateTime1 * @param localDateTime2 * @return */ public static Boolean compare(LocalDateTime localDateTime1,LocalDateTime localDateTime2){ return localDateTime1.isBefore(localDateTime2); } /** * 获取当前月份前/后的月份的第一天 * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String firstDay(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,0,i); //获取该月份的第一天 String firstDay = date.with(TemporalAdjusters.firstDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // System.out.println("第一天为:"+firstDay); return firstDay; } /** * 获取当前月份前/后的月份的最后一天 * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String lastDay(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,0,i); //获取该月份的最后一天 String lastDay = date.with(TemporalAdjusters.lastDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // System.out.println("最后一天为:"+lastDay); return lastDay; } /** * 获取当时间前/后的时间(天) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainDay(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,1,i); //获取天 String day = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // System.out.println("获取的时间为(天):"+day); return day; } /** * 获取当时间前/后的时间(小时) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainHours(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,2,i); //获取该月份的最后一天 String hours = date.format(DateTimeFormatter.ofPattern("HH:mm:ss")); // System.out.println("获取的时间为(小时):"+hours); return hours; } /** * 获取当时间前/后的时间(小时) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainMinutes(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,3,i); //获取该月份的最后一天 String minutes = date.format(DateTimeFormatter.ofPattern("HH:mm:ss")); // System.out.println("获取的时间为(分钟):"+minutes); return minutes; } /** * 获取当时间前/后的时间(小时) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainSeconds(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,4,i); //获取该月份的最后一天 String seconds = date.format(DateTimeFormatter.ofPattern("HH:mm:ss")); // System.out.println("获取的时间为(秒):"+seconds); return seconds; } public static void main(String[] args) { System.out.println("当前时间为:"+LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); System.out.println("前一个月份的第一天为:"+LocalDateTimeUtil.firstDay(1,1)); System.out.println("前一个月份的最后一天为:"+LocalDateTimeUtil.lastDay(1,1)); System.out.println("当前时间的前一天为:"+LocalDateTimeUtil.obtainDay(1,1)); System.out.println("当前时间的后一天为:"+LocalDateTimeUtil.obtainDay(2,1)); System.out.println("当前时间的前一小时为:"+LocalDateTimeUtil.obtainHours(1,1)); System.out.println("当前时间的后一小时为:"+LocalDateTimeUtil.obtainHours(2,1)); System.out.println("当前时间的前一分钟为:"+LocalDateTimeUtil.obtainMinutes(1,1)); System.out.println("当前时间的后一分钟为:"+LocalDateTimeUtil.obtainMinutes(2,1)); System.out.println("当前时间的前一秒为:"+LocalDateTimeUtil.obtainSeconds(1,1)); System.out.println("当前时间的后一秒为:"+LocalDateTimeUtil.obtainSeconds(2,1)); } private static LocalDateTime getLocalDateTime(Integer state,Integer type,Integer i) { LocalDateTime date; if(state == 0){ date = LocalDateTime.now(); }else if(state == 1){ if(type == 0) { //获取月 date = LocalDateTime.now().minusMonths(i); }else if(type == 1){ //获取天 date = LocalDateTime.now().minusDays(i); }else if(type == 2){ //获取小时 date = LocalDateTime.now().minusHours(i); }else if(type == 3){ //获取分钟 date = LocalDateTime.now().minusMinutes(i);
ImageComparerUI——基于Java语言实现的相似图像识别,基于直方图比较算法。 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.MediaTracker; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JPanel; public class ImageComparerUI extends JComponent implements ActionListener { /** * */ private static final long serialVersionUID = 1L; private JButton browseBtn; private JButton histogramBtn; private JButton compareBtn; private Dimension mySize; // image operator private MediaTracker tracker; private BufferedImage sourceImage; private BufferedImage candidateImage; private double simility; // command constants public final static String BROWSE_CMD = "Browse..."; public final static String HISTOGRAM_CMD = "Histogram Bins"; public final static String COMPARE_CMD = "Compare Result"; public ImageComparerUI() { JPanel btnPanel = new JPanel(); btnPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); browseBtn = new JButton("Browse..."); histogramBtn = new JButton("Histogram Bins"); compareBtn = new JButton("Compare Result"); // buttons btnPanel.add(browseBtn); btnPanel.add(histogramBtn); btnPanel.add(compareBtn); // setup listener... browseBtn.addActionListener(this); histogramBtn.addActionListener(this); compareBtn.addActionListener(this); mySize = new Dimension(620, 500); JFrame demoUI = new JFrame("Similiar Image Finder"); demoUI.getContentPane().setLayout(new BorderLayout()); demoUI.getContentPane().add(this, BorderLayout.CENTER); demoUI.getContentPane().add(btnPanel, BorderLayout.SOUTH); demoUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); demoUI.pack(); demoUI.setVisible(true); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; if(sourceImage != null) { Image scaledImage = sourceImage.getScaledInstance(300, 300, Image.SCALE_FAST); g2.drawImage(scaledImage, 0, 0, 300, 300, null); } if(candidateImage != null) { Image scaledImage = candidateImage.getScaledInstance(300, 330, Image.SCALE_FAST); g2.drawImage(scaledImage, 310, 0, 300, 300, null); } // display compare result info here Font myFont = new Font("Serif", Font.BOLD, 16); g2.setFont(myFont); g2.setPaint(Color.RED); g2.drawString("The degree of similarity : " + simility, 50, 350); } public void actionPerformed(ActionEvent e) { if(BROWSE_CMD.equals(e.getActionCommand())) { JFileChooser chooser = new JFileChooser(); chooser.showOpenDialog(null); File f = chooser.getSelectedFile(); BufferedImage bImage = null; if(f == null) return; try { bImage = ImageIO.read(f); } catch (IOException e1) { e1.printStackTrace(); } tracker = new MediaTracker(this); tracker.addImage(bImage, 1); // blocked 10 seconds to load the image data try { if (!tracker.waitForID(1, 10000)) { System.out.println("Load error."); System.exit(1); }// end if } catch (InterruptedException ine) { ine.printStackTrace(); System.exit(1); } // end catch if(sourceImage == null) { sourceImage = bImage; }else if(candidateImage == null) { candidateImage = bImage; } else { sourceImage = null; candidateImage = null; }
CAS(Compare and Swap)队列是一种基于无锁的并发编程实现,其核心思想是利用原子操作的特性来实现线程安全的数据访问。下面是用Java实现一个简单的CAS队列的示例代码: ```java import java.util.concurrent.atomic.AtomicReference; public class CASQueue<T> { private AtomicReference<Node<T>> head; private AtomicReference<Node<T>> tail; public CASQueue() { Node<T> dummy = new Node<>(null); head = new AtomicReference<>(dummy); tail = new AtomicReference<>(dummy); } public void enqueue(T item) { Node<T> newNode = new Node<>(item); while (true) { Node<T> curTail = tail.get(); Node<T> tailNext = curTail.next.get(); if (curTail == tail.get()) { if (tailNext != null) { tail.compareAndSet(curTail, tailNext); } else { if (curTail.next.compareAndSet(null, newNode)) { tail.compareAndSet(curTail, newNode); return; } } } } } public T dequeue() { while (true) { Node<T> curHead = head.get(); Node<T> curTail = tail.get(); Node<T> headNext = curHead.next.get(); if (curHead == head.get()) { if (curHead == curTail) { if (headNext == null) { return null; } tail.compareAndSet(curTail, headNext); } else { T item = headNext.item; if (head.compareAndSet(curHead, headNext)) { return item; } } } } } private static class Node<T> { private T item; private AtomicReference<Node<T>> next; public Node(T item) { this.item = item; this.next = new AtomicReference<>(null); } } } ``` 这个队列中的每个节点都包含一个元素和一个指向下一个节点的引用。队列的头部和尾部都是用AtomicReference来保证线程安全。enqueue方法中,我们首先创建一个新的节点,然后利用CAS操作来将其添加到队列的尾部。如果队列的尾部发生了变化,我们需要再次尝试添加节点。dequeue方法中,我们利用CAS操作来将队列的头部指针向前移动,并返回移除的元素。如果队列为空,则返回null

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值